Skip to content

Clang crashes and mis-handles aggregate initialization with base initializers in certain cases #80510

@rnk

Description

@rnk

I've identified a few loops over InitListExprs for records that don't account for the changes in C++17 which allowed base initializers to appear in an aggregate initialization expression, namely here and here:

for (const auto *Field : RD->fields()) {

https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/CGExprConstant.cpp#L696

The first case represents an actual bug, since it means we don't check the remaining initializer list expressions, as in this example:

struct Empty {};
struct Foo : Empty {
  int x;
  int y;
};
int f();
Foo o = (Foo){{}, 1, f()};

Clang accepts this, but if you remove the Empty base and its initializer, it rejects it:

struct Foo  {
  int x;
  int y;
};
int f();
Foo o = (Foo){1, f()};

-->

t.cpp:9:19: error: initializer element is not a compile-time constant
    9 | Foo o = (Foo){1, f()};
      |                   ^~~
1 error generated.

Something is not right, and the dumped AST doesn't look right, it classifies f() as a ConstantExpr:

`-VarDecl 0x55c70d2d2190 <line:7:1, col:25> col:5 o 'Foo' cinit
  `-CompoundLiteralExpr 0x55c70d2d25c8 <col:9, col:25> 'Foo'
    `-InitListExpr 0x55c70d2d2390 <col:14, col:25> 'Foo'
      |-ConstantExpr 0x55c70d2d2580 <col:15, col:16> 'Empty'
      | `-InitListExpr 0x55c70d2d23e8 <col:15, col:16> 'Empty'
      |-ConstantExpr 0x55c70d2d2598 <col:19> 'int'
      | `-IntegerLiteral 0x55c70d2d2248 <col:19> 'int' 1
      `-ConstantExpr 0x55c70d2d25b0 <col:22, col:24> 'int'
        `-CallExpr 0x55c70d2d2318 <col:22, col:24> 'int'
          `-ImplicitCastExpr 0x55c70d2d2300 <col:22> 'int (*)()' <FunctionToPointerDecay>
            `-DeclRefExpr 0x55c70d2d22b0 <col:22> 'int ()' lvalue Function 0x55c70d2d2058 'f' 'int ()'

In this larger test case, this misclassification of this initializer as a constant ultimately results in a crash during codegen:

struct Empty {};
struct Foo : Empty {
  int x;
  int y;
};
int getint();
struct Span {
  Span(const Foo (&p)[1]);
};
Span defs = (Foo[1]){{.x = 0, getint()}};

-->

clang: ../clang/lib/CodeGen/CGExprConstant.cpp:932: ConstantAddress (anonymous namespace)::tryEmitGlobalCompoundLiteral(ConstantEmitter &, const CompoundLiteralExpr *): Assertion `!E->isFileScope() && "f
ile-scope compound literal did not have constant initializer!"' failed.                                                                                                                                    
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:                                                                                                                                                                                                
...
 #9 0x0000555717168e8e /b/f/w/set_by_reclient/a/../clang/lib/CodeGen/CGExprConstant.cpp:931:5
#10 0x0000555717168a75 clang::CodeGen::CodeGenModule::GetAddrOfConstantCompoundLiteral(clang::CompoundLiteralExpr const*) /b/f/w/set_by_reclient/a/../clang/lib/CodeGen/CGExprConstant.cpp:2243:1     
#11 0x0000555717127b31 clang::CodeGen::CodeGenFunction::EmitCompoundLiteralLValue(clang::CompoundLiteralExpr const*) /b/f/w/set_by_reclient/a/../clang/lib/CodeGen/CGExpr.cpp:4945:27                      
#12 0x0000555717122c19 clang::CodeGen::CodeGenFunction::EmitLValueHelper(clang::Expr const*, clang::CodeGen::KnownNonNull_t) /b/f/w/set_by_reclient/a/../clang/lib/CodeGen/CGExpr.cpp:0:12
...

I believe the solution is to update isConstantInitializer to iterate over bases and not just fields, but that may uncover more issues.

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:codegenIR generation bugs: mangling, exceptions, etc.crashPrefer [crash-on-valid] or [crash-on-invalid]

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions