aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cortex-m-rt/macros/src/lib.rs83
-rw-r--r--cortex-m-rt/tests/compile-fail/whitelist-1.rs32
-rw-r--r--cortex-m-rt/tests/compile-fail/whitelist-2.rs32
-rw-r--r--cortex-m-rt/tests/compile-fail/whitelist-3.rs32
-rw-r--r--cortex-m-rt/tests/compile-fail/whitelist-4.rs32
-rw-r--r--cortex-m-rt/tests/compile-fail/whitelist-double-attr.rs13
-rw-r--r--cortex-m-rt/tests/compiletest.rs2
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);