Skip to content

Commit 22145ae

Browse files
bors[bot]korken89
andauthored
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 rust-embedded/cortex-m-rt#213 Co-authored-by: Emil Fresk <[email protected]>
2 parents f55c06d + 3dd900d commit 22145ae

File tree

7 files changed

+225
-1
lines changed

7 files changed

+225
-1
lines changed

cortex-m-rt/macros/src/lib.rs

+83
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,15 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
150150
})
151151
.collect::<Vec<_>>();
152152

153+
if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Entry) {
154+
return error;
155+
}
156+
157+
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
158+
153159
quote!(
160+
#(#cfgs)*
161+
#(#attrs)*
154162
#[doc(hidden)]
155163
#[export_name = "main"]
156164
pub unsafe extern "C" fn #tramp_ident() {
@@ -286,6 +294,10 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
286294
.into();
287295
}
288296

297+
if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Exception) {
298+
return error;
299+
}
300+
289301
let fspan = f.span();
290302
let ident = f.sig.ident.clone();
291303

@@ -343,7 +355,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
343355
let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site());
344356
let ident = &f.sig.ident;
345357

358+
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
359+
346360
quote!(
361+
#(#cfgs)*
362+
#(#attrs)*
347363
#[doc(hidden)]
348364
#[export_name = #ident_s]
349365
pub unsafe extern "C" fn #tramp_ident() {
@@ -396,7 +412,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
396412
let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site());
397413
let ident = &f.sig.ident;
398414

415+
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
416+
399417
quote!(
418+
#(#cfgs)*
419+
#(#attrs)*
400420
#[doc(hidden)]
401421
#[export_name = "HardFault"]
402422
#[link_section = ".HardFault.user"]
@@ -481,7 +501,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
481501
})
482502
.collect::<Vec<_>>();
483503

504+
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
505+
484506
quote!(
507+
#(#cfgs)*
508+
#(#attrs)*
485509
#[doc(hidden)]
486510
#[export_name = #ident_s]
487511
pub unsafe extern "C" fn #tramp_ident() {
@@ -650,7 +674,15 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
650674
})
651675
.collect::<Vec<_>>();
652676

677+
if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Interrupt) {
678+
return error;
679+
}
680+
681+
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
682+
653683
quote!(
684+
#(#cfgs)*
685+
#(#attrs)*
654686
#[doc(hidden)]
655687
#[export_name = #ident_s]
656688
pub unsafe extern "C" fn #tramp_ident() {
@@ -724,6 +756,10 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
724756
.into();
725757
}
726758

759+
if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::PreInit) {
760+
return error;
761+
}
762+
727763
// XXX should we blacklist other attributes?
728764
let attrs = f.attrs;
729765
let ident = f.sig.ident;
@@ -790,6 +826,53 @@ fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
790826
(cfgs, not_cfgs)
791827
}
792828

829+
enum WhiteListCaller {
830+
Entry,
831+
Exception,
832+
Interrupt,
833+
PreInit,
834+
}
835+
836+
fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result<(), TokenStream> {
837+
let whitelist = &[
838+
"doc",
839+
"link_section",
840+
"cfg",
841+
"allow",
842+
"warn",
843+
"deny",
844+
"forbid",
845+
"cold",
846+
];
847+
848+
'o: for attr in attrs {
849+
for val in whitelist {
850+
if eq(&attr, &val) {
851+
continue 'o;
852+
}
853+
}
854+
855+
let err_str = match caller {
856+
WhiteListCaller::Entry => "this attribute is not allowed on a cortex-m-rt entry point",
857+
WhiteListCaller::Exception => {
858+
"this attribute is not allowed on an exception handler controlled by cortex-m-rt"
859+
}
860+
WhiteListCaller::Interrupt => {
861+
"this attribute is not allowed on an interrupt handler controlled by cortex-m-rt"
862+
}
863+
WhiteListCaller::PreInit => {
864+
"this attribute is not allowed on a pre-init controlled by cortex-m-rt"
865+
}
866+
};
867+
868+
return Err(parse::Error::new(attr.span(), &err_str)
869+
.to_compile_error()
870+
.into());
871+
}
872+
873+
Ok(())
874+
}
875+
793876
/// Returns `true` if `attr.path` matches `name`
794877
fn eq(attr: &Attribute, name: &str) -> bool {
795878
attr.style == AttrStyle::Outer && attr.path.is_ident(name)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
extern crate cortex_m_rt;
5+
extern crate panic_halt;
6+
7+
use cortex_m_rt::{entry, exception, interrupt};
8+
9+
#[inline] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point
10+
#[entry]
11+
fn foo() -> ! {
12+
loop {}
13+
}
14+
15+
#[inline] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt
16+
#[exception]
17+
fn SysTick() {}
18+
19+
#[allow(non_camel_case_types)]
20+
enum interrupt {
21+
USART1,
22+
USART2,
23+
}
24+
25+
#[inline] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
26+
#[interrupt]
27+
fn USART1() {}
28+
29+
#[cfg(feature = "device")]
30+
#[cfg_attr(feature = "device", inline)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
31+
#[interrupt]
32+
fn USART2() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
extern crate cortex_m_rt;
5+
extern crate panic_halt;
6+
7+
use cortex_m_rt::{entry, exception, interrupt};
8+
9+
#[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point
10+
#[entry]
11+
fn foo() -> ! {
12+
loop {}
13+
}
14+
15+
#[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt
16+
#[exception]
17+
fn SysTick() {}
18+
19+
#[allow(non_camel_case_types)]
20+
enum interrupt {
21+
USART1,
22+
USART2,
23+
}
24+
25+
#[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
26+
#[interrupt]
27+
fn USART1() {}
28+
29+
#[cfg(feature = "device")]
30+
#[cfg_attr(feature = "device", export_name = "not_allowed")] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
31+
#[interrupt]
32+
fn USART2() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
extern crate cortex_m_rt;
5+
extern crate panic_halt;
6+
7+
use cortex_m_rt::{entry, exception, interrupt};
8+
9+
#[no_mangle] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point
10+
#[entry]
11+
fn foo() -> ! {
12+
loop {}
13+
}
14+
15+
#[no_mangle] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt
16+
#[exception]
17+
fn SysTick() {}
18+
19+
#[allow(non_camel_case_types)]
20+
enum interrupt {
21+
USART1,
22+
USART2,
23+
}
24+
25+
#[no_mangle] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
26+
#[interrupt]
27+
fn USART1() {}
28+
29+
#[cfg(feature = "device")]
30+
#[cfg_attr(feature = "device", no_mangle)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
31+
#[interrupt]
32+
fn USART2() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
extern crate cortex_m_rt;
5+
extern crate panic_halt;
6+
7+
use cortex_m_rt::{entry, exception, interrupt};
8+
9+
#[must_use] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point
10+
#[entry]
11+
fn foo() -> ! {
12+
loop {}
13+
}
14+
15+
#[must_use] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt
16+
#[exception]
17+
fn SysTick() {}
18+
19+
#[allow(non_camel_case_types)]
20+
enum interrupt {
21+
USART1,
22+
USART2,
23+
}
24+
25+
#[must_use] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
26+
#[interrupt]
27+
fn USART1() {}
28+
29+
#[cfg(feature = "device")]
30+
#[cfg_attr(feature = "device", must_use)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt
31+
#[interrupt]
32+
fn USART2() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
extern crate cortex_m_rt;
5+
extern crate panic_halt;
6+
7+
use cortex_m_rt::{entry, exception};
8+
9+
#[exception]
10+
#[entry] //~ ERROR this attribute is not allowed on an exception handler
11+
fn SVCall() -> ! {
12+
loop {}
13+
}

cortex-m-rt/tests/compiletest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fn run_mode(mode: &'static str) {
99
config.src_base = PathBuf::from(format!("tests/{}", mode));
1010
// config.link_deps(); // Populate config.target_rustcflags with dependencies on the path
1111
config.target_rustcflags =
12-
Some("-L target/debug -L target/debug/deps -C panic=abort".to_owned());
12+
Some("-L target/debug -L target/debug/deps -C panic=abort --cfg feature=\"device\"".to_owned());
1313
// config.clean_rmeta(); // If your tests import the parent crate, this helps with E0464
1414

1515
compiletest::run_tests(&config);

0 commit comments

Comments
 (0)