Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.

while (S) {
if (S->isFunctionScope())
return true;

S = S->getParent();
}

return false;
}

ExprResult
Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
SourceLocation RParenLoc, Expr *LiteralExpr) {
Expand Down Expand Up @@ -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.
Expand Down
33 changes: 33 additions & 0 deletions clang/test/Sema/gh87867.c
Original file line number Diff line number Diff line change
@@ -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;
}
Loading