aboutsummaryrefslogtreecommitdiff
path: root/cortex-m-rt/macros/src/lib.rs
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <jorge@japaric.io> 2018-10-26 21:22:43 +0200
committerGravatar Jorge Aparicio <jorge@japaric.io> 2018-10-26 21:22:43 +0200
commitadf49361cd19291005bbc9645e41ed334abb2e66 (patch)
tree9ef9dc68d78025cafdf6f1a1b79e91d10333e3af /cortex-m-rt/macros/src/lib.rs
parentc5d24f867d7d4f4f270ba99eef89f97cf38a4445 (diff)
downloadcortex-m-adf49361cd19291005bbc9645e41ed334abb2e66.tar.gz
cortex-m-adf49361cd19291005bbc9645e41ed334abb2e66.tar.zst
cortex-m-adf49361cd19291005bbc9645e41ed334abb2e66.zip
attributes: turn panics into compile errors
Sample error messages: ``` error: `#[entry]` function must have signature `[unsafe] fn() -> !` --> examples/error.rs:15:1 | 15 | fn main() { | ^^ error: aborting due to previous error ``` ``` error: This attribute accepts no arguments --> examples/error.rs:14:1 | 14 | #[entry(hello)] | ^^^^^^^^^^^^^^^ error: aborting due to previous error ``` ``` error: This is not a valid exception name --> examples/error.rs:20:4 | 20 | fn foo() {} | ^^^ error: aborting due to previous error ```
Diffstat (limited to 'cortex-m-rt/macros/src/lib.rs')
-rw-r--r--cortex-m-rt/macros/src/lib.rs343
1 files changed, 201 insertions, 142 deletions
diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs
index dd89f06..54bbdfa 100644
--- a/cortex-m-rt/macros/src/lib.rs
+++ b/cortex-m-rt/macros/src/lib.rs
@@ -14,7 +14,10 @@ use rand::Rng;
use rand::SeedableRng;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
-use syn::{FnArg, Ident, Item, ItemFn, ItemStatic, ReturnType, Stmt, Type, Visibility};
+use syn::{
+ parse, spanned::Spanned, FnArg, Ident, Item, ItemFn, ItemStatic, ReturnType, Stmt, Type,
+ Visibility,
+};
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
@@ -81,28 +84,35 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);
// check the function signature
- assert!(
- f.constness.is_none()
- && f.vis == Visibility::Inherited
- && f.abi.is_none()
- && f.decl.inputs.is_empty()
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.variadic.is_none()
- && match f.decl.output {
- ReturnType::Default => false,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Never(_) => true,
- _ => false,
- },
+ let valid_signature = f.constness.is_none()
+ && f.vis == Visibility::Inherited
+ && f.abi.is_none()
+ && f.decl.inputs.is_empty()
+ && f.decl.generics.params.is_empty()
+ && f.decl.generics.where_clause.is_none()
+ && f.decl.variadic.is_none()
+ && match f.decl.output {
+ ReturnType::Default => false,
+ ReturnType::Type(_, ref ty) => match **ty {
+ Type::Never(_) => true,
+ _ => false,
},
- "`#[entry]` function must have signature `[unsafe] fn() -> !`"
- );
+ };
+
+ if !valid_signature {
+ return parse::Error::new(
+ f.span(),
+ "`#[entry]` function must have signature `[unsafe] fn() -> !`",
+ )
+ .to_compile_error()
+ .into();
+ }
- assert!(
- args.to_string() == "",
- "`entry` attribute must have no arguments"
- );
+ if !args.is_empty() {
+ return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
+ .to_compile_error()
+ .into();
+ }
// XXX should we blacklist other attributes?
let attrs = f.attrs;
@@ -127,7 +137,8 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
&mut #ident
};
)
- }).collect::<Vec<_>>();
+ })
+ .collect::<Vec<_>>();
quote!(
#[export_name = "main"]
@@ -137,7 +148,8 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
#(#stmts)*
}
- ).into()
+ )
+ .into()
}
/// Attribute to declare an exception handler
@@ -255,11 +267,13 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);
- assert!(
- args.to_string() == "",
- "`exception` attribute must have no arguments"
- );
+ if !args.is_empty() {
+ return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
+ .to_compile_error()
+ .into();
+ }
+ let fspan = f.span();
let ident = f.ident;
enum Exception {
@@ -276,7 +290,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
// MemoryManagement is not available on Cortex-M0)
"NonMaskableInt" | "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault"
| "SVCall" | "DebugMonitor" | "PendSV" | "SysTick" => Exception::Other,
- _ => panic!("{} is not a valid exception name", ident_s),
+ _ => {
+ return parse::Error::new(ident.span(), "This is not a valid exception name")
+ .to_compile_error()
+ .into();
+ }
};
// XXX should we blacklist other attributes?
@@ -288,24 +306,30 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
let hash = random_ident();
match exn {
Exception::DefaultHandler => {
- assert!(
- f.constness.is_none()
- && f.vis == Visibility::Inherited
- && f.abi.is_none()
- && f.decl.inputs.len() == 1
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.variadic.is_none()
- && match f.decl.output {
- ReturnType::Default => true,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Tuple(ref tuple) => tuple.elems.is_empty(),
- Type::Never(..) => true,
- _ => false,
- },
+ let valid_signature = f.constness.is_none()
+ && f.vis == Visibility::Inherited
+ && f.abi.is_none()
+ && f.decl.inputs.len() == 1
+ && f.decl.generics.params.is_empty()
+ && f.decl.generics.where_clause.is_none()
+ && f.decl.variadic.is_none()
+ && match f.decl.output {
+ ReturnType::Default => true,
+ ReturnType::Type(_, ref ty) => match **ty {
+ Type::Tuple(ref tuple) => tuple.elems.is_empty(),
+ Type::Never(..) => true,
+ _ => false,
},
- "`DefaultHandler` exception must have signature `[unsafe] fn(i16) [-> !]`"
- );
+ };
+
+ if !valid_signature {
+ return parse::Error::new(
+ fspan,
+ "`DefaultHandler` must have signature `[unsafe] fn(i16) [-> !]`",
+ )
+ .to_compile_error()
+ .into();
+ }
let arg = match f.decl.inputs[0] {
FnArg::Captured(ref arg) => arg,
@@ -324,35 +348,40 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
#(#stmts)*
}
- ).into()
+ )
+ .into()
}
Exception::HardFault => {
- assert!(
- f.constness.is_none()
- && f.vis == Visibility::Inherited
- && f.abi.is_none()
- && f.decl.inputs.len() == 1
- && match f.decl.inputs[0] {
- FnArg::Captured(ref arg) => match arg.ty {
- Type::Reference(ref r) => {
- r.lifetime.is_none() && r.mutability.is_none()
- }
- _ => false,
- },
+ let valid_signature = f.constness.is_none()
+ && f.vis == Visibility::Inherited
+ && f.abi.is_none()
+ && f.decl.inputs.len() == 1
+ && match f.decl.inputs[0] {
+ FnArg::Captured(ref arg) => match arg.ty {
+ Type::Reference(ref r) => r.lifetime.is_none() && r.mutability.is_none(),
_ => false,
- }
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.variadic.is_none()
- && match f.decl.output {
- ReturnType::Default => false,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Never(_) => true,
- _ => false,
- },
},
- "`HardFault` exception must have signature `[unsafe] fn(&ExceptionFrame) -> !`"
- );
+ _ => false,
+ }
+ && f.decl.generics.params.is_empty()
+ && f.decl.generics.where_clause.is_none()
+ && f.decl.variadic.is_none()
+ && match f.decl.output {
+ ReturnType::Default => false,
+ ReturnType::Type(_, ref ty) => match **ty {
+ Type::Never(_) => true,
+ _ => false,
+ },
+ };
+
+ if !valid_signature {
+ return parse::Error::new(
+ fspan,
+ "`HardFault` handler must have signature `[unsafe] fn(&ExceptionFrame) -> !`",
+ )
+ .to_compile_error()
+ .into();
+ }
let arg = match f.decl.inputs[0] {
FnArg::Captured(ref arg) => arg,
@@ -372,28 +401,35 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
#(#stmts)*
}
- ).into()
+ )
+ .into()
}
Exception::Other => {
- assert!(
- f.constness.is_none()
- && f.vis == Visibility::Inherited
- && f.abi.is_none()
- && f.decl.inputs.is_empty()
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.variadic.is_none()
- && match f.decl.output {
- ReturnType::Default => true,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Tuple(ref tuple) => tuple.elems.is_empty(),
- Type::Never(..) => true,
- _ => false,
- },
+ let valid_signature = f.constness.is_none()
+ && f.vis == Visibility::Inherited
+ && f.abi.is_none()
+ && f.decl.inputs.is_empty()
+ && f.decl.generics.params.is_empty()
+ && f.decl.generics.where_clause.is_none()
+ && f.decl.variadic.is_none()
+ && match f.decl.output {
+ ReturnType::Default => true,
+ ReturnType::Type(_, ref ty) => match **ty {
+ Type::Tuple(ref tuple) => tuple.elems.is_empty(),
+ Type::Never(..) => true,
+ _ => false,
},
- "`#[exception]` functions other than `DefaultHandler` and `HardFault` must \
- have signature `[unsafe] fn() [-> !]`"
- );
+ };
+
+ if !valid_signature {
+ return parse::Error::new(
+ fspan,
+ "`#[exception]` handlers other than `DefaultHandler` and `HardFault` must have \
+ signature `[unsafe] fn() [-> !]`",
+ )
+ .to_compile_error()
+ .into();
+ }
let (statics, stmts) = extract_static_muts(stmts);
@@ -414,7 +450,8 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
&mut #ident
};
)
- }).collect::<Vec<_>>();
+ })
+ .collect::<Vec<_>>();
quote!(
#[export_name = #ident_s]
@@ -429,7 +466,8 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
#(#stmts)*
}
- ).into()
+ )
+ .into()
}
}
}
@@ -505,11 +543,13 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
let f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
- assert!(
- args.to_string() == "",
- "`interrupt` attribute must have no arguments"
- );
+ if !args.is_empty() {
+ return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
+ .to_compile_error()
+ .into();
+ }
+ let fspan = f.span();
let ident = f.ident;
let ident_s = ident.to_string();
@@ -519,24 +559,30 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
let stmts = block.stmts;
let unsafety = f.unsafety;
- assert!(
- f.constness.is_none()
- && f.vis == Visibility::Inherited
- && f.abi.is_none()
- && f.decl.inputs.is_empty()
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.variadic.is_none()
- && match f.decl.output {
- ReturnType::Default => true,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Tuple(ref tuple) => tuple.elems.is_empty(),
- Type::Never(..) => true,
- _ => false,
- },
+ let valid_signature = f.constness.is_none()
+ && f.vis == Visibility::Inherited
+ && f.abi.is_none()
+ && f.decl.inputs.is_empty()
+ && f.decl.generics.params.is_empty()
+ && f.decl.generics.where_clause.is_none()
+ && f.decl.variadic.is_none()
+ && match f.decl.output {
+ ReturnType::Default => true,
+ ReturnType::Type(_, ref ty) => match **ty {
+ Type::Tuple(ref tuple) => tuple.elems.is_empty(),
+ Type::Never(..) => true,
+ _ => false,
},
- "`#[interrupt]` functions must have signature `[unsafe] fn() [-> !]`"
- );
+ };
+
+ if !valid_signature {
+ return parse::Error::new(
+ fspan,
+ "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
+ )
+ .to_compile_error()
+ .into();
+ }
let (statics, stmts) = extract_static_muts(stmts);
@@ -557,7 +603,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
&mut #ident
};
)
- }).collect::<Vec<_>>();
+ })
+ .collect::<Vec<_>>();
let hash = random_ident();
quote!(
@@ -570,7 +617,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
#(#stmts)*
}
- ).into()
+ )
+ .into()
}
/// Attribute to mark which function will be called at the beginning of the reset handler.
@@ -600,29 +648,36 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);
// check the function signature
- assert!(
- f.constness.is_none()
- && f.vis == Visibility::Inherited
- && f.unsafety.is_some()
- && f.abi.is_none()
- && f.decl.inputs.is_empty()
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.variadic.is_none()
- && match f.decl.output {
- ReturnType::Default => true,
- ReturnType::Type(_, ref ty) => match **ty {
- Type::Tuple(ref tuple) => tuple.elems.is_empty(),
- _ => false,
- },
+ let valid_signature = f.constness.is_none()
+ && f.vis == Visibility::Inherited
+ && f.unsafety.is_some()
+ && f.abi.is_none()
+ && f.decl.inputs.is_empty()
+ && f.decl.generics.params.is_empty()
+ && f.decl.generics.where_clause.is_none()
+ && f.decl.variadic.is_none()
+ && match f.decl.output {
+ ReturnType::Default => true,
+ ReturnType::Type(_, ref ty) => match **ty {
+ Type::Tuple(ref tuple) => tuple.elems.is_empty(),
+ _ => false,
},
- "`#[pre_init]` function must have signature `unsafe fn()`"
- );
+ };
+
+ if !valid_signature {
+ return parse::Error::new(
+ f.span(),
+ "`#[pre_init]` function must have signature `unsafe fn()`",
+ )
+ .to_compile_error()
+ .into();
+ }
- assert!(
- args.to_string() == "",
- "`pre_init` attribute must have no arguments"
- );
+ if !args.is_empty() {
+ return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
+ .to_compile_error()
+ .into();
+ }
// XXX should we blacklist other attributes?
let attrs = f.attrs;
@@ -633,7 +688,8 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
#[export_name = "__pre_init"]
#(#attrs)*
pub unsafe fn #ident() #block
- ).into()
+ )
+ .into()
}
// Creates a random identifier
@@ -663,7 +719,8 @@ fn random_ident() -> Ident {
} else {
('0' as u8 + rng.gen::<u8>() % 10) as char
}
- }).collect::<String>(),
+ })
+ .collect::<String>(),
Span::call_site(),
)
}
@@ -676,11 +733,13 @@ fn extract_static_muts(stmts: Vec<Stmt>) -> (Vec<ItemStatic>, Vec<Stmt>) {
let mut stmts = vec![];
while let Some(stmt) = istmts.next() {
match stmt {
- Stmt::Item(Item::Static(var)) => if var.mutability.is_some() {
- statics.push(var);
- } else {
- stmts.push(Stmt::Item(Item::Static(var)));
- },
+ Stmt::Item(Item::Static(var)) => {
+ if var.mutability.is_some() {
+ statics.push(var);
+ } else {
+ stmts.push(Stmt::Item(Item::Static(var)));
+ }
+ }
_ => {
stmts.push(stmt);
break;