diff options
| author | bors <bors@rust-lang.org> | 2020-07-22 08:18:46 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-07-22 08:18:46 +0000 |
| commit | e22b61bff0bdd08be7665607cb7be3748c8a35d2 (patch) | |
| tree | 01a600863f4ef3e76cfe58ceef2ba5d91700557e /src/test/codegen | |
| parent | 4825e12fc9c79954aa0fe18f5521efa6c19c7539 (diff) | |
| parent | 5581ce6c10ae0b4e6503db0081e2defd7ef829ff (diff) | |
| download | rust-e22b61bff0bdd08be7665607cb7be3748c8a35d2.tar.gz rust-e22b61bff0bdd08be7665607cb7be3748c8a35d2.zip | |
Auto merge of #73270 - dylanmckay:avr-use-correct-addrspace, r=nagisa
[AVR] Correctly set the pointer address space when constructing pointers to functions NOTE: Pull request iterations: * https://github.com/dylanmckay/rust/releases/tag/avr-use-correct-addrspace.0 * https://github.com/dylanmckay/rust/releases/tag/avr-use-correct-addrspace.1 * https://github.com/dylanmckay/rust/releases/tag/avr-use-correct-addrspace.2 This patch extends the existing `type_i8p` method so that it requires an explicit address space to be specified. Before this patch, the `type_i8p` method implcitily assumed the default address space, which is not a safe transformation on all targets, namely AVR. The Rust compiler already has support for tracking the "instruction address space" on a per-target basis. This patch extends the code generation routines so that an address space must always be specified. In my estimation, around 15% of the callers of `type_i8p` produced invalid code on AVR due to the loss of address space prior to LLVM final code generation. This would lead to unavoidable assertion errors relating to invalid bitcasts. With this patch, the address space is always either 1) explicitly preserved from the input type, or 2) explicitly set to the instruction address space because the logic is dealing with functions which must be placed there, or 3) explicitly set to the default address space 0 because the logic can only operate on data space pointers and thus we keep the existing semantics of assuming the default, "data" address space.
Diffstat (limited to 'src/test/codegen')
| -rw-r--r-- | src/test/codegen/avr/avr-func-addrspace.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/test/codegen/avr/avr-func-addrspace.rs b/src/test/codegen/avr/avr-func-addrspace.rs new file mode 100644 index 00000000000..7759d9603a5 --- /dev/null +++ b/src/test/codegen/avr/avr-func-addrspace.rs @@ -0,0 +1,93 @@ +// compile-flags: -O --target=avr-unknown-unknown --crate-type=rlib + +// This test validates that function pointers can be stored in global variables +// and called upon. It ensures that Rust emits function pointers in the correct +// address space to LLVM so that an assertion error relating to casting is +// not triggered. +// +// It also validates that functions can be called through function pointers +// through traits. + +#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +pub trait Sized { } +#[lang = "copy"] +pub trait Copy { } +#[lang = "receiver"] +pub trait Receiver { } + +pub struct Result<T, E> { _a: T, _b: E } + +impl Copy for usize {} + +#[lang = "drop_in_place"] +pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +pub trait FnMut<Args> : FnOnce<Args> { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "fn"] +pub trait Fn<Args>: FnOnce<Args> { + /// Performs the call operation. + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> R { + (*self)(args) + } +} + +pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box; +pub static mut STORAGE_BAR: u32 = 12; + +fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> { + let raw_ptr = ptr as *const usize; + let _v: usize = unsafe { *raw_ptr }; + loop {} +} + +#[inline(never)] +#[no_mangle] +fn call_through_fn_trait(a: &mut impl Fn<(), Output=()>) { + (*a)() +} + +#[inline(never)] +fn update_bar_value() { + unsafe { + STORAGE_BAR = 88; + } +} + +// CHECK: define void @test(){{.+}}addrspace(1) +#[no_mangle] +pub extern "C" fn test() { + let mut buf = 7; + + // A call through the Fn trait must use address space 1. + // + // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait() + call_through_fn_trait(&mut update_bar_value); + + // A call through a global variable must use address space 1. + // CHECK: load {{.*}}addrspace(1){{.+}}FOO + unsafe { + STORAGE_FOO(&1, &mut buf); + } +} |
