Skip to content

[clang][Sema] Fixed Compound Literal is not Constant Expression #143852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

Mr-Anyone
Copy link
Contributor

Added a check for a compound literal hiding inside a function.

fixes #87867

Added a check for a compound literal hiding inside a function.

fixes llvm#87867
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 12, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 12, 2025

@llvm/pr-subscribers-clang

Author: Vincent (Mr-Anyone)

Changes

Added a check for a compound literal hiding inside a function.

fixes #87867


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

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+12)
  • (added) clang/test/Sema/gh87867.c (+33)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b42d5f8425af6..df1963f19e35f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -680,6 +680,8 @@ Bug Fixes in This Version
   ``#include`` directive. (#GH138094)
 - Fixed a crash during constant evaluation involving invalid lambda captures
   (#GH138832)
+- Fixed compound literal is not constant expression inside initializer list 
+  (#GH87867)
 - Fixed a crash when instantiating an invalid dependent friend template specialization.
   (#GH139052)
 - Fixed a crash with an invalid member function parameter list with a default
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index c7abbbd6993de..5468d6573b4bb 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7219,6 +7219,17 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty,
   return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, InitExpr);
 }
 
+static bool IsInsideFunction(Scope *S) {
+  while (S) {
+    if (S->isFunctionScope())
+      return true;
+
+    S = S->getParent();
+  }
+
+  return false;
+}
+
 ExprResult
 Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
                                SourceLocation RParenLoc, Expr *LiteralExpr) {
@@ -7281,6 +7292,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
   //   void func(char *para[(int [1]){ 0 }[0]);
   const Scope *S = getCurScope();
   bool IsFileScope = !CurContext->isFunctionOrMethod() &&
+                     !IsInsideFunction(getCurScope()) &&
                      (!S || !S->isFunctionPrototypeScope());
 
   // In C, compound literals are l-values for some reason.
diff --git a/clang/test/Sema/gh87867.c b/clang/test/Sema/gh87867.c
new file mode 100644
index 0000000000000..0568c734424ca
--- /dev/null
+++ b/clang/test/Sema/gh87867.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s
+
+// Compound literal doesn't need a constant expression inside a initializer-list if it is already inside a function 
+// see: https://github.com/llvm/llvm-project/issues/87867
+int foo(int *a, int b) {
+    return 0;
+}
+
+int x;
+struct{int t;} a = (struct {
+    typeof(foo(&(struct { int t; }){.t = x}.t, 0)) t; // expected-error {{initializer element is not a compile-time constant}}
+}){0};
+
+void inside_a_func(){
+    int x;
+    (void)(struct {
+        typeof(foo(&(struct { int t; }){.t = x}.t, 0)) t;
+    }){0};
+}
+
+// see: https://github.com/llvm/llvm-project/issues/143613
+#define bitcast(type, value) \
+    (((union{ typeof(value) src; type dst; }){ (value) }).dst)
+
+double placeholder = 10.0;
+double bar = bitcast(double, placeholder);  // expected-error {{initializer element is not a compile-time constant}}
+
+int main(void)
+{
+    int foo = 4;
+    foo = bitcast(int, bitcast(double, foo));
+    return 0;
+}

@Sirraide Sirraide requested a review from AaronBallman June 12, 2025 09:43
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM aside from a nit, thank you for working on this!

@@ -7219,6 +7219,17 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty,
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, InitExpr);
}

static bool IsInsideFunction(Scope *S) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static bool IsInsideFunction(Scope *S) {
static bool IsContainedByFunctionScope(const Scope *S) {

makes it more clear that we're checking whether the given scope is itself somewhere within a function scope.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AaronBallman it feels like it makes sense to sink this into Scope just like isInObjCMethodScope()

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can go either way. This is currently the first time we've needed this, so a static function makes sense. But if we need this a second time, then absolutely agreed it should be hoisted into Scope. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do see people using this from time to time. I just moved this logic into Scope.

Copy link

github-actions bot commented Jun 16, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@Mr-Anyone Mr-Anyone requested a review from AaronBallman June 16, 2025 13:58
@Mr-Anyone Mr-Anyone force-pushed the compound_literal_is_not_constant_expression_fix branch from 8dd64c3 to cc509b9 Compare June 16, 2025 14:00
@Mr-Anyone Mr-Anyone requested a review from shafik June 16, 2025 14:00
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Mr-Anyone
Copy link
Contributor Author

@AaronBallman I don't have merge access. Could you please merge this for me? Thanks.

@AaronBallman AaronBallman merged commit 977d8a4 into llvm:main Jun 17, 2025
8 checks passed
@AaronBallman
Copy link
Collaborator

@AaronBallman I don't have merge access. Could you please merge this for me? Thanks.

Absolutely, thank you for letting me know. :-)

ajaden-codes pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 17, 2025
…#143852)

Added a check for a compound literal hiding inside a function.

fixes llvm#87867
fschlimb pushed a commit to fschlimb/llvm-project that referenced this pull request Jun 18, 2025
…#143852)

Added a check for a compound literal hiding inside a function.

fixes llvm#87867
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

getting: "error: initializer element is not a compile-time constant" Even when struct is inside function
4 participants