From 93ed7cf05f900b9150dcf59c0e0f37f3bd325f62 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 17 Jul 2012 21:16:27 +0000 Subject: [PATCH] Teach the ASTImporter how to handle anonymous structs/unions better. Fixes ; the test (and back-ported version of this code) were committed to LLDB in r160186. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160395 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTImporter.h | 3 +- lib/AST/ASTImporter.cpp | 57 ++++++++++++++++++++++++--------- lib/AST/DeclBase.cpp | 20 ++++++------ 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h index 7157efe5b3..46a9881039 100644 --- a/include/clang/AST/ASTImporter.h +++ b/include/clang/AST/ASTImporter.h @@ -271,7 +271,8 @@ namespace clang { /// \brief Determine whether the given types are structurally /// equivalent. - bool IsStructurallyEquivalent(QualType From, QualType To); + bool IsStructurallyEquivalent(QualType From, QualType To, + bool Complain = true); }; } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 3403b6276c..3e952acdcb 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -119,7 +119,8 @@ namespace clang { bool ImportTemplateArguments(const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl &ToArgs); - bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); + bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, + bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); Decl *VisitDecl(Decl *D); @@ -201,12 +202,16 @@ namespace { /// \brief Whether we're being strict about the spelling of types when /// unifying two types. bool StrictTypeSpelling; - + + /// \brief Whether to complain about failures. + bool Complain; + StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, llvm::DenseSet > &NonEquivalentDecls, - bool StrictTypeSpelling = false) + bool StrictTypeSpelling = false, + bool Complain = true) : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls), - StrictTypeSpelling(StrictTypeSpelling) { } + StrictTypeSpelling(StrictTypeSpelling), Complain(Complain) { } /// \brief Determine whether the two declarations are structurally /// equivalent. @@ -223,10 +228,16 @@ namespace { public: DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { + if (!Complain) + return DiagnosticBuilder::getEmpty(); + return C1.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { + if (!Complain) + return DiagnosticBuilder::getEmpty(); + return C2.getDiagnostics().Report(Loc, DiagID); } }; @@ -2008,10 +2019,11 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, } bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, - RecordDecl *ToRecord) { + RecordDecl *ToRecord, bool Complain) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls()); + Importer.getNonEquivalentDecls(), + false, Complain); return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); } @@ -2291,7 +2303,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // We may already have a record of the same name; try to find and match it. RecordDecl *AdoptDecl = 0; - if (!DC->isFunctionOrMethod() && SearchName) { + if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; llvm::SmallVector FoundDecls; DC->localUncachedLookup(SearchName, FoundDecls); @@ -2307,25 +2319,31 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (RecordDecl *FoundRecord = dyn_cast(Found)) { if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { - if (!D->isCompleteDefinition() || IsStructuralMatch(D, FoundDef)) { + if ((SearchName && !D->isCompleteDefinition()) + || (D->isCompleteDefinition() && + D->isAnonymousStructOrUnion() + == FoundDef->isAnonymousStructOrUnion() && + 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. return Importer.Imported(D, FoundDef); } - } else { + } else if (!D->isCompleteDefinition()) { // We have a forward declaration of this type, so adopt that forward // declaration rather than building a new one. AdoptDecl = FoundRecord; continue; - } + } else if (!SearchName) { + continue; + } } ConflictingDecls.push_back(FoundDecls[I]); } - if (!ConflictingDecls.empty()) { + if (!ConflictingDecls.empty() && SearchName) { Name = Importer.HandleNameConflict(Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); @@ -2351,6 +2369,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); + if (D->isAnonymousStructOrUnion()) + D2->setAnonymousStructOrUnion(true); } Importer.Imported(D, D2); @@ -2642,11 +2662,16 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (IndirectFieldDecl *FoundField = dyn_cast(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getType(), - FoundField->getType())) { + FoundField->getType(), + Name)) { Importer.Imported(D, FoundField); return FoundField; } - + + // If there are more anonymous fields to check, continue. + if (!Name && I < N-1) + continue; + Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) @@ -4621,12 +4646,14 @@ Decl *ASTImporter::Imported(Decl *From, Decl *To) { return To; } -bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) { +bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, + bool Complain) { llvm::DenseMap::iterator Pos = ImportedTypes.find(From.getTypePtr()); if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) return true; - StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls); + StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, + false, Complain); return Ctx.IsStructurallyEquivalent(From, To); } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 574f779b86..f9ce46def5 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -1196,23 +1196,25 @@ void DeclContext::localUncachedLookup(DeclarationName Name, // If there's no external storage, just perform a normal lookup and copy // the results. - if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage()) { + if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) { lookup_result LookupResults = lookup(Name); Results.insert(Results.end(), LookupResults.first, LookupResults.second); return; } // If we have a lookup table, check there first. Maybe we'll get lucky. - if (StoredDeclsMap *Map = LookupPtr.getPointer()) { - StoredDeclsMap::iterator Pos = Map->find(Name); - if (Pos != Map->end()) { - Results.insert(Results.end(), - Pos->second.getLookupResult().first, - Pos->second.getLookupResult().second); - return; + if (Name) { + if (StoredDeclsMap *Map = LookupPtr.getPointer()) { + StoredDeclsMap::iterator Pos = Map->find(Name); + if (Pos != Map->end()) { + Results.insert(Results.end(), + Pos->second.getLookupResult().first, + Pos->second.getLookupResult().second); + return; + } } } - + // Slow case: grovel through the declarations in our chain looking for // matches. for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { -- 2.40.0