Change:
This function compiles to Notice the attribute! Under current LLVM semantics, this means "dereferenceable for the entire duration of this function body". That is, clearly, not accurate. This issue is closely related to , but affects all instead of just a few uses of references, so I felt it is a separate discussion. I propose we remove the attribute from for now. It seems like the situation might , but we should first make things sound. Thanks to for pointing this out. Cc
triage: P-high. Leaving nominated tag on it for now.
The T-lang design team this last night in their weekly meeting. It seems like we should indeed look into taking the short-term action of ceasing our emission of for parameters. Some members of the Rust team should try to follow the LLVM-dev discussion of ///etc. See for example this email thread: and this LLVM Pull Request: People may even want to give feedback about our particular use case; has already started doing so. The and WG-LLVM are probably the most relevant working groups to try to solicit here But that is a much broader topic than the relatively limited issue at hand here in . Regarding removal of from : some T-lang teammates did note that it would be best to see some benchmark results to have an idea of the performance impact before we land the change. (We generally believe that passing around a in this fashion is relatively rare, and thus the performance impact will be limited. But still, best to try to validate that claim if we can.)
I can write the patch to remove from , but wouldn't know what to benchmark beyond rust-perf (and likely wouldn't have the time, either).
well lets start with that and go from there. I bet another community member can handle the benchmarking if you provide a PR with the patch.
Turns out I was a bit too quick to promise this... I think I traced the attribute to , but unfortunately that code ties "nonnull" and "dereferencable" together. (Though, interestingly, the type somehow manages to get just that attribute...) I am not sure how to disentangle that. The goal is to make still and but not . But the only use of is in to turn it into a ; there does not seem to be enough information here to say whether that's noalias with or without dereferencable. any advice?
The code you linked doesn't seem like an obstacle for this change? As long as you can arrange for being 0 for Box arguments (edit: seems to happen ) this code should do the right thing: keep the nonnull attribute and not add any variant of dereferenceable. Am I missing something?
Ah, I didn't realize that is what controls "dereferenceable". And I am also not sure if that is right... the is set even for raw pointers! (And that is, I think, where it comes from for .)
That would be super wrong, but empirically we don't get on raw pointers, so you must be mistaken. Why do you think is set for raw pointers? The line I linked earlier only sets it for safe pointers, it's guarded by an to that effect.
There's also a field. So my guess is gets when it's and has a non-zero . The code is here: Notice how it doesn't set any size. But it previously recursively traversed the field of , and that finds a raw ptr nested inside a .
But that (edit: meaning ) is the field, not .
Yeah I know, but becomes later. That is the only place is used, so I assume the size also gets propagated.
Here it is:
That's the line I linked ! Although I edited in, so I guess that's why you didn't see it.
Yes so? is where all the type-dependent smarts happen, that just gets translated to later. I don't know why both of them exist, but it seems to be abstraction-breaking to do anything type-dependent in that translation. The code is already spaghetti enough without two places that incorporate type information.^^
Also you asked where gets set for raw ptrs, and I did answer that question: first gets set for raw ptrs, later that value gets put into .
Ask I guess But crucially it doesn't get put there for raw pointers. So is not set for raw pointers.
Ah, because that line copying it is guarded by . I missed that. So seems to indicate "dereferencable" via the size... hm. Maybe we just want that to remain 0 then for ? So, not looking at the type, but the . That doesn't seem quite so abstraction-breaking. I guess that's what you meant.
Yeah. Glad we're finally on the same page :)
I just had to unfold some spaghetti first. ;)
PR open at

Discussion:
if let Some(pointee) = layout.pointee_info_at(cx, offset) { if let Some(kind) = pointee.safe { <del> attrs.pointee_size = pointee.size; </del> attrs.pointee_align = Some(pointee.align); <ins> // `Box` (`UniqueBorrowed`) are not necessarily dereferencable // for the entire duration of the function as they can be deallocated // any time. Set their valid size to 0. attrs.pointee_size = match kind { PointerKind::UniqueOwned => Size::ZERO, _ => pointee.size }; </ins> // `Box` pointer parameters never alias because ownership is transferred // `&mut` pointer parameters never alias other parameters, // or mutable global data

#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct ArgAttributes { pub regular: ArgAttribute, <ins> /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes). </ins> pub pointee_size: Size, pub pointee_align: Option<Align> }

pub fn borrowed_struct(_: &S) { } <del> // CHECK: noalias align 4 dereferenceable(4) i32* @_box(i32* noalias align 4 dereferenceable(4) %x) </del> <ins> // `Box` can get deallocated during execution of the function, so it should // not get `dereferenceable`. // CHECK: noalias nonnull align 4 i32* @_box(i32* noalias nonnull align 4 %x) </ins> #[no_mangle] pub fn _box(x: Box<i32>) -> Box<i32> { x