Pre-RFC: hygine-based unsaftey

Either over an editon bounty or via an attribute (or possibly both, where the default value for the macro changes between editions), change how macro hygine interacts with unsaftey.

semantically, every span would be labeled with it's ability to call unsafe code before macro expansion happens, although this is unlikely to be the actual implementation in the compiler. any legacy macros would fall back to the normal unsafe resolution post-expansion.

this would prevent any "unsafe" blocks inside the macro from leaking out and allowing the macro arguments to use unsafe code, while also allowing all arguments to macros within an unsafe block to use unsafe, unlike the proposal for safe blocks.

in order to facilitate the continued existence of unsafe-to-call macros, this would be accompanied by allowing macros to be marked unsafe like functions can be.

6 Likes

There are some corner cases which need to be worked out where neither the macro code nor the arguments necessarily require unsafe, but their combination does. For example, I'm not sure exactly which span(s) below are "calling" unsafe code. With hygiene-based safety, where do the unsafe markers need to be added (and why)?

macro_rules! inc {
    ($x:expr) => (*$x += 1)
}

// ----

let x: *mut u32 = ...;
inc!(x);

let y: &mut u32 = ...;
inc!(y);
1 Like

the deref operator is the unsafe bit there.

it's whatever span the E0133 diagnostic points at.

1 Like

So, if I understand the proposal correctly, unsafe { inc!(x) } would no longer compile because the unsafe operation arises from within the macro expander. Instead, we need to add the unsafe block inside the macro itself:

macro_rules! inc {
    ($x:expr) => ( unsafe { *$x += 1 } )
}

That's undesirable because this macro has no reasonable way to enforce the preconditions. We could also make the macro unsafe to call, but then that requires a spurious unsafe block around inc!(y).

So, I guess that my question really is what's the expected/best way to migrate this code to hygienic unsafe?

no, in this case the caller should use unsafe to turn the raw pointer into a reference (making sure not to violate aliasing rules), the same way you would do if you needed to pass a raw pointer into a safe function.

1 Like