[clang] Fix __builtin_object_size calculation for references of unknown origin in C++23 (PR #157778)

via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 9 18:57:44 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Akira Hatanaka (ahatanak)

<details>
<summary>Changes</summary>

This addresses an issue introduced by 0a9c08c59ba61e727e9dee6d71883d9106963442, which implemented P2280R4.

This fixes the issue reported in
https://github.com/llvm/llvm-project/pull/95474#issuecomment-3025887023.

rdar://149897839

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


2 Files Affected:

- (modified) clang/lib/AST/ExprConstant.cpp (+15-1) 
- (added) clang/test/Sema/builtin-object-size.cpp (+48) 


``````````diff
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 2376e482a19f5..229211c4f2cb7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13279,6 +13279,9 @@ static bool refersToCompleteObject(const LValue &LVal) {
   if (LVal.Designator.Invalid)
     return false;
 
+  if (LVal.AllowConstexprUnknown)
+    return false;
+
   if (!LVal.Designator.Entries.empty())
     return LVal.Designator.isMostDerivedAnUnsizedArray();
 
@@ -13328,7 +13331,7 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) {
     return false;
   };
 
-  return LVal.InvalidBase &&
+  return (LVal.InvalidBase || LVal.AllowConstexprUnknown) &&
          Designator.Entries.size() == Designator.MostDerivedPathLength &&
          Designator.MostDerivedIsArrayElement && isFlexibleArrayMember() &&
          isDesignatorAtObjectEnd(Ctx, LVal);
@@ -13396,6 +13399,17 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc,
     if (LVal.InvalidBase)
       return false;
 
+    // We cannot deterimine the end offset of the enitre object if this is an
+    // unknown reference.
+    if (Type == 0 && LVal.AllowConstexprUnknown)
+      return false;
+
+    // We cannot deterimine the end offset of the subobject if this is an
+    // unknown reference and the subobject designator is invalid (e.g., unsized
+    // array designator).
+    if (Type == 1 && LVal.Designator.Invalid && LVal.AllowConstexprUnknown)
+      return false;
+
     QualType BaseTy = getObjectType(LVal.getLValueBase());
     const bool Ret = CheckedHandleSizeof(BaseTy, EndOffset);
     addFlexibleArrayMemberInitSize(Info, BaseTy, LVal, EndOffset);
diff --git a/clang/test/Sema/builtin-object-size.cpp b/clang/test/Sema/builtin-object-size.cpp
new file mode 100644
index 0000000000000..3995e1880ec81
--- /dev/null
+++ b/clang/test/Sema/builtin-object-size.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fstrict-flex-arrays=0 -DSTRICT0 -std=c++23 -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fstrict-flex-arrays=1 -DSTRICT1 -std=c++23 -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fstrict-flex-arrays=2 -DSTRICT2 -std=c++23 -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -fstrict-flex-arrays=3 -DSTRICT3 -std=c++23 -verify %s
+
+struct EmptyS {
+  int i;
+  char a[];
+};
+
+template <unsigned N>
+struct S {
+  int i;
+  char a[N];
+};
+
+extern S<2> &s2;
+static_assert(__builtin_object_size(s2.a, 0)); // expected-error {{static assertion expression is not an integral constant expression}}
+static_assert(__builtin_object_size(s2.a, 1) == 2);
+#if defined(STRICT0)
+// expected-error at -2 {{static assertion expression is not an integral constant expression}}
+#endif
+static_assert(__builtin_object_size(s2.a, 2) == 4);
+static_assert(__builtin_object_size(s2.a, 3) == 2);
+
+extern S<1> &s1;
+static_assert(__builtin_object_size(s1.a, 0)); // expected-error {{static assertion expression is not an integral constant expression}}
+static_assert(__builtin_object_size(s1.a, 1) == 1);
+#if defined(STRICT0) || defined(STRICT1)
+// expected-error at -2 {{static assertion expression is not an integral constant expression}}
+#endif
+static_assert(__builtin_object_size(s1.a, 2) == 4);
+static_assert(__builtin_object_size(s1.a, 3) == 1);
+
+extern S<0> &s0;
+static_assert(__builtin_object_size(s0.a, 0)); // expected-error {{static assertion expression is not an integral constant expression}}
+static_assert(__builtin_object_size(s0.a, 1) == 0);
+#if defined(STRICT0) || defined(STRICT1) || defined(STRICT2)
+// expected-error at -2 {{static assertion expression is not an integral constant expression}}
+#endif
+static_assert(__builtin_object_size(s0.a, 2) == 0);
+static_assert(__builtin_object_size(s0.a, 3) == 0);
+
+extern EmptyS ∅
+static_assert(__builtin_object_size(empty.a, 0)); // expected-error {{static assertion expression is not an integral constant expression}}
+static_assert(__builtin_object_size(empty.a, 1)); // expected-error {{static assertion expression is not an integral constant expression}}
+static_assert(__builtin_object_size(empty.a, 2) == 0);
+static_assert(__builtin_object_size(empty.a, 3)); // expected-error {{static assertion expression is not an integral constant expression}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/157778


More information about the cfe-commits mailing list