Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Use captures(address) instead of captures(none) for indirect args #145877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
bors merged 1 commit into rust-lang:master from nikic:capture-address
Aug 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions compiler/rustc_codegen_llvm/src/abi.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =

const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 6] = [
(ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias),
(ArgAttribute::NoCapture, llvm::AttributeKind::NoCapture),
(ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress),
(ArgAttribute::NonNull, llvm::AttributeKind::NonNull),
(ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly),
(ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
Expand Down Expand Up @@ -84,8 +84,10 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
}
for (attr, llattr) in OPTIMIZATION_ATTRIBUTES {
if regular.contains(attr) {
// captures(address, read_provenance) is only available since LLVM 21.
if attr == ArgAttribute::CapturesReadOnly && llvm_util::get_version() < (21, 0, 0) {
// captures(...) is only available since LLVM 21.
if (attr == ArgAttribute::CapturesReadOnly || attr == ArgAttribute::CapturesAddress)
&& llvm_util::get_version() < (21, 0, 0)
{
continue;
}
attrs.push(llattr.create_attr(cx.llcx));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/llvm/ffi.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ pub(crate) enum AttributeKind {
MinSize = 4,
Naked = 5,
NoAlias = 6,
NoCapture = 7,
CapturesAddress = 7,
NoInline = 8,
NonNull = 9,
NoRedZone = 10,
Expand Down
15 changes: 5 additions & 10 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ enum class LLVMRustAttributeKind {
MinSize = 4,
Naked = 5,
NoAlias = 6,
NoCapture = 7,
CapturesAddress = 7,
NoInline = 8,
NonNull = 9,
NoRedZone = 10,
Expand Down Expand Up @@ -297,12 +297,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
return Attribute::Naked;
case LLVMRustAttributeKind::NoAlias:
return Attribute::NoAlias;
case LLVMRustAttributeKind::NoCapture:
#if LLVM_VERSION_GE(21, 0)
report_fatal_error("NoCapture doesn't exist in LLVM 21");
#else
return Attribute::NoCapture;
#endif
case LLVMRustAttributeKind::NoCfCheck:
return Attribute::NoCfCheck;
case LLVMRustAttributeKind::NoInline:
Expand Down Expand Up @@ -377,6 +371,7 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
#else
report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later");
#endif
case LLVMRustAttributeKind::CapturesAddress:
case LLVMRustAttributeKind::CapturesReadOnly:
report_fatal_error("Should be handled separately");
}
Expand Down Expand Up @@ -429,9 +424,9 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
extern "C" LLVMAttributeRef
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
#if LLVM_VERSION_GE(21, 0)
// LLVM 21 replaced the NoCapture attribute with Captures(none).
if (RustAttr == LLVMRustAttributeKind::NoCapture) {
return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
if (RustAttr == LLVMRustAttributeKind::CapturesAddress) {
return wrap(Attribute::getWithCaptureInfo(
*unwrap(C), CaptureInfo(CaptureComponents::Address)));
}
if (RustAttr == LLVMRustAttributeKind::CapturesReadOnly) {
return wrap(Attribute::getWithCaptureInfo(
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_target/src/callconv/mod.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ mod attr_impl {
bitflags::bitflags! {
impl ArgAttribute: u8 {
const NoAlias = 1 << 1;
const NoCapture = 1 << 2;
const CapturesAddress = 1 << 2;
const NonNull = 1 << 3;
const ReadOnly = 1 << 4;
const InReg = 1 << 5;
Expand Down Expand Up @@ -400,11 +400,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
let mut attrs = ArgAttributes::new();

// For non-immediate arguments the callee gets its own copy of
// the value on the stack, so there are no aliases. It's also
// program-invisible so can't possibly capture
// the value on the stack, so there are no aliases. The function
// can capture the address of the argument, but not the provenance.
attrs
.set(ArgAttribute::NoAlias)
.set(ArgAttribute::NoCapture)
.set(ArgAttribute::CapturesAddress)
.set(ArgAttribute::NonNull)
.set(ArgAttribute::NoUndef);
attrs.pointee_size = layout.size;
Expand Down
6 changes: 3 additions & 3 deletions tests/codegen-llvm/addr-of-mutate.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Test for the absence of `readonly` on the argument when it is mutated via `&raw const`.
// See <https://github.com/rust-lang/rust/issues/111502>.

// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noaliasnoundef align 1{{( captures\(address\))?}} dereferenceable(128) %x)
#[no_mangle]
pub fn foo(x: [u8; 128]) -> u8 {
let ptr = core::ptr::addr_of!(x).cast_mut();
Expand All @@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 {
x[0]
}

// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
// CHECK: i1 @second(ptr{{( dead_on_return)?}} noaliasnoundef align {{[0-9]+}}{{( captures\(address\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
#[no_mangle]
pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut();
Expand All @@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
}

// If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
// CHECK: i1 @third(ptr{{( dead_on_return)?}} noaliasnoundef readonly align {{[0-9]+}}{{( captures\(address\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
#[no_mangle]
pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
Expand Down
4 changes: 2 additions & 2 deletions tests/codegen-llvm/function-arguments.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
#[no_mangle]
pub fn notunpin_borrow(_: &NotUnpin) {}

// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noaliasnoundef readonly align 4{{( captures\(address\))?}} dereferenceable(32) %_1)
#[no_mangle]
pub fn indirect_struct(_: S) {}

Expand Down Expand Up @@ -197,7 +197,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
x
}

// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}})
// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noaliasnoundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(address\))?}} dereferenceable(32){{( %_0)?}})
#[no_mangle]
pub fn struct_return() -> S {
S { _field: [0, 0, 0, 0, 0, 0, 0, 0] }
Expand Down
4 changes: 2 additions & 2 deletions tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,11 @@ pub struct IntDoubleInt {
c: i32,
}

// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noaliasnoundef align 8{{( captures\(address\))?}} dereferenceable(24) %a)
#[no_mangle]
pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}

// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0)
// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noaliasnoundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(address\))?}} dereferenceable(24) %_0)
#[no_mangle]
pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt {
IntDoubleInt { a: 1, b: 2., c: 3 }
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/abi/c-zst.powerpc-linux.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: Some(
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/abi/c-zst.s390x-linux.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: Some(
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/abi/c-zst.sparc64-linux.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: Some(
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: Some(
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/abi/debug.generic.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ error: ABIs are not compatible
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(32 bytes),
pointee_align: Some(
Expand Down Expand Up @@ -527,7 +527,7 @@ error: ABIs are not compatible
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(128 bytes),
pointee_align: Some(
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/abi/debug.loongarch64.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ error: ABIs are not compatible
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(32 bytes),
pointee_align: Some(
Expand Down Expand Up @@ -527,7 +527,7 @@ error: ABIs are not compatible
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(128 bytes),
pointee_align: Some(
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/abi/debug.riscv64.stderr
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ error: ABIs are not compatible
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(32 bytes),
pointee_align: Some(
Expand Down Expand Up @@ -527,7 +527,7 @@ error: ABIs are not compatible
},
mode: Indirect {
attrs: ArgAttributes {
regular: NoAlias | NoCapture | NonNull | NoUndef,
regular: NoAlias | CapturesAddress | NonNull | NoUndef,
arg_ext: None,
pointee_size: Size(128 bytes),
pointee_align: Some(
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/codegen/indirect-nocapture.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Regression test for issue #137668 where an indirect argument have been marked as nocapture
// despite the fact that callee did in fact capture the address.
//
//@ run-pass
//@ compile-flags: -Copt-level=2

#[inline(never)]
pub fn f(a: [u32; 64], b: [u32; 64]) -> bool {
&a as *const _ as usize != &b as *const _ as usize
}

fn main() {
static S: [u32; 64] = [0; 64];
assert!(f(S, S));
}
Loading

AltStyle によって変換されたページ (->オリジナル) /