From 1c70e99a2c18b9a47659c4743f2d5bade3ea85de Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 3 Jun 2010 19:28:45 +0000 Subject: [PATCH] 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 --- clang/lib/AST/ASTImporter.cpp | 53 ++++++++++++++------------- clang/lib/Frontend/PCHReaderDecl.cpp | 31 ++++++++++++++++ clang/lib/Frontend/PCHWriterDecl.cpp | 17 +++++++++ clang/test/ASTMerge/Inputs/class1.cpp | 8 ++++ clang/test/ASTMerge/Inputs/class2.cpp | 8 ++++ clang/test/ASTMerge/class.cpp | 9 +++++ 6 files changed, 101 insertions(+), 25 deletions(-) create mode 100644 clang/test/ASTMerge/Inputs/class1.cpp create mode 100644 clang/test/ASTMerge/Inputs/class2.cpp create mode 100644 clang/test/ASTMerge/class.cpp diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 6ed08d1e1e29..3ccded28c4ee 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1687,7 +1687,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // Create the record declaration. RecordDecl *D2 = AdoptDecl; if (!D2) { - if (CXXRecordDecl *D1CXX = dyn_cast(D)) { + if (isa(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 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(D2)) { + CXXRecordDecl *D1CXX = cast(D); + + llvm::SmallVector 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(); } diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 2a1044c447f1..606e852385d4 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -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(Record[Idx++]); + bool isBaseOfClass = static_cast(Record[Idx++]); + AccessSpecifier AS = static_cast(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 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) { diff --git a/clang/lib/Frontend/PCHWriterDecl.cpp b/clang/lib/Frontend/PCHWriterDecl.cpp index 42756c35cc33..d0a01f083f9f 100644 --- a/clang/lib/Frontend/PCHWriterDecl.cpp +++ b/clang/lib/Frontend/PCHWriterDecl.cpp @@ -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; } diff --git a/clang/test/ASTMerge/Inputs/class1.cpp b/clang/test/ASTMerge/Inputs/class1.cpp new file mode 100644 index 000000000000..e13faf0539b1 --- /dev/null +++ b/clang/test/ASTMerge/Inputs/class1.cpp @@ -0,0 +1,8 @@ +struct A { + int x; +}; + +struct B : A { + float y; + float foo(); +}; diff --git a/clang/test/ASTMerge/Inputs/class2.cpp b/clang/test/ASTMerge/Inputs/class2.cpp new file mode 100644 index 000000000000..91b84dc13b75 --- /dev/null +++ b/clang/test/ASTMerge/Inputs/class2.cpp @@ -0,0 +1,8 @@ +struct A { + int x; +}; + +struct B : A { + int y; + int foo(); +}; diff --git a/clang/test/ASTMerge/class.cpp b/clang/test/ASTMerge/class.cpp new file mode 100644 index 000000000000..114687f8d984 --- /dev/null +++ b/clang/test/ASTMerge/class.cpp @@ -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