[ASTImporter] Modifying ImportDeclContext(...) to ensure that we also handle the case when the FieldDecl is an ArrayType whose ElementType is a RecordDecl

When we fixed ImportDeclContext(...) in D71378 to make sure we complete each
FieldDecl of a RecordDecl when we are importing the definition we missed the
case where a FeildDecl was an ArrayType whose ElementType is a record.

This fix was motivated by a codegen crash during LLDB expression parsing. Since
we were not importing the definition we were crashing during layout which
required all the records be defined.

Differential Revision: https://reviews.llvm.org/D86660
This commit is contained in:
shafik 2020-09-21 14:55:33 -07:00
parent 8c3ef08f8a
commit 6807f244fa
4 changed files with 90 additions and 5 deletions

View File

@ -1742,12 +1742,28 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
Decl *ImportedDecl = *ImportedOrErr;
FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
if (FieldFrom && FieldTo) {
const RecordType *RecordFrom = FieldFrom->getType()->getAs<RecordType>();
const RecordType *RecordTo = FieldTo->getType()->getAs<RecordType>();
if (RecordFrom && RecordTo) {
RecordDecl *FromRecordDecl = RecordFrom->getDecl();
RecordDecl *ToRecordDecl = RecordTo->getDecl();
RecordDecl *FromRecordDecl = nullptr;
RecordDecl *ToRecordDecl = nullptr;
// If we have a field that is an ArrayType we need to check if the array
// element is a RecordDecl and if so we need to import the defintion.
if (FieldFrom->getType()->isArrayType()) {
// getBaseElementTypeUnsafe(...) handles multi-dimensonal arrays for us.
FromRecordDecl = FieldFrom->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl();
ToRecordDecl = FieldTo->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl();
}
if (!FromRecordDecl || !ToRecordDecl) {
const RecordType *RecordFrom =
FieldFrom->getType()->getAs<RecordType>();
const RecordType *RecordTo = FieldTo->getType()->getAs<RecordType>();
if (RecordFrom && RecordTo) {
FromRecordDecl = RecordFrom->getDecl();
ToRecordDecl = RecordTo->getDecl();
}
}
if (FromRecordDecl && ToRecordDecl) {
if (FromRecordDecl->isCompleteDefinition() &&
!ToRecordDecl->isCompleteDefinition()) {
Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl);

View File

@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp
include Makefile.rules

View File

@ -0,0 +1,14 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class TestImportDefinitionArrayType(TestBase):
mydir = TestBase.compute_mydir(__file__)
def test(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp"))
self.expect_expr("__private->o", result_type="char", result_value="'A'")

View File

@ -0,0 +1,52 @@
// This is a reproducer for a crash during codegen. The base issue is when we
// Import the DeclContext we force FieldDecl that are RecordType to be defined
// since we need these to be defined in order to layout the class.
// This case involves an array member whose ElementType are records. In this
// case we need to check the ElementType of an ArrayType and if it is a record
// we need to import the definition.
struct A {
int x;
};
struct B {
// When we import the all the FieldDecl we need to check if we have an
// ArrayType and then check if the ElementType is a RecordDecl and if so
// import the defintion. Otherwise during codegen we will attempt to layout A
// but won't be able to.
A s1[2];
A s2[2][2][3];
char o;
};
class FB {
public:
union {
struct {
unsigned char *_s;
} t;
char *tt[1];
} U;
FB(B *p) : __private(p) {}
// We import A but we don't import the definition.
void f(A **bounds) {}
void init();
private:
B *__private;
};
void FB::init() {
return; // break here
}
int main() {
B b;
FB fb(&b);
b.o = 'A';
fb.init();
}