[clang] [clang][CodeGen] Emit file-scope compound literals in a constant context (PR #221390)

Akash Manna via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 16 20:50:49 PDT 2026


================
@@ -7541,18 +7541,55 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
   //  "If the compound literal occurs outside the body of a function, the
   //  initializer list shall consist of constant expressions."
   if (IsFileScope)
-    if (auto ILE = dyn_cast<InitListExpr>(LiteralExpr))
+    if (auto ILE = dyn_cast<InitListExpr>(LiteralExpr)) {
+      // A default argument or default member initializer containing an
+      // immediate call or source_location is rebuilt at each use site, where
+      // its elements are evaluated (see BuildCXXDefaultArgExpr).
+      bool InDefaultArgOrInit =
+          isCheckingDefaultArgumentOrInitializer() ||
+          InnermostDeclarationWithDelayedImmediateInvocations().has_value();
       for (unsigned i = 0, j = ILE->getNumInits(); i != j; i++) {
         Expr *Init = ILE->getInit(i);
-        if (!Init->isTypeDependent() && !Init->isValueDependent() &&
-            !Init->isConstantInitializer(Context)) {
+        // An immediate invocation is already a ConstantExpr and receives its
+        // value at the end of the full-expression.
+        if (isa<ConstantExpr>(Init))
+          continue;
+        if (Init->isTypeDependent() || Init->isValueDependent()) {
+          ILE->setInit(i, ConstantExpr::Create(Context, Init));
+          continue;
+        }
+        // Only a reference member is initialized by a glvalue.
+        bool IsRef = Init->isGLValue();
+        if (!Init->isConstantInitializer(Context, IsRef)) {
----------------
akash-manna-sky wrote:

Tried it and it works out well. The per-element `isConstantInitializer` call is gone; an element is accepted when its constant-context evaluation succeeds without side effects, keeping the old tolerance for folded UB like signed overflow. Deferred elements are still evaluated for validity, just not stored. Each element is now evaluated once instead of twice, and the only behavior change is that `(RR[1]){1}` with an `int&&` member, the last case in the FIXME crash test, now gets "not a compile-time constant" instead of crashing CodeGen, matching how `(RT){1}` is already rejected. Test converted accordingly. The whole-literal check below still uses `isConstantInitializer` for non-list initializers.


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


More information about the cfe-commits mailing list