macro_rules! id {
    ($($tt:tt)*) => {
        $($tt)*
    };
}
macro_rules! unsafe_deref {
    () => {
        *(&() as *const ())
    };
}

union Union {
    field: u32,
}

struct Struct { field: i32 }

static mut MUT_GLOBAL: Struct = Struct { field: 0 };
unsafe fn unsafe_fn() {}

impl Struct {
    unsafe fn unsafe_method(&self) {}
}

unsafe trait UnsafeTrait {}
unsafe impl UnsafeTrait for Union {}
impl !UnsafeTrait for () {}

fn unsafe_trait_bound<T: UnsafeTrait>(_: T) {}

extern {
    static EXTERN_STATIC: ();
}

fn main() {
    let x: *const usize;
    let u: Union;

    // id should be safe here, but unsafe_deref should not
    id! {
        unsafe { unsafe_deref!() }
    };

    unsafe {
        // unsafe macro calls
        unsafe_deref!();
        id! { unsafe_deref!() };

        // unsafe fn and method calls
        unsafe_fn();
        self::unsafe_fn();
        (unsafe_fn as unsafe fn())();
        Struct { field: 0 }.unsafe_method();

        u.field;
        &u.field;
        &raw const u.field;
        // this should be safe!
        let Union { field: _ };
        // but not these
        let Union { field };
        let Union { field: field };
        let Union { field: ref field };
        let Union { field: (_ | ref field) };

        // unsafe deref
        *&raw const*&*x;

        // unsafe access to a static mut
        MUT_GLOBAL.field;
        &MUT_GLOBAL.field;
        &raw const MUT_GLOBAL.field;
        MUT_GLOBAL;
        &MUT_GLOBAL;
        &raw const MUT_GLOBAL;
        EXTERN_STATIC;
        &EXTERN_STATIC;
        &raw const EXTERN_STATIC;

        core::arch::asm!(
            "push {base}",
            base = const 0
        );
    }
}