• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 // unaligned_references did not exist in older compilers and safe_packed_borrows was removed in the latest compilers.
4 // https://github.com/rust-lang/rust/pull/82525
5 #![allow(unknown_lints, renamed_and_removed_lints)]
6 #![forbid(unaligned_references, safe_packed_borrows)]
7 
8 use std::cell::Cell;
9 
10 // Ensure that the compiler doesn't copy the fields
11 // of #[repr(packed)] types during drop, if the field has alignment 1
12 // (that is, any reference to the field is guaranteed to have proper alignment)
13 // We are currently unable to statically prevent the usage of #[pin_project]
14 // on #[repr(packed)] types composed entirely of fields of alignment 1.
15 // This shouldn't lead to undefined behavior, as long as the compiler doesn't
16 // try to move the field anyway during drop.
17 //
18 // This tests validates that the compiler is doing what we expect.
19 #[test]
weird_repr_packed()20 fn weird_repr_packed() {
21     // We keep track of the field address during
22     // drop using a thread local, to avoid changing
23     // the layout of our #[repr(packed)] type.
24     thread_local! {
25         static FIELD_ADDR: Cell<usize> = Cell::new(0);
26     }
27 
28     #[repr(packed)]
29     struct Struct {
30         field: u8,
31     }
32 
33     impl Drop for Struct {
34         fn drop(&mut self) {
35             FIELD_ADDR.with(|f| {
36                 f.set(&self.field as *const u8 as usize);
37             });
38         }
39     }
40 
41     let field_addr = {
42         // We let this field drop by going out of scope,
43         // rather than explicitly calling drop(foo).
44         // Calling drop(foo) causes 'foo' to be moved
45         // into the 'drop' function, resulting in a different
46         // address.
47         let x = Struct { field: 27 };
48         &x.field as *const u8 as usize
49     };
50     assert_eq!(field_addr, FIELD_ADDR.with(Cell::get));
51 }
52