Rust 中的结构体std::cell::Ref
定义如下:
pub struct Ref<'b, T: ?Sized + 'b> {
// NB: we use a pointer instead of `&'b T` to avoid `noalias` violations, because a
// `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
// `NonNull` is also covariant over `T`, just like we would have with `&T`.
value: NonNull<T>,
borrow: BorrowRef<'b>,
}
评论// NB
(我假设 Nota bene / Nasty Bug 或其他什么?)暗示以下定义不起作用,因为这会违反noalias
(它们是否意味着后端的 LLVM 属性?):
pub struct Ref2<'b, T: ?Sized + 'b> {
value: &'b T,
borrow: BorrowRef<'b>,
}
我不明白这一点,因为我的印象是非词汇生命周期语义在代码生成中得到了正确的保留。否则下面的简单示例(当然可以编译)也是非法的,对吗?:
struct Foo<'a> {
v: &'a i32,
}
fn foo(x: &mut i32) {
let f = Foo { v: x };
*x = 5; // value modified while the `noalias` f.v pointer is still in scope
}
对内部结构有更多了解的人可以为我阐明这一点吗?我担心我在这里误解了一些关键的东西,导致我自己的不安全代码出现潜在问题。
非词法生命周期从来都不是代码生成的属性。它们纯粹是借用检查器属性,借用检查永远不会影响代码生成。
根据 LLVM,您提供的示例并不违法。问题
noalias
仅体现在函数参数上,因为只有它们才获得noalias
属性(至少目前如此)。因此,编写有问题的代码而没有不安全代码的唯一方法是:但它无法编译,因为您正在移动借用的
v
. 所以实际上没有办法触发错误编译。但是
RefCell
,我们可以这样做:Ref
如果使用参考,这将是 LLVM UB 。