llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Henrik G. Olsson (hnrklssn)

<details>
<summary>Changes</summary>

`capture(none)` has very restrictive semantics and an easy footgun to 
accidentally fire some UB into your code with. Most significantly it does not 
allow any visible side-effects of whether a pointer was null or not to escape 
the function. This means that the function cannot perform different side 
effects depending on whether a pointer marked `noescape` is null. Relax this to 
`captures(address)`, which allows information about the numerical address to 
escape the function, but no provenance (i.e. nothing that could be 
dereferenced) may escape.

As discussed in 
https://discourse.llvm.org/t/rfc-updating-the-semantics-of-the-noescape-attribute/90326.

---
Full diff: https://github.com/llvm/llvm-project/pull/199281.diff


3 Files Affected:

- (modified) clang/lib/CodeGen/CGCall.cpp (+1-1) 
- (modified) clang/test/CodeGenCXX/noescape.cpp (+15-15) 
- (modified) clang/test/CodeGenObjC/noescape.m (+13-13) 


``````````diff
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7194b81459922..d09e62eb52a53 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3163,7 +3163,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
     }
 
     if (FI.getExtParameterInfo(ArgNo).isNoEscape())
-      Attrs.addCapturesAttr(llvm::CaptureInfo::none());
+      
Attrs.addCapturesAttr(llvm::CaptureInfo(llvm::CaptureComponents::Address));
 
     if (Attrs.hasAttributes()) {
       unsigned FirstIRArg, NumIRArgs;
diff --git a/clang/test/CodeGenCXX/noescape.cpp 
b/clang/test/CodeGenCXX/noescape.cpp
index c3fc90e2ea54d..9c1ea1719bea5 100644
--- a/clang/test/CodeGenCXX/noescape.cpp
+++ b/clang/test/CodeGenCXX/noescape.cpp
@@ -8,26 +8,26 @@ struct S {
   virtual void vm1(int *, int * __attribute__((noescape)));
 };
 
-// CHECK: define{{.*}} void @_ZN1SC2EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(none) {{%.*}})
-// CHECK: define{{.*}} void @_ZN1SC1EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(none) {{%.*}}) {{.*}} {
-// CHECK: call void @_ZN1SC2EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} captures(none) 
{{.*}})
+// CHECK: define{{.*}} void @_ZN1SC2EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(address) {{%.*}})
+// CHECK: define{{.*}} void @_ZN1SC1EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(address) {{%.*}}) {{.*}} {
+// CHECK: call void @_ZN1SC2EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} 
captures(address) {{.*}})
 
 S::S(int *, int * __attribute__((noescape))) {}
 
-// CHECK: define {{.*}} ptr @_ZN1SaSEPi(ptr {{.*}}, {{.*}} noundef 
captures(none) {{%.*}})
+// CHECK: define {{.*}} ptr @_ZN1SaSEPi(ptr {{.*}}, {{.*}} noundef 
captures(address) {{%.*}})
 S &S::operator=(int * __attribute__((noescape))) { return *this; }
 
-// CHECK: define{{.*}} void @_ZN1S2m0EPiS0_(ptr {{.*}}, {{.*}} noundef 
captures(none) {{%.*}})
+// CHECK: define{{.*}} void @_ZN1S2m0EPiS0_(ptr {{.*}}, {{.*}} noundef 
captures(address) {{%.*}})
 void S::m0(int *, int * __attribute__((noescape))) {}
 
-// CHECK: define{{.*}} void @_ZN1S3vm1EPiS0_(ptr {{.*}}, {{.*}} noundef 
captures(none) {{%.*}})
+// CHECK: define{{.*}} void @_ZN1S3vm1EPiS0_(ptr {{.*}}, {{.*}} noundef 
captures(address) {{%.*}})
 void S::vm1(int *, int * __attribute__((noescape))) {}
 
 // CHECK-LABEL: define{{.*}} void @_Z5test0P1SPiS1_(
-// CHECK: call void @_ZN1SC1EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(none) {{.*}})
-// CHECK: call {{.*}} ptr @_ZN1SaSEPi(ptr {{.*}}, {{.*}} noundef 
captures(none) {{.*}})
-// CHECK: call void @_ZN1S2m0EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(none) {{.*}})
-// CHECK: call void {{.*}}(ptr {{.*}}, {{.*}}, {{.*}} noundef captures(none) 
{{.*}})
+// CHECK: call void @_ZN1SC1EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(address) {{.*}})
+// CHECK: call {{.*}} ptr @_ZN1SaSEPi(ptr {{.*}}, {{.*}} noundef 
captures(address) {{.*}})
+// CHECK: call void @_ZN1S2m0EPiS0_(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(address) {{.*}})
+// CHECK: call void {{.*}}(ptr {{.*}}, {{.*}}, {{.*}} noundef 
captures(address) {{.*}})
 void test0(S *s, int *p0, int *p1) {
   S t(p0, p1);
   t = p1;
@@ -39,27 +39,27 @@ namespace std {
   typedef decltype(sizeof(0)) size_t;
 }
 
-// CHECK: define {{.*}} @_ZnwmPv({{.*}}, {{.*}} captures(none) {{.*}})
+// CHECK: define {{.*}} @_ZnwmPv({{.*}}, {{.*}} captures(address) {{.*}})
 void *operator new(std::size_t, void * __attribute__((noescape)) p) {
   return p;
 }
 
 // CHECK-LABEL: define{{.*}} ptr @_Z5test1Pv(
-// CHECK: %call = call {{.*}} @_ZnwmPv({{.*}}, {{.*}} captures(none) {{.*}})
+// CHECK: %call = call {{.*}} @_ZnwmPv({{.*}}, {{.*}} captures(address) {{.*}})
 void *test1(void *p0) {
   return ::operator new(16, p0);
 }
 
 // CHECK-LABEL: define{{.*}} void @_Z5test2PiS_(
-// CHECK: call void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, {{.*}} 
captures(none) {{.*}})
-// CHECK: define internal void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, 
{{.*}} noundef captures(none) {{%.*}})
+// CHECK: call void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, {{.*}} 
captures(address) {{.*}})
+// CHECK: define internal void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, 
{{.*}} noundef captures(address) {{%.*}})
 void test2(int *p0, int *p1) {
   auto t = [](int *, int * __attribute__((noescape))){};
   t(p0, p1);
 }
 
 // CHECK-LABEL: define{{.*}} void @_Z5test3PFvU8noescapePiES_(
-// CHECK: call void {{.*}}(ptr noundef captures(none) {{.*}})
+// CHECK: call void {{.*}}(ptr noundef captures(address) {{.*}})
 typedef void (*NoEscapeFunc)(__attribute__((noescape)) int *);
 
 void test3(NoEscapeFunc f, int *p) {
diff --git a/clang/test/CodeGenObjC/noescape.m 
b/clang/test/CodeGenObjC/noescape.m
index e1dbc0eb92e54..80d4bb8e1c876 100644
--- a/clang/test/CodeGenObjC/noescape.m
+++ b/clang/test/CodeGenObjC/noescape.m
@@ -26,37 +26,37 @@
 // CHECK: @[[BLOCK_DESCIPTOR_TMP_2:.*ls32l8"]] = linkonce_odr hidden 
unnamed_addr constant { i64, i64, ptr, i64 } { i64 0, i64 40, ptr @{{.*}}, i64 
256 }, align 8
 
 // CHECK-LABEL: define{{.*}} void @test0(
-// CHECK: call void @noescapeFunc0({{.*}}, {{.*}} captures(none) {{.*}})
-// CHECK: declare void @noescapeFunc0(ptr noundef, {{.*}} noundef 
captures(none))
+// CHECK: call void @noescapeFunc0({{.*}}, {{.*}} captures(address) {{.*}})
+// CHECK: declare void @noescapeFunc0(ptr noundef, {{.*}} noundef 
captures(address))
 void test0(BlockTy b) {
   noescapeFunc0(0, b);
 }
 
 // CHECK-LABEL: define{{.*}} void @test1(
-// CHECK: call void @noescapeFunc1({{.*}} captures(none) {{.*}})
-// CHECK: declare void @noescapeFunc1({{.*}} noundef captures(none))
+// CHECK: call void @noescapeFunc1({{.*}} captures(address) {{.*}})
+// CHECK: declare void @noescapeFunc1({{.*}} noundef captures(address))
 void test1(int *i) {
   noescapeFunc1(i);
 }
 
 // CHECK-LABEL: define{{.*}} void @test2(
-// CHECK: call void @noescapeFunc2({{.*}} captures(none) {{.*}})
-// CHECK: declare void @noescapeFunc2({{.*}} noundef captures(none))
+// CHECK: call void @noescapeFunc2({{.*}} captures(address) {{.*}})
+// CHECK: declare void @noescapeFunc2({{.*}} noundef captures(address))
 void test2(id i) {
   noescapeFunc2(i);
 }
 
 // CHECK-LABEL: define{{.*}} void @test3(
-// CHECK: call void @noescapeFunc3({{.*}} captures(none) {{.*}})
-// CHECK: declare void @noescapeFunc3({{.*}} captures(none))
+// CHECK: call void @noescapeFunc3({{.*}} captures(address) {{.*}})
+// CHECK: declare void @noescapeFunc3({{.*}} captures(address))
 void test3(union U u) {
   noescapeFunc3(u);
 }
 
-// CHECK: define internal void @"\01-[C0 m0:]"({{.*}}, {{.*}}, {{.*}} 
captures(none) {{.*}})
+// CHECK: define internal void @"\01-[C0 m0:]"({{.*}}, {{.*}}, {{.*}} 
captures(address) {{.*}})
 
 // CHECK-LABEL: define{{.*}} void @test4(
-// CHECK: call void @objc_msgSend(ptr {{.*}}, ptr {{.*}}, ptr noundef 
captures(none) {{.*}})
+// CHECK: call void @objc_msgSend(ptr {{.*}}, ptr {{.*}}, ptr noundef 
captures(address) {{.*}})
 
 @interface C0
 -(void) m0:(int*)__attribute__((noescape)) p0;
@@ -72,9 +72,9 @@ void test4(C0 *c0, int *p) {
 }
 
 // CHECK-LABEL: define{{.*}} void @test5(
-// CHECK: call void {{.*}}(ptr noundef @{{.*}}, ptr noundef captures(none) 
{{.*}})
-// CHECK: call void {{.*}}(ptr {{.*}}, ptr noundef captures(none) {{.*}})
-// CHECK: define internal void @{{.*}}(ptr {{.*}}, ptr noundef captures(none) 
{{.*}})
+// CHECK: call void {{.*}}(ptr noundef @{{.*}}, ptr noundef captures(address) 
{{.*}})
+// CHECK: call void {{.*}}(ptr {{.*}}, ptr noundef captures(address) {{.*}})
+// CHECK: define internal void @{{.*}}(ptr {{.*}}, ptr noundef 
captures(address) {{.*}})
 
 typedef void (^BlockTy2)(__attribute__((noescape)) int *);
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/199281
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to