llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Fixes #<!-- -->212106

A file-scope compound literal is always a constant-initialized global, and Sema 
checks its initializer in a constant context, where `__builtin_constant_p` of 
something it can't fold just yields 0. CodeGen evaluated the same initializer 
under whatever context the *caller* was in. When the literal's address is taken 
by a global that needs dynamic initialization, that context is non-constant, 
`__builtin_constant_p` refuses to fold, and `tryEmitGlobalCompoundLiteral` 
asserts. The strict-FP variant of this was fixed in D131555 by propagating the 
caller's context, which didn't cover this entry point.

The literal's constant-ness is a property of the literal, not of whoever asks 
for its address, so `tryEmitGlobalCompoundLiteral` now sets the constant 
context itself for any file-scope literal. That covers both callers and keeps 
the assertion in place. The same two lines are mirrored in CIR, which has the 
identical check.

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


5 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+4) 
- (modified) clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp (+6) 
- (modified) clang/lib/CodeGen/CGExprConstant.cpp (+6) 
- (modified) clang/test/AST/static-compound-literals-crash.cpp (+2-10) 
- (added) clang/test/CodeGenCXX/GH212106.cpp (+49) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 042d7112dbe7d..18de7e72abef4 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -652,6 +652,10 @@ features cannot lower the translation-unit ABI level;
 - Fixed a crash when generating fake uses for parameters of bodyless 
destructors with `-fextend-variable-liveness`.
 - Fixed an assertion failure when instantiating a block that captures
   `this` via a member access through a dependent base class.
+- Fixed an assertion failure when the dynamic initializer of a global variable
+  takes the address of a file-scope compound literal whose initializer is only
+  constant under constant-evaluation rules, such as `__builtin_constant_p` of a
+  non-constant expression. (#GH212106)
 
 ### OpenACC Specific Changes
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 4bebe053f5768..d036d73388100 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -941,6 +941,12 @@ tryEmitGlobalCompoundLiteral(ConstantEmitter &emitter,
   if (cir::GlobalOp addr = cgm.getAddrOfConstantCompoundLiteralIfEmitted(e))
     return builder.getGlobalViewAttr(addr);
 
+  // A file-scope compound literal is a constant-initialized global, so emit
+  // its initializer under constant-evaluation rules even when reached from a
+  // non-constant context.
+  if (e->isFileScope())
+    emitter.setInConstantContext(true);
+
   assert(!cir::MissingFeatures::addressSpace());
   mlir::Attribute c =
       emitter.tryEmitForInitializer(e->getInitializer(), e->getType());
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp 
b/clang/lib/CodeGen/CGExprConstant.cpp
index 48e80910ce577..cf2a4ff18cea6 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1087,6 +1087,12 @@ tryEmitGlobalCompoundLiteral(ConstantEmitter &emitter,
           CGM.getAddrOfConstantCompoundLiteralIfEmitted(E))
     return ConstantAddress(Addr, Addr->getValueType(), Align);
 
+  // A file-scope compound literal is a constant-initialized global, so emit
+  // its initializer under constant-evaluation rules even when reached from a
+  // non-constant context such as the dynamic initializer of another global.
+  if (E->isFileScope())
+    emitter.setInConstantContext(true);
+
   LangAS addressSpace = E->getType().getAddressSpace();
   llvm::Constant *C = emitter.tryEmitForInitializer(E->getInitializer(),
                                                     addressSpace, 
E->getType());
diff --git a/clang/test/AST/static-compound-literals-crash.cpp 
b/clang/test/AST/static-compound-literals-crash.cpp
index f9c3bd82fd025..838d67b2f3f17 100644
--- a/clang/test/AST/static-compound-literals-crash.cpp
+++ b/clang/test/AST/static-compound-literals-crash.cpp
@@ -1,5 +1,5 @@
-// FIXME: These test cases currently crash during codegen, despite initializers
-// for CLEs being constant.
+// FIXME: This test case currently crashes during codegen, despite the
+// initializer for the CLE being constant.
 // RUN: not --crash %clang_cc1 -verify -std=c++20 -emit-llvm %s -o -
 // expected-no-diagnostics
 namespace case1 {
@@ -7,11 +7,3 @@ struct RR { int&& r; };
 struct Z { RR* x; };
 constinit Z z = { (RR[1]){1} };
 }
-
-
-namespace case2 {
-struct RR { int r; };
-struct Z { int x; const RR* y; int z; };
-inline int f() { return 0; }
-Z z2 = { 10, (const RR[1]){__builtin_constant_p(z2.x)}, z2.y->r+f() };
-}
diff --git a/clang/test/CodeGenCXX/GH212106.cpp 
b/clang/test/CodeGenCXX/GH212106.cpp
new file mode 100644
index 0000000000000..dfdf5dd96924d
--- /dev/null
+++ b/clang/test/CodeGenCXX/GH212106.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -emit-llvm -o - 
%s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 
-ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s
+
+// A file-scope compound literal is a constant-initialized global even when its
+// address is taken from a non-constant context, so its initializer must be
+// emitted under constant-evaluation rules.
+
+struct RR { int r; };
+struct Z { int x; const RR* y; int z; };
+inline int f() { return 0; }
+Z z2 = { 10, (const RR[1]){__builtin_constant_p(z2.x)}, z2.y->r+f() };
+
+// CHECK-DAG: @z2 = {{.*}}global %struct.Z zeroinitializer
+// CHECK-DAG: [[Z2CL:@.compoundliteral(\.[0-9]+)?]] = internal constant [1 x 
%struct.RR] zeroinitializer
+
+namespace reduced {
+struct Z { const int* y; int z; };
+int f();
+Z z2 = { (int[1]){__builtin_constant_p(z2.z)}, f() };
+}
+
+// CHECK-DAG: @_ZN7reduced2z2E = {{.*}}global %"struct.reduced::Z" 
zeroinitializer
+// CHECK-DAG: @.compoundliteral{{(\.[0-9]+)?}} = internal global [1 x i32] 
zeroinitializer
+
+struct F { int a; const float *fp; };
+int g();
+F fl = { g(), (float[1]){0.1} };
+
+// CHECK-DAG: @fl = {{.*}}global %struct.F zeroinitializer
+// CHECK-DAG: @.compoundliteral{{(\.[0-9]+)?}} = internal global [1 x float] 
[float 1.000000e-01]
+
+const RR *p = (const RR[1]){__builtin_constant_p(1)};
+
+// CHECK-DAG: @.compoundliteral{{(\.[0-9]+)?}} = internal constant [1 x 
%struct.RR] [%struct.RR { i32 1 }]
+// CHECK-DAG: @p = {{.*}}global ptr @.compoundliteral{{(\.[0-9]+)?}}
+
+// A default member initializer at namespace scope is also a file-scope 
compound
+// literal, reached here from a constructor emitted for a local variable.
+extern int n;
+struct Q { const int *m = (const int[1]){__builtin_constant_p(n)}; };
+void h() { Q q; }
+
+// CHECK-DAG: [[QCL:@.compoundliteral(\.[0-9]+)?]] = internal constant [1 x 
i32] zeroinitializer
+
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
+// CHECK: store ptr [[Z2CL]], ptr getelementptr inbounds{{.*}}(i8, ptr @z2, 
i64 8)
+
+// CHECK-LABEL: define {{.*}}void @_ZN1QC2Ev(
+// CHECK: store ptr [[QCL]], ptr

``````````

</details>


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

Reply via email to