Prevent field projection through references?

There is alas no standalone / reliable way to avoid .-deref operations from occurring when inside a ptr::addr_of{,_mut}!(…) invocation.

The usual workaround is to be less ambitious w.r.t. projections, and allow the macro to handle them one by one.

From there, by requiring that the intermediary type (your P::Inner) be specified to the macro as well, the macro can then make the necessary previous checks to make it impossible for the caller to "smuggle" derefs.

Demo


In that demo, the syntax I have chosen is:

project!(
    & <mut>? <expr> => <P::Inner> => .<field>
)
  • e.g., for a tuple:

    project!(&m => (_, _) => .1)
    
  • and for a (tuple) struct:

    project!(&m => StructName<...> => .some_field)
    

The key idea is that, for (tuple) structs, emitting:

let StructName { field_name: _, .. };

is:

  • valid Rust code you can emit anywhere;
    • even for numerical/indexed field names! let Wrapper { 0: _, .. }.
  • and which compile-time asserts the existence of .field_name for that type, thereby guaranteeing lack of *-deref shenanigans being involved.

For actual Rust tuples, whilst we cannot do this, it turns out that we do know they do not implement Deref.

Finally, by emitting the given type in the input arg signature of the closure expected to work with P::Inner, we are effectively asserting that these two match, so that a ManuallyDrop<& ...> with thus a P::Inner of & ... will correctly reject any of these two usages.

3 Likes