llvm / llvm/llvm-project

[Clang] ICE in AggExprEmitter::VisitCXXParenListOrInitListExpr when aggregate-initializing array-of-aggregates member in template class constructor

Open
#189,005 5 comments 0 reactions 0 assignees View on GitHub
clang:codegen crash
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Clang crashes (segfault) during codegen when a template class constructor uses parenthesized aggregate initialization (C++20, P0960) in its member initializer list to initialize a struct member containing an array of aggregates.

Reproducer
```cpp
struct Inner { int x; };
struct Outer { Inner arr[2]; };

template
struct S {
S() : m({{1}, {2}}) {}
Outer m;
};

template struct S;
```
```bash
$ clang++ -std=c++20 -c repro.cpp
```

https://godbolt.org/z/f7o3vn6vT

Crashes at all optimization levels (-O0 through -O3) and all C++20+ standard modes (-std=c++20, -std=c++23, -std=c++2c).

Conditions

All of the following must be true to trigger the crash:

1. The containing class is a template (non-template classes compile fine)
2. The member is a struct containing a C-array of aggregates (e.g. struct { Inner arr[N]; })
3. The initialization uses parenthesized aggregate init in a member initializer list

Also reproduces with `std::array, N>` (which wraps a C-array of pair aggregates):
```cpp
#include
#include

template
struct S {
S() : a({{1, 2}}) {}
std::array, 1> a;
};

template struct S;
```

Does not crash when

- The class is not a template
- The member is initialized via explicit constructor call (e.g. `m(Outer{Inner{1}, Inner{2}})`)
- The initialization is a default member initializer instead of a mem-initializer-list
- The inner aggregate type is replaced with a scalar

Stack trace

```
#0 llvm::sys::PrintStackTrace(...)
#1 llvm::sys::RunSignalHandlers()
#2 CrashRecoverySignalHandler(int)
#3 __restore_rt
#4 clang::TagDecl::getDefinition() const
#5 (anonymous namespace)::AggExprEmitter::VisitCXXParenListOrInitListExpr(...) CGExprAgg.cpp
#6 clang::CodeGen::CodeGenFunction::EmitAggExpr(...)
#7 (anonymous namespace)::AggExprEmitter::VisitCXXParenListOrInitListExpr(...) CGExprAgg.cpp
#8 clang::CodeGen::CodeGenFunction::EmitAggExpr(...)
#9 clang::CodeGen::CodeGenFunction::EmitInitializerForField(...)
#10 EmitMemberInitializer(...) CGClass.cpp
#11 clang::CodeGen::CodeGenFunction::EmitCtorPrologue(...)
#12 clang::CodeGen::CodeGenFunction::EmitConstructorBody(...)
#13 clang::CodeGen::CodeGenFunction::GenerateCode(...)
```

Version

clang version 22.1.2
Target: x86_64-unknown-linux-gnu

Contributor guide

Open the contributing guide

Research direction

Start in CGExprAgg.cpp at AggExprEmitter::VisitCXXParenListOrInitListExpr and reproduce the crash with the supplied C++20 template example using clang++ -std=c++20 -c repro.cpp. Trace how the aggregate member initializer is handled during constructor code generation. Done means the reproducer and equivalent std::array case compile without a crash across the affected standard modes and optimization levels.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.