<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/57655>57655</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[lldb] CXXRecordDecl::IsStandardLayout incorrectly unset when importing a class with a single base class
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
Michael137
</td>
</tr>
</table>
<pre>
Essentially it’s just about importing a type with a single base class with member fields. There isn't anything problematic I ran into with this per-se, but it was a discrepancy I noticed while working on a different issue.
Setup:
```
// lib.h
class Base {
void* Field;
};
class Derived : Base {};
struct Foo {
Derived d;
};
// main.cpp
#include "lib.h"
int main() {
Foo f;
return 0;
}
```
```
./bin/lldb \
-o "br se -p return -X main" \
-o "log enable lldb ast" \
-o "r" \
-o "p f" \
-o "q" \
a.out
```
Executing `run.sh` will print:
```
-CXXRecordDecl 0x159f31d10 <<invalid sloc>> <invalid sloc> <undeserialized declarations> class Foo definition
|-DefinitionData pass_in_registers trivially_copyable trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
`-FieldDecl 0x159f32180 <<invalid sloc>> <invalid sloc> d 'test::Derived'
-CXXRecordDecl 0x159f31e50 <<invalid sloc>> <invalid sloc> class Derived definition
|-DefinitionData pass_in_registers trivially_copyable trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
`-private 'test::Base'
-CXXRecordDecl 0x159f31f90 <<invalid sloc>> <invalid sloc> class Base definition
|-DefinitionData pass_in_registers standard_layout trivially_copyable trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
`-FieldDecl 0x159f32110 <<invalid sloc>> <invalid sloc> Mem 'void *'
```
Note that both `class Derived` and `class Foo` don’t have `standard_layout` set in its DeinitionData despite `class Base` having it set.
According to the standard, a standard-layout class is allowed to have a single base class with member fields. This is codified in `RecordDecl::setBases` as follows:
```
…
// C++2a [class]p7:
// A standard-layout class is a class that:
// [...]
// -- has all non-static data members and bit-fields in the class and
// its base classes first declared in the same class
if (BaseClassDecl->data().HasBasesWithFields ||
!BaseClassDecl->field_empty()) {
if (data().HasBasesWithFields) {
data().IsStandardLayout = false;
}
data().HasBasesWithFields = true;
}
…
```
When we're asked to complete `Foo` we call into `DWARFASTParserClang::CompleteRecordType` and then `TypeSystemClang::TransferBaseClasses` which calls `CXXRecordDecl::setBases`.
When we then import the definition into the scratch AST (see `ASTNodeImporter::ImportDefinition`), we do:
```
struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
#define FIELD(Name, Width, Merge) \
ToData.Name = FromData.Name;
#include "clang/AST/CXXRecordDeclDefinitionBits.def"
if (!Bases.empty())
ToCXX->setBases(Bases.data(), Bases.size());
```
So now the `To` decl has `HasBasesWithFields` set going into `CXXRecordDecl::setBases`, and unset `IsStandardLayout` because we mistakenly claimed that `To` has more than one base class with members.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWd9v4jgQ_mvCi0UEyQLlgQcKRbfS7ep0rbT7VjmJA74Ncc42Zbm__r6xA4E0pdvdu4fTLUJtMvb89HzjsUlUdpjdGSNKK3lRHJi0wV0U3AyC6dSwP3bGMp6onWVyWyltZblmnNlDJdhe2g2eDUiFYAk3gqUFN8YPbMU2EZrlUhSZCdnDRmjBpCmDaAKJ5cFuSFSlVVKILbcyZe-Z5iWTpVVeAmYYVgndNyKIFiwhGyzbcwOlmTSpFhUv0wP4SgV-kbH9RsKSvdJfSLYq3cQ8h-YSvMbsRBgMlsFg7v_eC7urgrh-C8aD-utfoxW-rJBJuPEU79wt-RlMbj2NsSclsyCasxU5GsQ1PZgsm-cz7qXQ8gmWQmsj6dlcY_UutWyl1LmmI-81LbXVWy7LMK2qIzGWZVrsMqiLIu9RFJ2zIeiOJ4hugmh6rpRsyFtKGNOInC7Z4MKSzih2EUOYmJCyVVFkCQtGi6NcxvqKbEw0Q2z61VFR_3NtXkSzmfu0eQq1ZqLkSCfmxHJjL-Z38ehnM55_2jwV4vEaV5vnzzfp4SHh7frnSrTvvop054CKAb0rQ7PBAzBVFMAblvqllO8vPn_-XaRKZ0uRFmzwdTia5vEwGw6Qrwt8ZfnEC5kxU6g0iO_wZc-pRNqVmTBIV9D_ooyFOK4BclUamuGxQKmViVyWkgZq94PJor88EZfcclZh8qMsH7VYS2OFNswCCK5YPaaqOrglr0nAK2bwopF2lMh3hV1Av4OW0kx8hbCTKFYKkUHLtipkKl8L_pXlO2pcwLBzdYZEN2ZuuIHtGH6sEJhtW_3x4bE1r6Xkg3oSHT61dP2Qax1uzY2R63JLNfVf8-pMx7_g1IVX4wHSo71OUmtRiCcO_f-sRmhzO8U5wqLhzdsQhv0DuyiMJiTH83pjAO0qjsXobVoud6yfSP2J1P8bUrFbPnErLtFGbRsIr0p4AYX59HtQ6HrF74OgsbzMuM4eC36gvuInJH9C8r8LyY7N843t6QexJUDTuQ3_56dds7OX_qgAf7vhliUKR1KMXuyK1FcDXQ0dPS3RMkD0eIi2WNknQVNaSKSJRmBlcei1JPIcx-ifK2lFI9mVHXBAGLX2CCJ4L46z85SKDQ3iBG034oR8Oj3z01u_rgNeLI7YqAVqjx0eXM7Sbz_SS8efKhyyJQTAEVjY1DxfL2Em2W5crAzLFakzzRmkM_g-ePPxxal2EUS3-EYcR6lbZ1cwWlYTOkt_z-dCNmPzKxGqHykRrmtrySRDwzCEmd9l4UtS-32qFrRwrFRlH3bT_UlGeePXyLisTKTt-8WipaGM8G5grC0RH8rBZsUFVkpqY-uzm19dl1R8e5TTYaPMgakbWu8FTaEs6AN0ZJq_Wwh_4calwydk1Mobh0pCxeS69-4pGj4T7Rx8FNvKHryG-gLj2-MK153VV41sXYswdjb7vbmvM-dXnzhBvGQ5LwDYuNuOo5hg8mOJ0Zb3SpxhFkr1i1Z1S_0BG1tg7h7tKrufNqJke2qzNOqR-eKrU6poe_FFsS60e-QiwcDdGoKw_DT_fTW_f_iNayM0EqVc-yq0qHl9dXo4VOJYuy3pwgvR7g_ombZnbA-alyYX-pR2vo7tNzLdOM2GWC86vWdVL-zwzGv1V6oOVk1v531xUEs1t9ADfyg_jXCe4-2jysR7xyu0V-ffml6Q4klQWJCuTL1041NfNHbY32org2j8oPwTkuhBgeMS13VOvV3sSqvtSTC9dIk-3WO6MAm2en_36xKjH1GMyMlPMrMbevgg9Fo4rHZctnkp3o-QWE86T5Qr0Oi6S01dpkSUcfh74W_j6S0qawjD23eurujUJc2ErQr2GqhYswinVPOFF7qa0CEknmbkX-IkvYloF_juFXaVvctAgoVvaKjjoj0HLx3Fse5k1sq1JjUWr6PCNSWA364kThDaVZSEJiLlO2xJSOItGln-RZTFgXYfuaWSQH3ZyUSybqu0a9dKpsqX-hcT9sRsOB5Hk_hmGA962SzOpvGU96y0hZhhx6brY9qyOxx4VuqRDArtbmphl3dl3yDb_1hyZkFHa9Xb6WK2sbZyLZHbkNeYuktClDt3Rf50_IfzqPoDqvDqfszAiq9Gk_Fo1NvM0lGa82E8EXmcp4Mkz6Y8GudJko-TPI-mo17BE1EYcg95WIq9_z2EcnK07MlZNIiiwXQwHY7eRcNByOPp8F2UT5JxFg_iNA7eDcSWyyIkO0Kl1z09cyYlu7XBYEHHjGaQuxOIcNEk-XxnN0rPPqBqclHAzJ7TPnPW_w3wQ7uM">