https://github.com/chaitanyav updated 
https://github.com/llvm/llvm-project/pull/169869

>From fc8d8c7cc306bc8531065260da0456a510747884 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Thu, 27 Nov 2025 19:18:31 -0800
Subject: [PATCH 1/5] [Clang] Make __builtin_assume_dereferenceable constexpr

Enable constant evaluation of __builtin_assume_dereferenceable.
During evaluation, we verify the pointer is valid and the requested
bytes are dereferenceable.

Resolves:#168335
---
 clang/include/clang/Basic/Builtins.td         |  2 +-
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      | 34 ++++++++++
 clang/lib/AST/ExprConstant.cpp                | 29 +++++++++
 ...iltin-assume-dereferenceable-constexpr.cpp | 64 +++++++++++++++++++
 4 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 6d6104a3ddb8d..226ad1cc03078 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -859,7 +859,7 @@ def BuiltinAssumeAligned : Builtin {
 
 def BuiltinAssumeDereferenceable : Builtin {
   let Spellings = ["__builtin_assume_dereferenceable"];
-  let Attributes = [NoThrow, Const];
+  let Attributes = [NoThrow, Const, Constexpr];
   let Prototype = "void(void const*, size_t)";
 }
 
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 8496b58105c7a..1abddae3d6358 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2170,6 +2170,37 @@ static unsigned computePointerOffset(const ASTContext 
&ASTCtx,
   return Result;
 }
 
+/// __builtin_assume_dereferenceable(Ptr, Size)
+static bool interp__builtin_assume_dereferenceable(InterpState &S, CodePtr 
OpPC,
+                                                   const InterpFrame *Frame,
+                                                   const CallExpr *Call) {
+  assert(Call->getNumArgs() == 2);
+
+  APSInt ReqSize = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)));
+  if (ReqSize.getZExtValue() < 1)
+    return false;
+
+  const Pointer &Ptr = S.Stk.pop<Pointer>();
+  if (Ptr.isZero() || !Ptr.isLive() || !Ptr.isBlockPointer() || 
Ptr.isPastEnd())
+    return false;
+
+  const ASTContext &ASTCtx = S.getASTContext();
+  const Descriptor *DeclDesc = Ptr.getDeclDesc();
+  std::optional<unsigned> FullSize = computeFullDescSize(ASTCtx, DeclDesc);
+  if (!FullSize)
+    return false;
+
+  unsigned ByteOffset = computePointerOffset(ASTCtx, Ptr);
+  if (ByteOffset > *FullSize)
+    return false;
+
+  unsigned RemainingSpace = *FullSize - ByteOffset;
+  if (RemainingSpace < ReqSize.getZExtValue())
+    return false;
+
+  return true;
+}
+
 /// Does Ptr point to the last subobject?
 static bool pointsToLastObject(const Pointer &Ptr) {
   Pointer P = Ptr;
@@ -3725,6 +3756,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const 
CallExpr *Call,
   case Builtin::BI__assume:
     return interp__builtin_assume(S, OpPC, Frame, Call);
 
+  case Builtin::BI__builtin_assume_dereferenceable:
+    return interp__builtin_assume_dereferenceable(S, OpPC, Frame, Call);
+
   case Builtin::BI__builtin_strcmp:
   case Builtin::BIstrcmp:
   case Builtin::BI__builtin_strncmp:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b986ee6ca4fa3..fe42afe5ddd78 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19690,6 +19690,35 @@ class VoidExprEvaluator
       // The argument is not evaluated!
       return true;
 
+    case Builtin::BI__builtin_assume_dereferenceable: {
+      assert(E->getType()->isVoidType());
+      assert(E->getNumArgs() == 2);
+
+      APSInt ReqSizeVal;
+      if (!::EvaluateInteger(E->getArg(1), ReqSizeVal, Info))
+        return false;
+      LValue Pointer;
+      if (!EvaluatePointer(E->getArg(0), Pointer, Info))
+        return false;
+      if (Pointer.Designator.Invalid)
+        return false;
+      if (Pointer.isNullPointer())
+        return false;
+
+      uint64_t ReqSize = ReqSizeVal.getZExtValue();
+      if (ReqSize < 1)
+        return false;
+      CharUnits EndOffset;
+      if (!determineEndOffset(Info, E->getExprLoc(), 0, Pointer, EndOffset))
+        return false;
+
+      uint64_t TotalSize =
+          (EndOffset - Pointer.getLValueOffset()).getQuantity();
+      if (TotalSize < ReqSize) {
+        return false;
+      }
+      return true;
+    }
     case Builtin::BI__builtin_operator_delete:
       return HandleOperatorDeleteCall(Info, E);
 
diff --git a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp 
b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
new file mode 100644
index 0000000000000..158eb78cbdabc
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -triple 
x86_64-unknown-unknown %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -triple 
x86_64-unknown-unknown %s -fexperimental-new-constant-interpreter
+
+constexpr int arr[10] = {};
+
+constexpr bool test_constexpr_valid() {
+  __builtin_assume_dereferenceable(arr, 40);
+  return true;
+}
+static_assert(test_constexpr_valid(), "");
+
+constexpr bool test_constexpr_partial() {
+  __builtin_assume_dereferenceable(&arr[5], 20);
+  return true;
+}
+static_assert(test_constexpr_partial(), "");
+
+constexpr bool test_constexpr_nullptr() {
+  __builtin_assume_dereferenceable(nullptr, 4);
+  return true;
+}
+static_assert(test_constexpr_nullptr(), ""); // expected-error {{not an 
integral constant expression}}
+
+constexpr bool test_constexpr_too_large() {
+  __builtin_assume_dereferenceable(arr, 100);
+  return true;
+}
+static_assert(test_constexpr_too_large(), ""); // expected-error {{not an 
integral constant expression}}
+
+constexpr int single_var = 42;
+constexpr bool test_single_var() {
+  __builtin_assume_dereferenceable(&single_var, 4);
+  return true;
+}
+static_assert(test_single_var(), "");
+
+constexpr bool test_exact_boundary() {
+  __builtin_assume_dereferenceable(&arr[9], 4);
+  return true;
+}
+static_assert(test_exact_boundary(), "");
+
+constexpr bool test_one_over() {
+  __builtin_assume_dereferenceable(&arr[9], 5);
+  return true;
+}
+static_assert(test_one_over(), ""); // expected-error {{not an integral 
constant expression}}
+
+constexpr bool test_zero_size() {
+  __builtin_assume_dereferenceable(arr, 0);
+  return true;
+}
+static_assert(test_zero_size(), ""); // expected-error {{not an integral 
constant expression}}
+
+struct S {
+  int x;
+  int y;
+};
+constexpr S s = {1, 2};
+constexpr bool test_struct_member() {
+  __builtin_assume_dereferenceable(&s.x, 4);
+  return true;
+}
+static_assert(test_struct_member(), "");

>From 4ca8c6acd3ea990b751ff989d34a52fd14ea3da6 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Fri, 28 Nov 2025 17:03:08 -0800
Subject: [PATCH 2/5] * Emit diagnostics when validation fails: null pointer,
 one-past-the-end, out-of-bounds access. * Enhance test suite to cover more
 scenarios * Return true when Size is zero.

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      | 25 ++++++--
 clang/lib/AST/ExprConstant.cpp                | 18 ++++--
 ...iltin-assume-dereferenceable-constexpr.cpp | 64 +++++++++++++------
 3 files changed, 78 insertions(+), 29 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 1abddae3d6358..190d8e4e3dda5 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2177,12 +2177,22 @@ static bool 
interp__builtin_assume_dereferenceable(InterpState &S, CodePtr OpPC,
   assert(Call->getNumArgs() == 2);
 
   APSInt ReqSize = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)));
-  if (ReqSize.getZExtValue() < 1)
-    return false;
-
   const Pointer &Ptr = S.Stk.pop<Pointer>();
-  if (Ptr.isZero() || !Ptr.isLive() || !Ptr.isBlockPointer() || 
Ptr.isPastEnd())
+
+  if (ReqSize.isZero())
+    return true;
+  if (Ptr.isZero()) {
+    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null)
+        << AK_Read << S.Current->getRange(OpPC);
     return false;
+  }
+  if (!Ptr.isLive() || !Ptr.isBlockPointer())
+    return false;
+  if (Ptr.isPastEnd()) {
+    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end)
+        << AK_Read << S.Current->getRange(OpPC);
+    return false;
+  }
 
   const ASTContext &ASTCtx = S.getASTContext();
   const Descriptor *DeclDesc = Ptr.getDeclDesc();
@@ -2194,9 +2204,12 @@ static bool 
interp__builtin_assume_dereferenceable(InterpState &S, CodePtr OpPC,
   if (ByteOffset > *FullSize)
     return false;
 
-  unsigned RemainingSpace = *FullSize - ByteOffset;
-  if (RemainingSpace < ReqSize.getZExtValue())
+  unsigned AvailSize = *FullSize - ByteOffset;
+  if (AvailSize < ReqSize.getZExtValue()) {
+    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end)
+        << AK_Read << S.Current->getRange(OpPC);
     return false;
+  }
 
   return true;
 }
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fe42afe5ddd78..20b28598c4760 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19697,24 +19697,32 @@ class VoidExprEvaluator
       APSInt ReqSizeVal;
       if (!::EvaluateInteger(E->getArg(1), ReqSizeVal, Info))
         return false;
+      if (ReqSizeVal.isZero())
+        return true;
+
       LValue Pointer;
       if (!EvaluatePointer(E->getArg(0), Pointer, Info))
         return false;
       if (Pointer.Designator.Invalid)
         return false;
-      if (Pointer.isNullPointer())
+      if (Pointer.isNullPointer()) {
+        Info.FFDiag(E, diag::note_constexpr_access_null) << AK_Read;
+        return false;
+      }
+      if (Pointer.Designator.isOnePastTheEnd()) {
+        Info.FFDiag(E, diag::note_constexpr_access_past_end) << AK_Read;
         return false;
+      }
 
       uint64_t ReqSize = ReqSizeVal.getZExtValue();
-      if (ReqSize < 1)
-        return false;
       CharUnits EndOffset;
       if (!determineEndOffset(Info, E->getExprLoc(), 0, Pointer, EndOffset))
         return false;
 
-      uint64_t TotalSize =
+      uint64_t AvailSize =
           (EndOffset - Pointer.getLValueOffset()).getQuantity();
-      if (TotalSize < ReqSize) {
+      if (AvailSize < ReqSize) {
+        Info.FFDiag(E, diag::note_constexpr_access_past_end) << AK_Read;
         return false;
       }
       return true;
diff --git a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp 
b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
index 158eb78cbdabc..3819ae3b9c2f0 100644
--- a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
+++ b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
@@ -1,64 +1,92 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -triple 
x86_64-unknown-unknown %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -triple 
x86_64-unknown-unknown %s -fexperimental-new-constant-interpreter
 
-constexpr int arr[10] = {};
-
 constexpr bool test_constexpr_valid() {
+  constexpr int arr[10] = {};
   __builtin_assume_dereferenceable(arr, 40);
   return true;
 }
 static_assert(test_constexpr_valid(), "");
 
 constexpr bool test_constexpr_partial() {
+  constexpr int arr[10] = {};
   __builtin_assume_dereferenceable(&arr[5], 20);
   return true;
 }
 static_assert(test_constexpr_partial(), "");
 
-constexpr bool test_constexpr_nullptr() {
-  __builtin_assume_dereferenceable(nullptr, 4);
+constexpr bool test_constexpr_nullptr() { // expected-error {{constexpr 
function never produces a constant expression}}
+  __builtin_assume_dereferenceable(nullptr, 4); // expected-note 2{{read of 
dereferenced null pointer is not allowed in a constant expression}}
   return true;
 }
-static_assert(test_constexpr_nullptr(), ""); // expected-error {{not an 
integral constant expression}}
+static_assert(test_constexpr_nullptr(), ""); // expected-error {{not an 
integral constant expression}} expected-note {{in call to}}
 
-constexpr bool test_constexpr_too_large() {
-  __builtin_assume_dereferenceable(arr, 100);
+constexpr bool test_constexpr_too_large() { // expected-error {{constexpr 
function never produces a constant expression}}
+  constexpr int arr[10] = {};
+  __builtin_assume_dereferenceable(arr, 100); // expected-note 2{{read of 
dereferenced one-past-the-end pointer is not allowed in a constant expression}}
   return true;
 }
-static_assert(test_constexpr_too_large(), ""); // expected-error {{not an 
integral constant expression}}
+static_assert(test_constexpr_too_large(), ""); // expected-error {{not an 
integral constant expression}} expected-note {{in call to}}
 
-constexpr int single_var = 42;
 constexpr bool test_single_var() {
+  constexpr int single_var = 42;
   __builtin_assume_dereferenceable(&single_var, 4);
   return true;
 }
 static_assert(test_single_var(), "");
 
 constexpr bool test_exact_boundary() {
+  constexpr int arr[10] = {};
   __builtin_assume_dereferenceable(&arr[9], 4);
   return true;
 }
 static_assert(test_exact_boundary(), "");
 
-constexpr bool test_one_over() {
-  __builtin_assume_dereferenceable(&arr[9], 5);
+constexpr bool test_one_over() { // expected-error {{constexpr function never 
produces a constant expression}}
+  constexpr int arr[10] = {};
+  __builtin_assume_dereferenceable(&arr[9], 5); // expected-note 2{{read of 
dereferenced one-past-the-end pointer is not allowed in a constant expression}}
   return true;
 }
-static_assert(test_one_over(), ""); // expected-error {{not an integral 
constant expression}}
+static_assert(test_one_over(), ""); // expected-error {{not an integral 
constant expression}} expected-note {{in call to}}
 
 constexpr bool test_zero_size() {
+  constexpr int arr[10] = {};
   __builtin_assume_dereferenceable(arr, 0);
   return true;
 }
-static_assert(test_zero_size(), ""); // expected-error {{not an integral 
constant expression}}
+static_assert(test_zero_size(), "");
 
-struct S {
-  int x;
-  int y;
-};
-constexpr S s = {1, 2};
 constexpr bool test_struct_member() {
+  struct S {
+    int x;
+    int y;
+  };
+  constexpr S s = {1, 2};
   __builtin_assume_dereferenceable(&s.x, 4);
   return true;
 }
 static_assert(test_struct_member(), "");
+
+constexpr bool test_range_valid() {
+  constexpr int range_data[5] = {1, 2, 3, 4, 5};
+  __builtin_assume_dereferenceable(range_data, 5 * sizeof(int));
+  return range_data[0] == 1;
+}
+static_assert(test_range_valid(), "");
+
+constexpr bool test_range_invalid() { // expected-error {{constexpr function 
never produces a constant expression}}
+  constexpr int range_data[5] = {1, 2, 3, 4, 5};
+  __builtin_assume_dereferenceable(range_data, 6 * sizeof(int)); // 
expected-note 2{{read of dereferenced one-past-the-end pointer is not allowed 
in a constant expression}}
+  return true;
+}
+static_assert(test_range_invalid(), ""); // expected-error {{not an integral 
constant expression}} expected-note {{in call to}}
+
+constexpr int arr1[10] = {};
+constexpr int valid = (__builtin_assume_dereferenceable(arr1, 40), 12);
+
+constexpr int invalid = (__builtin_assume_dereferenceable((int*)123, 4), 12); 
// expected-error {{constexpr variable 'invalid' must be initialized by a 
constant expression}} expected-note {{cast that performs the conversions of a 
reinterpret_cast is not allowed in a constant expression}}
+
+constexpr int arr2[5] = {1, 2, 3, 4, 5};
+constexpr int too_large = (__builtin_assume_dereferenceable(arr2, 6 * 
sizeof(int)), 12); // expected-error {{constexpr variable 'too_large' must be 
initialized by a constant expression}} expected-note {{read of dereferenced 
one-past-the-end pointer is not allowed in a constant expression}}
+
+constexpr int null = (__builtin_assume_dereferenceable(nullptr, 4), 12); // 
expected-error {{constexpr variable 'null' must be initialized by a constant 
expression}} expected-note {{read of dereferenced null pointer is not allowed 
in a constant expression}}

>From 33529fe5049df9a936fb787425e4361a425b5945 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Sat, 29 Nov 2025 13:42:48 -0800
Subject: [PATCH 3/5] Allow casts like (char*)&b + 1 to passthrough for
 non-constexpr const initialization

---
 clang/lib/AST/ByteCode/InterpBuiltin.cpp      |  9 ++++++--
 clang/lib/AST/ExprConstant.cpp                |  5 ++++-
 ...iltin-assume-dereferenceable-constexpr.cpp | 21 +++++++++++++++++++
 3 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 190d8e4e3dda5..9d36bc0082321 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2176,7 +2176,7 @@ static bool 
interp__builtin_assume_dereferenceable(InterpState &S, CodePtr OpPC,
                                                    const CallExpr *Call) {
   assert(Call->getNumArgs() == 2);
 
-  APSInt ReqSize = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)));
+  APSInt ReqSize = popToAPSInt(S, Call->getArg(1));
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
   if (ReqSize.isZero())
@@ -2186,7 +2186,12 @@ static bool 
interp__builtin_assume_dereferenceable(InterpState &S, CodePtr OpPC,
         << AK_Read << S.Current->getRange(OpPC);
     return false;
   }
-  if (!Ptr.isLive() || !Ptr.isBlockPointer())
+  if (!Ptr.isBlockPointer()) {
+    if (Ptr.isIntegralPointer())
+      return true;
+    return false;
+  }
+  if (!Ptr.isLive())
     return false;
   if (Ptr.isPastEnd()) {
     S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 20b28598c4760..9cd50262c1332 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19701,8 +19701,11 @@ class VoidExprEvaluator
         return true;
 
       LValue Pointer;
-      if (!EvaluatePointer(E->getArg(0), Pointer, Info))
+      if (!EvaluatePointer(E->getArg(0), Pointer, Info)) {
+        if (EvaluateBuiltinConstantP(Info, E->getArg(0)))
+          return true;
         return false;
+      }
       if (Pointer.Designator.Invalid)
         return false;
       if (Pointer.isNullPointer()) {
diff --git a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp 
b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
index 3819ae3b9c2f0..6416a9a340195 100644
--- a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
+++ b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
@@ -90,3 +90,24 @@ constexpr int arr2[5] = {1, 2, 3, 4, 5};
 constexpr int too_large = (__builtin_assume_dereferenceable(arr2, 6 * 
sizeof(int)), 12); // expected-error {{constexpr variable 'too_large' must be 
initialized by a constant expression}} expected-note {{read of dereferenced 
one-past-the-end pointer is not allowed in a constant expression}}
 
 constexpr int null = (__builtin_assume_dereferenceable(nullptr, 4), 12); // 
expected-error {{constexpr variable 'null' must be initialized by a constant 
expression}} expected-note {{read of dereferenced null pointer is not allowed 
in a constant expression}}
+
+int b = 10;
+const int f = (__builtin_assume_dereferenceable((char*)&b + 1, 3), 12);
+int a = f;
+
+int c[10] = {};
+const int g = (__builtin_assume_dereferenceable((unsigned char*)c + 5, 35), 
42);
+int d = g;
+
+long long ll = 100;
+const int h = (__builtin_assume_dereferenceable((void*)&ll, 8), 99);
+int e = h;
+
+struct Foo { int x; int y; int z; };
+Foo foo = {1, 2, 3};
+const int i = (__builtin_assume_dereferenceable((short*)&foo + 2, 8), 77);
+int j = i;
+
+double darr[10] = {};
+const int k = (__builtin_assume_dereferenceable((int*)darr, 40), 55);
+int l = k;

>From 1509ebf9a05e4ff22b8679e0ed79f2b9f1a5c7c2 Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Sat, 29 Nov 2025 23:06:27 -0800
Subject: [PATCH 4/5] Add codegen tests to verify constexpr passthrough for
 non-constexpr const initialization

---
 ...iltin-assume-dereferenceable-constexpr.cpp | 50 +++++++++++++++++++
 ...iltin-assume-dereferenceable-constexpr.cpp | 25 +---------
 2 files changed, 52 insertions(+), 23 deletions(-)
 create mode 100644 
clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp

diff --git a/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp 
b/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp
new file mode 100644
index 0000000000000..4747d4c35eedb
--- /dev/null
+++ b/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp
@@ -0,0 +1,50 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --include-generated-funcs
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -emit-llvm -o - 
%s | FileCheck %s
+
+constexpr int b = 10;
+int test_char_cast() {
+  const int f = (__builtin_assume_dereferenceable((char*)&b + 1, 3), 12);
+  return f;
+}
+
+constexpr long long ll = 100;
+int test_void_cast() {
+  const int h = (__builtin_assume_dereferenceable((void*)&ll, 8), 99);
+  return h;
+}
+
+constexpr int gb = 10;
+const int gf = (__builtin_assume_dereferenceable((char*)&gb + 1, 3), 12);
+int ga = gf;
+
+// CHECK-LABEL: test_char_castv
+// CHECK:         [[F:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
getelementptr inbounds (i8, ptr @_ZL1b, i64 1), i64 3) ]
+// CHECK-NEXT:    store i32 12, ptr [[F]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[F]], align 4
+// CHECK-NEXT:    ret i32 [[TMP0]]
+//
+//
+// CHECK-LABEL: test_void_castv
+// CHECK:         [[H:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 99, ptr [[H]], align 4
+// CHECK-NEXT:    ret i32 99
+//
+//
+// CHECK-LABEL: __cxx_global_var_init
+// CHECK:         [[TMP0:%.*]] = load i32, ptr @_ZL2gf, align 4
+// CHECK-NEXT:    store i32 [[TMP0]], ptr @ga, align 4
+// CHECK-NEXT:    ret void
+//
+//
+// CHECK-LABEL: __cxx_global_var_init.1
+// CHECK:         call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
getelementptr inbounds (i8, ptr @_ZL2gb, i64 1), i64 3) ]
+// CHECK-NEXT:    store i32 12, ptr @_ZL2gf, align 4
+// CHECK-NEXT:    ret void
+//
+//
+// CHECK-LABEL: _GLOBAL__sub_I_builtin_assume_dereferenceable_constexpr.cpp
+// CHECK:         call void @__cxx_global_var_init.1()
+// CHECK-NEXT:    call void @__cxx_global_var_init()
+// CHECK-NEXT:    ret void
+//
diff --git a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp 
b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
index 6416a9a340195..8a59f95b6e9dd 100644
--- a/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
+++ b/clang/test/SemaCXX/builtin-assume-dereferenceable-constexpr.cpp
@@ -58,8 +58,8 @@ static_assert(test_zero_size(), "");
 
 constexpr bool test_struct_member() {
   struct S {
-    int x;
-    int y;
+  int x;
+  int y;
   };
   constexpr S s = {1, 2};
   __builtin_assume_dereferenceable(&s.x, 4);
@@ -90,24 +90,3 @@ constexpr int arr2[5] = {1, 2, 3, 4, 5};
 constexpr int too_large = (__builtin_assume_dereferenceable(arr2, 6 * 
sizeof(int)), 12); // expected-error {{constexpr variable 'too_large' must be 
initialized by a constant expression}} expected-note {{read of dereferenced 
one-past-the-end pointer is not allowed in a constant expression}}
 
 constexpr int null = (__builtin_assume_dereferenceable(nullptr, 4), 12); // 
expected-error {{constexpr variable 'null' must be initialized by a constant 
expression}} expected-note {{read of dereferenced null pointer is not allowed 
in a constant expression}}
-
-int b = 10;
-const int f = (__builtin_assume_dereferenceable((char*)&b + 1, 3), 12);
-int a = f;
-
-int c[10] = {};
-const int g = (__builtin_assume_dereferenceable((unsigned char*)c + 5, 35), 
42);
-int d = g;
-
-long long ll = 100;
-const int h = (__builtin_assume_dereferenceable((void*)&ll, 8), 99);
-int e = h;
-
-struct Foo { int x; int y; int z; };
-Foo foo = {1, 2, 3};
-const int i = (__builtin_assume_dereferenceable((short*)&foo + 2, 8), 77);
-int j = i;
-
-double darr[10] = {};
-const int k = (__builtin_assume_dereferenceable((int*)darr, 40), 55);
-int l = k;

>From 9b4d9a0e15f63b30bb5e76dbdb66caea7799ba4b Mon Sep 17 00:00:00 2001
From: NagaChaitanya Vellanki <[email protected]>
Date: Sun, 30 Nov 2025 14:06:36 -0800
Subject: [PATCH 5/5] Update CodeGen tests for constexpr and global
 initialization scenarios

---
 ...iltin-assume-dereferenceable-constexpr.cpp | 80 ++++++++++---------
 1 file changed, 43 insertions(+), 37 deletions(-)

diff --git a/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp 
b/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp
index 4747d4c35eedb..88e562e31ed26 100644
--- a/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp
+++ b/clang/test/CodeGenCXX/builtin-assume-dereferenceable-constexpr.cpp
@@ -1,50 +1,56 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --include-generated-funcs
 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++14 -emit-llvm -o - 
%s | FileCheck %s
 
-constexpr int b = 10;
-int test_char_cast() {
-  const int f = (__builtin_assume_dereferenceable((char*)&b + 1, 3), 12);
-  return f;
+int b = 10;
+const int f = (__builtin_assume_dereferenceable((char*)&b + 1, 3), 12);
+int use_f = f;
+
+constexpr int g = 20;
+const int h = (__builtin_assume_dereferenceable((char*)&g + 1, 2), 42);
+int use_h = h;
+
+constexpr char arr[] = "hello";
+constexpr const char* ptr = arr + 1;
+constexpr int fully_constexpr() {
+  __builtin_assume_dereferenceable(ptr, 2);
+  return 100;
 }
+constexpr int i = fully_constexpr();
+int use_i = i;
 
-constexpr long long ll = 100;
-int test_void_cast() {
-  const int h = (__builtin_assume_dereferenceable((void*)&ll, 8), 99);
-  return h;
+void test_integral_ptr() {
+  __builtin_assume_dereferenceable((int*)0x1234, 4);
 }
 
-constexpr int gb = 10;
-const int gf = (__builtin_assume_dereferenceable((char*)&gb + 1, 3), 12);
-int ga = gf;
+void test_nullptr() {
+  __builtin_assume_dereferenceable(nullptr, 0);
+}
 
-// CHECK-LABEL: test_char_castv
-// CHECK:         [[F:%.*]] = alloca i32, align 4
-// CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
getelementptr inbounds (i8, ptr @_ZL1b, i64 1), i64 3) ]
-// CHECK-NEXT:    store i32 12, ptr [[F]], align 4
-// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[F]], align 4
-// CHECK-NEXT:    ret i32 [[TMP0]]
-//
-//
-// CHECK-LABEL: test_void_castv
-// CHECK:         [[H:%.*]] = alloca i32, align 4
-// CHECK-NEXT:    store i32 99, ptr [[H]], align 4
-// CHECK-NEXT:    ret i32 99
-//
+void test_zero_size() {
+  int x = 10;
+  __builtin_assume_dereferenceable(&x, 0);
+}
+
+void test_function_ptr() {
+  __builtin_assume_dereferenceable((void*)&test_zero_size, 8);
+}
+
+// CHECK: @use_i = global i32 100
 //
-// CHECK-LABEL: __cxx_global_var_init
-// CHECK:         [[TMP0:%.*]] = load i32, ptr @_ZL2gf, align 4
-// CHECK-NEXT:    store i32 [[TMP0]], ptr @ga, align 4
-// CHECK-NEXT:    ret void
+// CHECK: @{{_Z[0-9]+}}test_integral_ptrv
+// CHECK: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr inttoptr 
(i64 4660 to ptr), i64 4) ]
 //
+// CHECK: @{{_Z[0-9]+}}test_nullptrv
+// CHECK: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr null, i64 0) 
]
 //
-// CHECK-LABEL: __cxx_global_var_init.1
-// CHECK:         call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
getelementptr inbounds (i8, ptr @_ZL2gb, i64 1), i64 3) ]
-// CHECK-NEXT:    store i32 12, ptr @_ZL2gf, align 4
-// CHECK-NEXT:    ret void
+// CHECK: @{{_Z[0-9]+}}test_zero_sizev
+// CHECK: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr {{%.*}}, i64 
0) ]
 //
+// CHECK: @{{_Z[0-9]+}}test_function_ptrv
+// CHECK: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
@{{_Z[0-9]+}}test_zero_sizev, i64 8) ]
 //
-// CHECK-LABEL: _GLOBAL__sub_I_builtin_assume_dereferenceable_constexpr.cpp
-// CHECK:         call void @__cxx_global_var_init.1()
-// CHECK-NEXT:    call void @__cxx_global_var_init()
-// CHECK-NEXT:    ret void
+// CHECK: __cxx_global_var_init
+// CHECK: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
getelementptr inbounds (i8, ptr @b, i64 1), i64 3) ]
 //
+// CHECK: __cxx_global_var_init
+// CHECK: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr 
getelementptr inbounds (i8, ptr @{{_ZL[0-9]+}}g, i64 1), i64 2) ]
+// CHECK: store i32 42, ptr @{{_ZL[0-9]+}}h

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

Reply via email to