Author: Nikita Popov
Date: 2026-09-21T08:51:52+02:00
New Revision: 7d8c2a2f3436df5c564b61b75cd472f2c4a18a7e

URL: 
https://github.com/llvm/llvm-project/commit/7d8c2a2f3436df5c564b61b75cd472f2c4a18a7e
DIFF: 
https://github.com/llvm/llvm-project/commit/7d8c2a2f3436df5c564b61b75cd472f2c4a18a7e.diff

LOG: [Clang] Do not apply inaccessiblememonly to ::operator new() (#224316)

Do not apply `memory(inaccessiblemem: readwrite, errnomem: write)` to
`::operator new()` style calls (as opposed to `new T`). This matches the
cases where we mark the call as `builtin`, i.e. we only consider it
inaccessiblememonly in the cases where the allocation is also elidable.

I've left the old `noalias` handling alone, so that part keeps being
applied to `::operator new()` as before. Let me know if I should move
that to EmitNewDeleteCall() as well.

Added: 
    

Modified: 
    clang/lib/CodeGen/CGCall.cpp
    clang/lib/CodeGen/CGExprCXX.cpp
    clang/test/CodeGenCXX/new_hot_cold.cpp
    clang/test/CodeGenCXX/operator-new.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 50e04280e2a7d..4c3a4c75d3b52 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2804,17 +2804,10 @@ void CodeGenModule::ConstructAttributeList(StringRef 
Name,
       AddAttributesFromFunctionProtoType(
           getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
       if (AttrOnCallSite && Fn->isReplaceableGlobalAllocationFunction()) {
-        // A sane operator new returns a non-aliasing pointer and does not
-        // read or write accessible memory.
+        // A sane operator new returns a non-aliasing pointer.
         if (getCodeGenOpts().AssumeSaneOperatorNew &&
-            Fn->getDeclName().isAnyOperatorNew()) {
+            Fn->getDeclName().isAnyOperatorNew())
           RetAttrs.addAttribute(llvm::Attribute::NoAlias);
-          // FIXME: inaccessiblemem could cause issues if LTO makes the
-          // previously inaccessible memory accessible after linking.
-          FuncAttrs.addMemoryAttr(
-              llvm::MemoryEffects::inaccessibleOrErrnoMemOnly(
-                  llvm::ModRefInfo::ModRef, llvm::ModRefInfo::Mod));
-        }
       }
       const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
       const bool IsVirtualCall = MD && MD->isVirtual();

diff  --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 97bfcd7bda4e8..8279611accba3 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1391,9 +1391,19 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
   ///
   /// We model such elidable calls with the 'builtin' attribute.
   llvm::Function *Fn = dyn_cast<llvm::Function>(CalleePtr);
-  if (CalleeDecl->isReplaceableGlobalAllocationFunction() && Fn &&
-      Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
-    CallOrInvoke->addFnAttr(llvm::Attribute::Builtin);
+  if (CalleeDecl->isReplaceableGlobalAllocationFunction() && Fn) {
+    if (Fn->hasFnAttribute(llvm::Attribute::NoBuiltin))
+      CallOrInvoke->addFnAttr(llvm::Attribute::Builtin);
+
+    // A sane operator new does not read or write accessible memory.
+    if (CGF.CGM.getCodeGenOpts().AssumeSaneOperatorNew &&
+        CalleeDecl->getDeclName().isAnyOperatorNew()) {
+      // FIXME: inaccessiblemem could cause issues if LTO makes the
+      // previously inaccessible memory accessible after linking.
+      CallOrInvoke->setMemoryEffects(
+          llvm::MemoryEffects::inaccessibleOrErrnoMemOnly(
+              llvm::ModRefInfo::ModRef, llvm::ModRefInfo::Mod));
+    }
   }
 
   return RV;

diff  --git a/clang/test/CodeGenCXX/new_hot_cold.cpp 
b/clang/test/CodeGenCXX/new_hot_cold.cpp
index 439166ddea566..e8ebba1cceee6 100644
--- a/clang/test/CodeGenCXX/new_hot_cold.cpp
+++ b/clang/test/CodeGenCXX/new_hot_cold.cpp
@@ -124,7 +124,7 @@ void hot_cold_new_align_nothrow_array() {
 
 // CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = { nobuiltin allocsize(0) {{.*}} }
 // CHECK-DAG: attributes [[ATTR_NOBUILTIN_NOTHROW]] = { nobuiltin nounwind 
allocsize(0) {{.*}} }
-// CHECK-DAG: attributes [[ATTR_NO_BUILTIN_CALL]] = { allocsize(0) 
memory(inaccessiblemem: readwrite, errnomem: write) }
+// CHECK-DAG: attributes [[ATTR_NO_BUILTIN_CALL]] = { allocsize(0) }
 // CHECK-DAG: attributes [[ATTR_BUILTIN_CALL]] = { builtin allocsize(0) 
memory(inaccessiblemem: readwrite, errnomem: write) }
-// CHECK-DAG: attributes [[ATTR_NO_BUILTIN_NOTHROW_CALL]] = { nounwind 
allocsize(0) memory(inaccessiblemem: readwrite, errnomem: write) }
+// CHECK-DAG: attributes [[ATTR_NO_BUILTIN_NOTHROW_CALL]] = { nounwind 
allocsize(0) }
 // CHECK-DAG: attributes [[ATTR_BUILTIN_NOTHROW_CALL]] = { builtin nounwind 
allocsize(0) memory(inaccessiblemem: readwrite, errnomem: write) }

diff  --git a/clang/test/CodeGenCXX/operator-new.cpp 
b/clang/test/CodeGenCXX/operator-new.cpp
index e741d85fe4cd2..7d89a24941256 100644
--- a/clang/test/CodeGenCXX/operator-new.cpp
+++ b/clang/test/CodeGenCXX/operator-new.cpp
@@ -27,5 +27,14 @@ void *f2(long N) {
 }
 
 // ALL: declare noundef nonnull ptr @_Znaj(
+
+void *f3(unsigned long N) {
+  // SANE: call noalias noundef nonnull ptr @_Znwj(i32 noundef {{.*}}) 
[[ATTR2:#[0-9]+]]
+  // SANENOT: call noundef nonnull ptr @_Znwj(i32 noundef {{.*}}) 
[[ATTR2:#[0-9]+]]
+  return ::operator new(N);
+}
+
 // SANE: attributes [[ATTR]] = { builtin allocsize(0) memory(inaccessiblemem: 
readwrite, errnomem: write) }
+// SANE: attributes [[ATTR2]] = { allocsize(0) }
 // SANENOT: attributes [[ATTR]] = { builtin allocsize(0) }
+// SANENOT: attributes [[ATTR2]] = { allocsize(0) }


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

Reply via email to