Hack in some really terrible C++ record PCH support that I need right now.
This is required in order to test: The ASTImporter should set base classes after formally entering the definition. llvm-svn: 105401
This commit is contained in:
parent
30093b5d8b
commit
1c70e99a2c
|
@ -1687,7 +1687,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
|
|||
// Create the record declaration.
|
||||
RecordDecl *D2 = AdoptDecl;
|
||||
if (!D2) {
|
||||
if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D)) {
|
||||
if (isa<CXXRecordDecl>(D)) {
|
||||
CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(),
|
||||
D->getTagKind(),
|
||||
DC, Loc,
|
||||
|
@ -1695,30 +1695,6 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
|
|||
Importer.Import(D->getTagKeywordLoc()));
|
||||
D2 = D2CXX;
|
||||
D2->setAccess(D->getAccess());
|
||||
|
||||
if (D->isDefinition()) {
|
||||
// Add base classes.
|
||||
llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
|
||||
for (CXXRecordDecl::base_class_iterator
|
||||
Base1 = D1CXX->bases_begin(),
|
||||
FromBaseEnd = D1CXX->bases_end();
|
||||
Base1 != FromBaseEnd;
|
||||
++Base1) {
|
||||
QualType T = Importer.Import(Base1->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
Bases.push_back(
|
||||
new (Importer.getToContext())
|
||||
CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
|
||||
Base1->isVirtual(),
|
||||
Base1->isBaseOfClass(),
|
||||
Base1->getAccessSpecifierAsWritten(),
|
||||
T));
|
||||
}
|
||||
if (!Bases.empty())
|
||||
D2CXX->setBases(Bases.data(), Bases.size());
|
||||
}
|
||||
} else {
|
||||
D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
|
||||
DC, Loc,
|
||||
|
@ -1739,6 +1715,33 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
|
|||
|
||||
if (D->isDefinition()) {
|
||||
D2->startDefinition();
|
||||
|
||||
// Add base classes.
|
||||
if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
|
||||
CXXRecordDecl *D1CXX = cast<CXXRecordDecl>(D);
|
||||
|
||||
llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
|
||||
for (CXXRecordDecl::base_class_iterator
|
||||
Base1 = D1CXX->bases_begin(),
|
||||
FromBaseEnd = D1CXX->bases_end();
|
||||
Base1 != FromBaseEnd;
|
||||
++Base1) {
|
||||
QualType T = Importer.Import(Base1->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
Bases.push_back(
|
||||
new (Importer.getToContext())
|
||||
CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
|
||||
Base1->isVirtual(),
|
||||
Base1->isBaseOfClass(),
|
||||
Base1->getAccessSpecifierAsWritten(),
|
||||
T));
|
||||
}
|
||||
if (!Bases.empty())
|
||||
D2CXX->setBases(Bases.data(), Bases.size());
|
||||
}
|
||||
|
||||
ImportDeclContext(D);
|
||||
D2->completeDefinition();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace {
|
|||
unsigned &Idx)
|
||||
: Reader(Reader), Record(Record), Idx(Idx) { }
|
||||
|
||||
CXXBaseSpecifier *ReadCXXBaseSpecifier();
|
||||
|
||||
void VisitDecl(Decl *D);
|
||||
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
|
||||
void VisitNamedDecl(NamedDecl *ND);
|
||||
|
@ -550,9 +552,38 @@ void PCHDeclReader::VisitUnresolvedUsingTypename(
|
|||
D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx));
|
||||
}
|
||||
|
||||
CXXBaseSpecifier *PCHDeclReader::ReadCXXBaseSpecifier() {
|
||||
bool isVirtual = static_cast<bool>(Record[Idx++]);
|
||||
bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
|
||||
AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
|
||||
QualType T = Reader.GetType(Record[Idx++]);
|
||||
SourceRange Range = Reader.ReadSourceRange(Record, Idx);
|
||||
return new (*Reader.getContext())
|
||||
CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, T);
|
||||
}
|
||||
|
||||
void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
// assert(false && "cannot read CXXRecordDecl");
|
||||
VisitRecordDecl(D);
|
||||
|
||||
// FIXME: this is far from complete
|
||||
|
||||
if (D->isDefinition()) {
|
||||
D->setDefinition(false); // make peace with an assertion
|
||||
D->startDefinition();
|
||||
|
||||
unsigned NumBases = Record[Idx++];
|
||||
|
||||
llvm::SmallVector<CXXBaseSpecifier*, 4> Bases;
|
||||
Bases.reserve(NumBases);
|
||||
for (unsigned I = 0; I != NumBases; ++I)
|
||||
Bases.push_back(ReadCXXBaseSpecifier());
|
||||
D->setBases(Bases.begin(), NumBases);
|
||||
|
||||
// FIXME: there's a lot of stuff we do here that's kindof sketchy
|
||||
// if we're leaving the context incomplete.
|
||||
D->completeDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
void PCHDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
||||
|
|
|
@ -105,6 +105,8 @@ namespace {
|
|||
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
|
||||
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
|
||||
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
||||
|
||||
void WriteCXXBaseSpecifier(const CXXBaseSpecifier *Base);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -559,9 +561,24 @@ void PCHDeclWriter::VisitUnresolvedUsingTypename(
|
|||
Code = pch::DECL_UNRESOLVED_USING_TYPENAME;
|
||||
}
|
||||
|
||||
void PCHDeclWriter::WriteCXXBaseSpecifier(const CXXBaseSpecifier *Base) {
|
||||
Record.push_back(Base->isVirtual());
|
||||
Record.push_back(Base->isBaseOfClass());
|
||||
Record.push_back(Base->getAccessSpecifierAsWritten());
|
||||
Writer.AddTypeRef(Base->getType(), Record);
|
||||
Writer.AddSourceRange(Base->getSourceRange(), Record);
|
||||
}
|
||||
|
||||
void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
// assert(false && "cannot write CXXRecordDecl");
|
||||
VisitRecordDecl(D);
|
||||
if (D->isDefinition()) {
|
||||
unsigned NumBases = D->getNumBases();
|
||||
Record.push_back(NumBases);
|
||||
for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
|
||||
E = D->bases_end(); I != E; ++I)
|
||||
WriteCXXBaseSpecifier(&*I);
|
||||
}
|
||||
Code = pch::DECL_CXX_RECORD;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
struct A {
|
||||
int x;
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
float y;
|
||||
float foo();
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
struct A {
|
||||
int x;
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
int y;
|
||||
int foo();
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class1.cpp
|
||||
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class2.cpp
|
||||
// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: class1.cpp:5:8: warning: type 'B' has incompatible definitions in different translation units
|
||||
// CHECK: class1.cpp:6:9: note: field 'y' has type 'float' here
|
||||
// CHECK: class2.cpp:6:7: note: field 'y' has type 'int' here
|
||||
|
||||
// FIXME: we should also complain about mismatched types on the method
|
Loading…
Reference in New Issue