diff options
author | 2020-01-16 17:42:50 +0000 | |
---|---|---|
committer | 2020-01-16 17:42:50 +0000 | |
commit | 22145aeb5dd1c25e4df2f3320e7ae7e47a9a0c6c (patch) | |
tree | a67d3bd9ff39fe9f3c232d843e060f0be1f9ca3d | |
parent | f55c06da96ae05680979e5ad9ebda9e1d16b8908 (diff) | |
parent | 3dd900d8ad7c66fc2044e12e3d55274a5afb43a1 (diff) | |
download | cortex-m-22145aeb5dd1c25e4df2f3320e7ae7e47a9a0c6c.tar.gz cortex-m-22145aeb5dd1c25e4df2f3320e7ae7e47a9a0c6c.tar.zst cortex-m-22145aeb5dd1c25e4df2f3320e7ae7e47a9a0c6c.zip |
Merge #228
228: Added so attributes and cfgs are applied on the trampolines as well r=jonas-schievink a=korken89
I made a first go at #223, but maybe this implementation takes things we do not want to propagate.
If you come up with something that should not propagate, please comment here.
Closes #223
Closes https://github.com/rust-embedded/cortex-m-rt/issues/213
Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
-rw-r--r-- | cortex-m-rt/macros/src/lib.rs | 83 | ||||
-rw-r--r-- | cortex-m-rt/tests/compile-fail/whitelist-1.rs | 32 | ||||
-rw-r--r-- | cortex-m-rt/tests/compile-fail/whitelist-2.rs | 32 | ||||
-rw-r--r-- | cortex-m-rt/tests/compile-fail/whitelist-3.rs | 32 | ||||
-rw-r--r-- | cortex-m-rt/tests/compile-fail/whitelist-4.rs | 32 | ||||
-rw-r--r-- | cortex-m-rt/tests/compile-fail/whitelist-double-attr.rs | 13 | ||||
-rw-r--r-- | cortex-m-rt/tests/compiletest.rs | 2 |
7 files changed, 225 insertions, 1 deletions
diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 763b721..d919faa 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -150,7 +150,15 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { }) .collect::<Vec<_>>(); + if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Entry) { + return error; + } + + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + quote!( + #(#cfgs)* + #(#attrs)* #[doc(hidden)] #[export_name = "main"] pub unsafe extern "C" fn #tramp_ident() { @@ -286,6 +294,10 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { .into(); } + if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Exception) { + return error; + } + let fspan = f.span(); let ident = f.sig.ident.clone(); @@ -343,7 +355,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); let ident = &f.sig.ident; + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + quote!( + #(#cfgs)* + #(#attrs)* #[doc(hidden)] #[export_name = #ident_s] pub unsafe extern "C" fn #tramp_ident() { @@ -396,7 +412,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); let ident = &f.sig.ident; + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + quote!( + #(#cfgs)* + #(#attrs)* #[doc(hidden)] #[export_name = "HardFault"] #[link_section = ".HardFault.user"] @@ -481,7 +501,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { }) .collect::<Vec<_>>(); + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + quote!( + #(#cfgs)* + #(#attrs)* #[doc(hidden)] #[export_name = #ident_s] pub unsafe extern "C" fn #tramp_ident() { @@ -650,7 +674,15 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { }) .collect::<Vec<_>>(); + if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Interrupt) { + return error; + } + + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + quote!( + #(#cfgs)* + #(#attrs)* #[doc(hidden)] #[export_name = #ident_s] pub unsafe extern "C" fn #tramp_ident() { @@ -724,6 +756,10 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { .into(); } + if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::PreInit) { + return error; + } + // XXX should we blacklist other attributes? let attrs = f.attrs; let ident = f.sig.ident; @@ -790,6 +826,53 @@ fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) { (cfgs, not_cfgs) } +enum WhiteListCaller { + Entry, + Exception, + Interrupt, + PreInit, +} + +fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result<(), TokenStream> { + let whitelist = &[ + "doc", + "link_section", + "cfg", + "allow", + "warn", + "deny", + "forbid", + "cold", + ]; + + 'o: for attr in attrs { + for val in whitelist { + if eq(&attr, &val) { + continue 'o; + } + } + + let err_str = match caller { + WhiteListCaller::Entry => "this attribute is not allowed on a cortex-m-rt entry point", + WhiteListCaller::Exception => { + "this attribute is not allowed on an exception handler controlled by cortex-m-rt" + } + WhiteListCaller::Interrupt => { + "this attribute is not allowed on an interrupt handler controlled by cortex-m-rt" + } + WhiteListCaller::PreInit => { + "this attribute is not allowed on a pre-init controlled by cortex-m-rt" + } + }; + + return Err(parse::Error::new(attr.span(), &err_str) + .to_compile_error() + .into()); + } + + Ok(()) +} + /// Returns `true` if `attr.path` matches `name` fn eq(attr: &Attribute, name: &str) -> bool { attr.style == AttrStyle::Outer && attr.path.is_ident(name) diff --git a/cortex-m-rt/tests/compile-fail/whitelist-1.rs b/cortex-m-rt/tests/compile-fail/whitelist-1.rs new file mode 100644 index 0000000..9c5133b --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/whitelist-1.rs @@ -0,0 +1,32 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, exception, interrupt}; + +#[inline] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point +#[entry] +fn foo() -> ! { + loop {} +} + +#[inline] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt +#[exception] +fn SysTick() {} + +#[allow(non_camel_case_types)] +enum interrupt { + USART1, + USART2, +} + +#[inline] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART1() {} + +#[cfg(feature = "device")] +#[cfg_attr(feature = "device", inline)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART2() {} diff --git a/cortex-m-rt/tests/compile-fail/whitelist-2.rs b/cortex-m-rt/tests/compile-fail/whitelist-2.rs new file mode 100644 index 0000000..086f909 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/whitelist-2.rs @@ -0,0 +1,32 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, exception, interrupt}; + +#[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point +#[entry] +fn foo() -> ! { + loop {} +} + +#[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt +#[exception] +fn SysTick() {} + +#[allow(non_camel_case_types)] +enum interrupt { + USART1, + USART2, +} + +#[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART1() {} + +#[cfg(feature = "device")] +#[cfg_attr(feature = "device", export_name = "not_allowed")] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART2() {} diff --git a/cortex-m-rt/tests/compile-fail/whitelist-3.rs b/cortex-m-rt/tests/compile-fail/whitelist-3.rs new file mode 100644 index 0000000..9e5fb33 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/whitelist-3.rs @@ -0,0 +1,32 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, exception, interrupt}; + +#[no_mangle] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point +#[entry] +fn foo() -> ! { + loop {} +} + +#[no_mangle] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt +#[exception] +fn SysTick() {} + +#[allow(non_camel_case_types)] +enum interrupt { + USART1, + USART2, +} + +#[no_mangle] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART1() {} + +#[cfg(feature = "device")] +#[cfg_attr(feature = "device", no_mangle)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART2() {} diff --git a/cortex-m-rt/tests/compile-fail/whitelist-4.rs b/cortex-m-rt/tests/compile-fail/whitelist-4.rs new file mode 100644 index 0000000..95dad29 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/whitelist-4.rs @@ -0,0 +1,32 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, exception, interrupt}; + +#[must_use] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point +#[entry] +fn foo() -> ! { + loop {} +} + +#[must_use] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt +#[exception] +fn SysTick() {} + +#[allow(non_camel_case_types)] +enum interrupt { + USART1, + USART2, +} + +#[must_use] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART1() {} + +#[cfg(feature = "device")] +#[cfg_attr(feature = "device", must_use)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt +#[interrupt] +fn USART2() {} diff --git a/cortex-m-rt/tests/compile-fail/whitelist-double-attr.rs b/cortex-m-rt/tests/compile-fail/whitelist-double-attr.rs new file mode 100644 index 0000000..31da76a --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/whitelist-double-attr.rs @@ -0,0 +1,13 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, exception}; + +#[exception] +#[entry] //~ ERROR this attribute is not allowed on an exception handler +fn SVCall() -> ! { + loop {} +} diff --git a/cortex-m-rt/tests/compiletest.rs b/cortex-m-rt/tests/compiletest.rs index 6cea3ac..82dda07 100644 --- a/cortex-m-rt/tests/compiletest.rs +++ b/cortex-m-rt/tests/compiletest.rs @@ -9,7 +9,7 @@ fn run_mode(mode: &'static str) { config.src_base = PathBuf::from(format!("tests/{}", mode)); // config.link_deps(); // Populate config.target_rustcflags with dependencies on the path config.target_rustcflags = - Some("-L target/debug -L target/debug/deps -C panic=abort".to_owned()); + Some("-L target/debug -L target/debug/deps -C panic=abort --cfg feature=\"device\"".to_owned()); // config.clean_rmeta(); // If your tests import the parent crate, this helps with E0464 compiletest::run_tests(&config); |