diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index a7a76532cabe..5993e9ac34ef 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -789,6 +789,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { IDNS |= Decl::IDNS_Ordinary; // We may already have a record of the same name; try to find and match it. + RecordDecl *AdoptDecl = 0; if (!DC->isFunctionOrMethod() && SearchName) { llvm::SmallVector ConflictingDecls; for (DeclContext::lookup_result Lookup = DC->lookup(Name); @@ -804,15 +805,21 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } if (RecordDecl *FoundRecord = dyn_cast(Found)) { - RecordDecl *FoundDef = FoundRecord->getDefinition(); - // FIXME: If we found something but there is no definition, - // assume the types are the same and fill in the gaps. - if (FoundDef && IsStructuralMatch(D, FoundDef)) { - // The record types structurally match. - // FIXME: For C++, we should also merge methods here. - Importer.getImportedDecls()[D] = FoundDef; - return FoundDef; - } + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { + if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // function. + // FIXME: For C++, we should also merge methods here. + Importer.getImportedDecls()[D] = FoundDef; + return FoundDef; + } + } else { + // We have a forward declaration of this type, so adopt that forward + // declaration rather than building a new one. + AdoptDecl = FoundRecord; + continue; + } } ConflictingDecls.push_back(*Lookup.first); @@ -826,47 +833,50 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } // Create the record declaration. - RecordDecl *ToRecord = 0; - if (CXXRecordDecl *FromCXX = dyn_cast(D)) { - CXXRecordDecl *ToCXX = CXXRecordDecl::Create(Importer.getToContext(), - D->getTagKind(), - DC, Loc, - Name.getAsIdentifierInfo(), + RecordDecl *ToRecord = AdoptDecl; + if (!ToRecord) { + if (CXXRecordDecl *FromCXX = dyn_cast(D)) { + CXXRecordDecl *ToCXX = CXXRecordDecl::Create(Importer.getToContext(), + D->getTagKind(), + DC, Loc, + Name.getAsIdentifierInfo(), Importer.Import(D->getTagKeywordLoc())); - ToRecord = ToCXX; - - if (D->isDefinition()) { - // Add base classes. - llvm::SmallVector Bases; - for (CXXRecordDecl::base_class_iterator FromBase = FromCXX->bases_begin(), - FromBaseEnd = FromCXX->bases_end(); - FromBase != FromBaseEnd; - ++FromBase) { - QualType T = Importer.Import(FromBase->getType()); - if (T.isNull()) - return 0; - - Bases.push_back( - new (Importer.getToContext()) + ToRecord = ToCXX; + + if (D->isDefinition()) { + // Add base classes. + llvm::SmallVector Bases; + for (CXXRecordDecl::base_class_iterator + FromBase = FromCXX->bases_begin(), + FromBaseEnd = FromCXX->bases_end(); + FromBase != FromBaseEnd; + ++FromBase) { + QualType T = Importer.Import(FromBase->getType()); + if (T.isNull()) + return 0; + + Bases.push_back( + new (Importer.getToContext()) CXXBaseSpecifier(Importer.Import(FromBase->getSourceRange()), FromBase->isVirtual(), FromBase->isBaseOfClass(), FromBase->getAccessSpecifierAsWritten(), T)); + } + if (!Bases.empty()) + ToCXX->setBases(Bases.data(), Bases.size()); } - if (!Bases.empty()) - ToCXX->setBases(Bases.data(), Bases.size()); + } else { + ToRecord = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc())); } - } else { - ToRecord = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), - DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getTagKeywordLoc())); + ToRecord->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToRecord); } - ToRecord->setLexicalDeclContext(LexicalDC); Importer.getImportedDecls()[D] = ToRecord; - LexicalDC->addDecl(ToRecord); - + if (D->isDefinition()) { ToRecord->startDefinition(); for (DeclContext::decl_iterator FromMem = D->decls_begin(), diff --git a/clang/test/ASTMerge/Inputs/struct1.c b/clang/test/ASTMerge/Inputs/struct1.c index 5743fe0f4874..ff8fa0a04abd 100644 --- a/clang/test/ASTMerge/Inputs/struct1.c +++ b/clang/test/ASTMerge/Inputs/struct1.c @@ -34,3 +34,13 @@ struct S6 { int i : 8; unsigned j : 8; } x6; // Bit-field mismatch struct S7 { int i : 8; unsigned j : 8; } x7; + +// Incomplete type +struct S8 *x8; + +// Incomplete type +struct S9 { int i; float f; } *x9; + +// Incomplete type +struct S10 *x10; + diff --git a/clang/test/ASTMerge/Inputs/struct2.c b/clang/test/ASTMerge/Inputs/struct2.c index a707ed2a5bf1..d865eef895d9 100644 --- a/clang/test/ASTMerge/Inputs/struct2.c +++ b/clang/test/ASTMerge/Inputs/struct2.c @@ -31,3 +31,12 @@ struct S6 { int i : 8; unsigned j; } x6; // Bit-field mismatch struct S7 { int i : 8; unsigned j : 16; } x7; + +// Incomplete type +struct S8 { int i; float f; } *x8; + +// Incomplete type +struct S9 *x9; + +// Incomplete type +struct S10 *x10;