Commit 5ce254e
committed
[CIR] Fix assertion failure in CIRGenRecordLayout for Empty Base Optimization
This patch fixes a critical assertion failure that occurred when accessing
fields in records that use Empty Base Optimization (EBO), particularly
affecting std::unique_ptr, std::shared_ptr, and other standard library types.
**Problem:**
When processing classes with empty member types combined with inheriting
constructors, CIRGenRecordLayout::getCIRFieldNo() would assert with:
"Assertion `FieldInfo.count(FD) && \"Invalid field for record!\"' failed"
This occurred because EBO transforms empty-type members into base classes
rather than fields, so they don't exist in the FieldInfo map. The bug was
triggered by the combination of three conditions:
1. A member with an empty struct type (e.g., std::default_delete<T>)
2. Inheriting constructors (using Base::Base)
3. Instantiation of the inherited constructor
**Root Cause:**
std::unique_ptr internally uses std::tuple<T*, default_delete<T>>, where
default_delete is an empty struct. When std::tuple applies EBO, the empty
deleter is stored as a base class instead of a member field. During code
generation for constructors, CIR tried to initialize this "field" but it
didn't exist in the FieldInfo map, causing an assertion failure.
**Solution:**
Following the traditional CodeGen pattern from clang/lib/CodeGen, this patch:
1. Adds containsFieldDecl() method to CIRGenRecordLayout (matching
CGRecordLayout::containsFieldDecl) to check if a field exists in the
layout before attempting to access it.
2. Adds guard checks before getCIRFieldNo() calls in:
- CIRGenExpr.cpp::emitLValueForField() - handles field access
- CIRGenExpr.cpp::emitLValueForFieldInitialization() - handles
initialization of reference fields
- CIRGenExprConst.cpp::emitNullConstant() - handles null initialization
- CIRGenExpr.cpp::emitAddrOfFieldStorage() - removes redundant call
3. When a field doesn't exist in the layout (EBO case), returns appropriate
fallback values instead of asserting.
**Impact:**
This fix enables the following previously-broken STL types:
- std::unique_ptr<T>
- std::shared_ptr<T>
- std::function<Sig>
- std::array<T, N>
- std::any
- std::thread
**Testing:**
Added clang/test/CIR/CodeGen/ebo-tuple.cpp which tests the specific
scenario that triggered this bug: empty member types with inheriting
constructors.
Verified with:
- Minimal 24-line reproduction case
- std::unique_ptr<int> default construction
- std::shared_ptr<int> default construction
This implementation strictly follows the traditional CodeGen approach from
clang/lib/CodeGen/CGRecordLayout.h and clang/lib/CodeGen/CGExpr.cpp to
maintain consistency with LLVM CodeGen.
ghstack-source-id: f433d7e
Pull-Request: #19991 parent 4bcc825 commit 5ce254e
File tree
4 files changed
+79
-2
lines changed- clang
- lib/CIR/CodeGen
- test/CIR/CodeGen
4 files changed
+79
-2
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
92 | 91 | | |
93 | | - | |
| 92 | + | |
94 | 93 | | |
95 | 94 | | |
96 | 95 | | |
| |||
389 | 388 | | |
390 | 389 | | |
391 | 390 | | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
392 | 400 | | |
393 | 401 | | |
394 | 402 | | |
| |||
441 | 449 | | |
442 | 450 | | |
443 | 451 | | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
444 | 467 | | |
445 | 468 | | |
446 | 469 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1770 | 1770 | | |
1771 | 1771 | | |
1772 | 1772 | | |
| 1773 | + | |
| 1774 | + | |
| 1775 | + | |
1773 | 1776 | | |
1774 | 1777 | | |
1775 | 1778 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
184 | 189 | | |
185 | 190 | | |
186 | 191 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
0 commit comments