aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cortex-m-rt/.github/bors.toml2
-rw-r--r--cortex-m-rt/.github/workflows/ci.yml41
-rw-r--r--cortex-m-rt/CHANGELOG.md23
-rw-r--r--cortex-m-rt/examples/divergent-default-handler.rs3
-rw-r--r--cortex-m-rt/examples/override-exception.rs5
-rw-r--r--cortex-m-rt/macros/src/lib.rs42
-rw-r--r--cortex-m-rt/src/lib.rs64
-rw-r--r--cortex-m-rt/tests/compile-fail/default-handler-bad-signature-1.rs4
-rw-r--r--cortex-m-rt/tests/compile-fail/default-handler-bad-signature-2.rs4
-rw-r--r--cortex-m-rt/tests/compile-fail/default-handler-hidden.rs2
-rw-r--r--cortex-m-rt/tests/compile-fail/default-handler-twice.rs4
-rw-r--r--cortex-m-rt/tests/compile-fail/exception-nmi-unsafe.rs24
-rw-r--r--cortex-m-rt/tests/compile-fail/hard-fault-bad-signature-1.rs4
-rw-r--r--cortex-m-rt/tests/compile-fail/hard-fault-twice.rs4
-rw-r--r--cortex-m-rt/tests/compile-fail/unsafe-init-static.rs4
15 files changed, 169 insertions, 61 deletions
diff --git a/cortex-m-rt/.github/bors.toml b/cortex-m-rt/.github/bors.toml
index b4017af..9b9d884 100644
--- a/cortex-m-rt/.github/bors.toml
+++ b/cortex-m-rt/.github/bors.toml
@@ -4,5 +4,7 @@ required_approvals = 1
status = [
"ci-linux (stable)",
"ci-linux (1.39.0)",
+ "build-other (macOS-latest)",
+ "build-other (windows-latest)",
"Rustfmt"
]
diff --git a/cortex-m-rt/.github/workflows/ci.yml b/cortex-m-rt/.github/workflows/ci.yml
index 84e05f2..35abd15 100644
--- a/cortex-m-rt/.github/workflows/ci.yml
+++ b/cortex-m-rt/.github/workflows/ci.yml
@@ -25,8 +25,8 @@ jobs:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- - name: Install all Rust targets for ${{ matrix.rust }}
- run: rustup target install --toolchain=${{ matrix.rust }} thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.main-none-eabi
+ - name: Install all Rust targets for ${{ matrix.rust }}
+ run: rustup target install --toolchain=${{ matrix.rust }} thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf
- name: Install qemu and gcc
run: sudo apt-get update && sudo apt-get install qemu-system-arm gcc-arm-none-eabi
- name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }}
@@ -39,5 +39,42 @@ jobs:
run: TARGET=thumbv7em-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh
- name: Run CI script for thumbv7em-none-eabihf under ${{ matrix.rust }}
run: TARGET=thumbv7em-none-eabihf TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh
+ - name: Run CI script for thumbv8m.base-none-eabi under ${{ matrix.rust }}
+ run: TARGET=thumbv8m.base-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh
- name: Run CI script for thumbv8m.main-none-eabi under ${{ matrix.rust }}
run: TARGET=thumbv8m.main-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh
+ - name: Run CI script for thumbv8m.main-none-eabihf under ${{ matrix.rust }}
+ run: TARGET=thumbv8m.main-none-eabihf TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh
+
+ # On macOS and Windows, we at least make sure that all examples build and link.
+ build-other:
+ strategy:
+ matrix:
+ os:
+ - macOS-latest
+ - windows-latest
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions-rs/toolchain@v1
+ with:
+ profile: minimal
+ toolchain: stable
+ override: true
+ - name: Install all Rust targets
+ run: rustup target install thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf
+ - name: Build crate for thumbv6m-none-eabi
+ run: cargo build --target=thumbv6m-none-eabi --examples
+ - name: Build crate for thumbv7m-none-eabi
+ run: cargo build --target=thumbv7m-none-eabi --examples
+ - name: Build crate for thumbv7em-none-eabi
+ run: cargo build --target=thumbv7em-none-eabi --examples
+ - name: Build crate for thumbv7em-none-eabihf
+ run: cargo build --target=thumbv7em-none-eabihf --examples
+ - name: Build crate for thumbv8m.base-none-eabi
+ run: cargo build --target=thumbv8m.base-none-eabi --examples
+ - name: Build crate for thumbv8m.main-none-eabi
+ run: cargo build --target=thumbv8m.main-none-eabi --examples
+ - name: Build crate for thumbv8m.main-none-eabihf
+ run: cargo build --target=thumbv8m.main-none-eabihf --examples
diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md
index b6ca176..e04c9c9 100644
--- a/cortex-m-rt/CHANGELOG.md
+++ b/cortex-m-rt/CHANGELOG.md
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+### Fixes
+
+- Various fixes to the linker script ([#265], [#286]).
+- Use the correct ABI for the `main` symbol ([#278]).
+- Add barriers after FPU enabling ([#279]).
+
+[#265]: https://github.com/rust-embedded/cortex-m-rt/pull/265
+[#278]: https://github.com/rust-embedded/cortex-m-rt/pull/278
+[#279]: https://github.com/rust-embedded/cortex-m-rt/pull/279
+[#286]: https://github.com/rust-embedded/cortex-m-rt/pull/286
+
+### Breaking Changes
+
+- Make `ExceptionFrame`s fields private, adding setters and getters instead
+ ([#239]).
+- Only allow certain attributes on handlers, and apply them to the trampoline
+ too ([#228]).
+- Make it unsafe to define exception handlers for NMIs ([#289]).
+
+[#239]: https://github.com/rust-embedded/cortex-m-rt/pull/239
+[#228]: https://github.com/rust-embedded/cortex-m-rt/pull/228
+[#289]: https://github.com/rust-embedded/cortex-m-rt/pull/289
+
## [v0.6.11] - 2019-12-04
### Changed
diff --git a/cortex-m-rt/examples/divergent-default-handler.rs b/cortex-m-rt/examples/divergent-default-handler.rs
index 22fa437..3290254 100644
--- a/cortex-m-rt/examples/divergent-default-handler.rs
+++ b/cortex-m-rt/examples/divergent-default-handler.rs
@@ -1,4 +1,3 @@
-#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
@@ -14,6 +13,6 @@ fn foo() -> ! {
}
#[exception]
-fn DefaultHandler(_irqn: i16) -> ! {
+unsafe fn DefaultHandler(_irqn: i16) -> ! {
loop {}
}
diff --git a/cortex-m-rt/examples/override-exception.rs b/cortex-m-rt/examples/override-exception.rs
index 6da6c5e..3190b77 100644
--- a/cortex-m-rt/examples/override-exception.rs
+++ b/cortex-m-rt/examples/override-exception.rs
@@ -1,6 +1,5 @@
//! How to override the hard fault exception handler and the default exception handler
-#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
@@ -18,12 +17,12 @@ fn main() -> ! {
}
#[exception]
-fn DefaultHandler(_irqn: i16) {
+unsafe fn DefaultHandler(_irqn: i16) {
asm::bkpt();
}
#[exception]
-fn HardFault(_ef: &ExceptionFrame) -> ! {
+unsafe fn HardFault(_ef: &ExceptionFrame) -> ! {
asm::bkpt();
loop {}
diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs
index 3c532c0..7e54a5c 100644
--- a/cortex-m-rt/macros/src/lib.rs
+++ b/cortex-m-rt/macros/src/lib.rs
@@ -113,6 +113,14 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
.into()
}
+#[derive(Debug, PartialEq)]
+enum Exception {
+ DefaultHandler,
+ HardFault,
+ NonMaskableInt,
+ Other,
+}
+
#[proc_macro_attribute]
pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
let mut f = parse_macro_input!(input as ItemFn);
@@ -130,20 +138,15 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
let fspan = f.span();
let ident = f.sig.ident.clone();
- enum Exception {
- DefaultHandler,
- HardFault,
- Other,
- }
-
let ident_s = ident.to_string();
let exn = match &*ident_s {
"DefaultHandler" => Exception::DefaultHandler,
"HardFault" => Exception::HardFault,
+ "NonMaskableInt" => Exception::NonMaskableInt,
// NOTE that at this point we don't check if the exception is available on the target (e.g.
// MemoryManagement is not available on Cortex-M0)
- "NonMaskableInt" | "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault"
- | "SVCall" | "DebugMonitor" | "PendSV" | "SysTick" => Exception::Other,
+ "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
+ | "DebugMonitor" | "PendSV" | "SysTick" => Exception::Other,
_ => {
return parse::Error::new(ident.span(), "This is not a valid exception name")
.to_compile_error()
@@ -151,7 +154,22 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
}
};
- // XXX should we blacklist other attributes?
+ if f.sig.unsafety.is_none() {
+ match exn {
+ Exception::DefaultHandler | Exception::HardFault | Exception::NonMaskableInt => {
+ // These are unsafe to define.
+ let name = if exn == Exception::DefaultHandler {
+ format!("`DefaultHandler`")
+ } else {
+ format!("`{:?}` handler", exn)
+ };
+ return parse::Error::new(ident.span(), format_args!("defining a {} is unsafe and requires an `unsafe fn` (see the cortex-m-rt docs)", name))
+ .to_compile_error()
+ .into();
+ }
+ Exception::Other => {}
+ }
+ }
match exn {
Exception::DefaultHandler => {
@@ -174,7 +192,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
if !valid_signature {
return parse::Error::new(
fspan,
- "`DefaultHandler` must have signature `[unsafe] fn(i16) [-> !]`",
+ "`DefaultHandler` must have signature `unsafe fn(i16) [-> !]`",
)
.to_compile_error()
.into();
@@ -231,7 +249,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
if !valid_signature {
return parse::Error::new(
fspan,
- "`HardFault` handler must have signature `[unsafe] fn(&ExceptionFrame) -> !`",
+ "`HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`",
)
.to_compile_error()
.into();
@@ -257,7 +275,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
)
.into()
}
- Exception::Other => {
+ Exception::NonMaskableInt | Exception::Other => {
let valid_signature = f.sig.constness.is_none()
&& f.vis == Visibility::Inherited
&& f.sig.abi.is_none()
diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs
index fe4ee20..65dee34 100644
--- a/cortex-m-rt/src/lib.rs
+++ b/cortex-m-rt/src/lib.rs
@@ -199,15 +199,14 @@
//! won't find it.
//!
//! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn
-//! DefaultHandler(..` this will cause a panic with the message "DefaultHandler #`i`", where `i` is
-//! the number of the interrupt handler.
+//! DefaultHandler(..` this will be an infinite loop.
//!
//! - `HardFaultTrampoline`. This is the real hard fault handler. This function is simply a
//! trampoline that jumps into the user defined hard fault handler named `HardFault`. The
//! trampoline is required to set up the pointer to the stacked exception frame.
//!
//! - `HardFault`. This is the user defined hard fault handler. If not overridden using
-//! `#[exception] fn HardFault(..` it will default to a panic with message "HardFault".
+//! `#[exception] fn HardFault(..` it will default to an infinite loop.
//!
//! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains
//! the initial value of the stack pointer; this is where the stack will be located -- the stack
@@ -442,6 +441,7 @@ extern crate cortex_m_rt_macros as macros;
extern crate r0;
use core::fmt;
+use core::sync::atomic::{self, Ordering};
/// Attribute to declare an interrupt (AKA device-specific exception) handler
///
@@ -612,13 +612,13 @@ pub use macros::entry;
///
/// # Usage
///
-/// `#[exception] fn HardFault(..` sets the hard fault handler. The handler must have signature
-/// `[unsafe] fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause
-/// undefined behavior.
+/// `#[exception] unsafe fn HardFault(..` sets the hard fault handler. The handler must have
+/// signature `unsafe fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can
+/// cause undefined behavior.
///
-/// `#[exception] fn DefaultHandler(..` sets the *default* handler. All exceptions which have not
-/// been assigned a handler will be serviced by this handler. This handler must have signature
-/// `[unsafe] fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative
+/// `#[exception] unsafe fn DefaultHandler(..` sets the *default* handler. All exceptions which have
+/// not been assigned a handler will be serviced by this handler. This handler must have signature
+/// `unsafe fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative
/// number when the handler is servicing a core exception; `irqn` will be a positive number when the
/// handler is servicing a device specific exception (interrupt).
///
@@ -637,23 +637,25 @@ pub use macros::entry;
/// the attribute will help by making a transformation to the source code: for this reason a
/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
///
-/// # Examples
+/// # Safety
///
-/// - Setting the `HardFault` handler
+/// It is not generally safe to register handlers for non-maskable interrupts. On Cortex-M,
+/// `HardFault` is non-maskable (at least in general), and there is an explicitly non-maskable
+/// interrupt `NonMaskableInt`.
///
-/// ```
-/// # extern crate cortex_m_rt;
-/// # extern crate cortex_m_rt_macros;
-/// use cortex_m_rt::{ExceptionFrame, exception};
+/// The reason for that is that non-maskable interrupts will preempt any currently running function,
+/// even if that function executes within a critical section. Thus, if it was safe to define NMI
+/// handlers, critical sections wouldn't work safely anymore.
///
-/// #[exception]
-/// fn HardFault(ef: &ExceptionFrame) -> ! {
-/// // prints the exception frame as a panic message
-/// panic!("{:#?}", ef);
-/// }
+/// This also means that defining a `DefaultHandler` must be unsafe, as that will catch
+/// `NonMaskableInt` and `HardFault` if no handlers for those are defined.
///
-/// # fn main() {}
-/// ```
+/// The safety requirements on those handlers is as follows: The handler must not access any data
+/// that is protected via a critical section and shared with other interrupts that may be preempted
+/// by the NMI while holding the critical section. As long as this requirement is fulfilled, it is
+/// safe to handle NMIs.
+///
+/// # Examples
///
/// - Setting the default handler
///
@@ -661,7 +663,7 @@ pub use macros::entry;
/// use cortex_m_rt::exception;
///
/// #[exception]
-/// fn DefaultHandler(irqn: i16) {
+/// unsafe fn DefaultHandler(irqn: i16) {
/// println!("IRQn = {}", irqn);
/// }
///
@@ -990,17 +992,21 @@ pub unsafe extern "C" fn Reset() -> ! {
#[link_section = ".HardFault.default"]
#[no_mangle]
pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! {
- panic!("HardFault");
+ loop {
+ // add some side effect to prevent this from turning into a UDF instruction
+ // see rust-lang/rust#28728 for details
+ atomic::compiler_fence(Ordering::SeqCst);
+ }
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn DefaultHandler_() -> ! {
- const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
-
- let irqn = core::ptr::read(SCB_ICSR) as u8 as i16 - 16;
-
- panic!("DefaultHandler #{}", irqn);
+ loop {
+ // add some side effect to prevent this from turning into a UDF instruction
+ // see rust-lang/rust#28728 for details
+ atomic::compiler_fence(Ordering::SeqCst);
+ }
}
#[doc(hidden)]
diff --git a/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-1.rs b/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-1.rs
index 5436115..b590883 100644
--- a/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-1.rs
+++ b/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-1.rs
@@ -12,5 +12,5 @@ fn foo() -> ! {
}
#[exception]
-fn DefaultHandler(_irqn: i16, undef: u32) {}
-//~^ ERROR `DefaultHandler` must have signature `[unsafe] fn(i16) [-> !]`
+unsafe fn DefaultHandler(_irqn: i16, undef: u32) {}
+//~^ ERROR `DefaultHandler` must have signature `unsafe fn(i16) [-> !]`
diff --git a/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-2.rs b/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-2.rs
index 1cca10c..0dadd6a 100644
--- a/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-2.rs
+++ b/cortex-m-rt/tests/compile-fail/default-handler-bad-signature-2.rs
@@ -12,7 +12,7 @@ fn foo() -> ! {
}
#[exception]
-fn DefaultHandler(_irqn: i16) -> u32 {
- //~^ ERROR `DefaultHandler` must have signature `[unsafe] fn(i16) [-> !]`
+unsafe fn DefaultHandler(_irqn: i16) -> u32 {
+ //~^ ERROR `DefaultHandler` must have signature `unsafe fn(i16) [-> !]`
0
}
diff --git a/cortex-m-rt/tests/compile-fail/default-handler-hidden.rs b/cortex-m-rt/tests/compile-fail/default-handler-hidden.rs
index e57cb31..c658e2b 100644
--- a/cortex-m-rt/tests/compile-fail/default-handler-hidden.rs
+++ b/cortex-m-rt/tests/compile-fail/default-handler-hidden.rs
@@ -18,5 +18,5 @@ mod hidden {
use cortex_m_rt::exception;
#[exception]
- fn DefaultHandler(_irqn: i16) {}
+ unsafe fn DefaultHandler(_irqn: i16) {}
}
diff --git a/cortex-m-rt/tests/compile-fail/default-handler-twice.rs b/cortex-m-rt/tests/compile-fail/default-handler-twice.rs
index ad1c3f9..bbf2edd 100644
--- a/cortex-m-rt/tests/compile-fail/default-handler-twice.rs
+++ b/cortex-m-rt/tests/compile-fail/default-handler-twice.rs
@@ -12,11 +12,11 @@ fn foo() -> ! {
}
#[exception]
-fn DefaultHandler(_irqn: i16) {}
+unsafe fn DefaultHandler(_irqn: i16) {}
pub mod reachable {
use cortex_m_rt::exception;
#[exception] //~ ERROR symbol `DefaultHandler` is already defined
- fn DefaultHandler(_irqn: i16) {}
+ unsafe fn DefaultHandler(_irqn: i16) {}
}
diff --git a/cortex-m-rt/tests/compile-fail/exception-nmi-unsafe.rs b/cortex-m-rt/tests/compile-fail/exception-nmi-unsafe.rs
new file mode 100644
index 0000000..f5de2f8
--- /dev/null
+++ b/cortex-m-rt/tests/compile-fail/exception-nmi-unsafe.rs
@@ -0,0 +1,24 @@
+#![no_main]
+#![no_std]
+
+extern crate cortex_m_rt;
+extern crate panic_halt;
+
+use cortex_m_rt::{entry, exception};
+
+#[entry]
+fn foo() -> ! {
+ loop {}
+}
+
+#[exception]
+fn DefaultHandler(_irq: i16) {}
+//~^ ERROR defining a `DefaultHandler` is unsafe and requires an `unsafe fn`
+
+#[exception]
+fn HardFault() {}
+//~^ ERROR defining a `HardFault` handler is unsafe and requires an `unsafe fn`
+
+#[exception]
+fn NonMaskableInt() {}
+//~^ ERROR defining a `NonMaskableInt` handler is unsafe and requires an `unsafe fn`
diff --git a/cortex-m-rt/tests/compile-fail/hard-fault-bad-signature-1.rs b/cortex-m-rt/tests/compile-fail/hard-fault-bad-signature-1.rs
index d3b4392..11b53dc 100644
--- a/cortex-m-rt/tests/compile-fail/hard-fault-bad-signature-1.rs
+++ b/cortex-m-rt/tests/compile-fail/hard-fault-bad-signature-1.rs
@@ -12,7 +12,7 @@ fn foo() -> ! {
}
#[exception]
-fn HardFault(_ef: &ExceptionFrame, undef: u32) -> ! {
- //~^ ERROR `HardFault` handler must have signature `[unsafe] fn(&ExceptionFrame) -> !`
+unsafe fn HardFault(_ef: &ExceptionFrame, undef: u32) -> ! {
+ //~^ ERROR `HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`
loop {}
}
diff --git a/cortex-m-rt/tests/compile-fail/hard-fault-twice.rs b/cortex-m-rt/tests/compile-fail/hard-fault-twice.rs
index 030b54c..03b79a5 100644
--- a/cortex-m-rt/tests/compile-fail/hard-fault-twice.rs
+++ b/cortex-m-rt/tests/compile-fail/hard-fault-twice.rs
@@ -12,7 +12,7 @@ fn foo() -> ! {
}
#[exception]
-fn HardFault(_ef: &ExceptionFrame) -> ! {
+unsafe fn HardFault(_ef: &ExceptionFrame) -> ! {
loop {}
}
@@ -20,7 +20,7 @@ pub mod reachable {
use cortex_m_rt::{exception, ExceptionFrame};
#[exception] //~ ERROR symbol `HardFault` is already defined
- fn HardFault(_ef: &ExceptionFrame) -> ! {
+ unsafe fn HardFault(_ef: &ExceptionFrame) -> ! {
loop {}
}
}
diff --git a/cortex-m-rt/tests/compile-fail/unsafe-init-static.rs b/cortex-m-rt/tests/compile-fail/unsafe-init-static.rs
index c040173..23105f1 100644
--- a/cortex-m-rt/tests/compile-fail/unsafe-init-static.rs
+++ b/cortex-m-rt/tests/compile-fail/unsafe-init-static.rs
@@ -29,12 +29,12 @@ fn SVCall() {
}
#[exception]
-fn DefaultHandler(_irq: i16) {
+unsafe fn DefaultHandler(_irq: i16) {
static mut X: u32 = init(); //~ ERROR requires unsafe
}
#[exception]
-fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
+unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
static mut X: u32 = init(); //~ ERROR requires unsafe
loop {}
}