From: Douglas Gregor Date: Fri, 26 Oct 2012 16:45:11 +0000 (+0000) Subject: Match up anonymous structs/unions in the ASTImporter. Previously, we'd X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=11ce5fe7d8dda29f3d093e5759a7476b140e3241;p=clang Match up anonymous structs/unions in the ASTImporter. Previously, we'd only actually get the answer right if there was only a single anonymous struct/union at that level. This is part of ; the test will go into LLDB itself. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166781 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 48dafebd10..dc1afcbd4d 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -819,8 +819,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FieldDecl *Field1, FieldDecl *Field2) { RecordDecl *Owner2 = cast(Field2->getDeclContext()); - - if (!IsStructurallyEquivalent(Context, + + // For anonymous structs/unions, match up the anonymous struct/union type + // declarations directly, so that we don't go off searching for anonymous + // types + if (Field1->isAnonymousStructOrUnion() && + Field2->isAnonymousStructOrUnion()) { + RecordDecl *D1 = Field1->getType()->castAs()->getDecl(); + RecordDecl *D2 = Field2->getType()->castAs()->getDecl(); + return IsStructurallyEquivalent(Context, D1, D2); + } + + if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { if (Context.Complain) { Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) @@ -875,6 +885,39 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// \brief Find the index of the given anonymous struct/union within its +/// context. +/// +/// \returns Returns the index of this anonymous struct/union in its context, +/// including the next assigned index (if none of them match). Returns an +/// empty option if the context is not a record, i.e.. if the anonymous +/// struct/union is at namespace or block scope. +static llvm::Optional +findAnonymousStructOrUnionIndex(RecordDecl *Anon) { + ASTContext &Context = Anon->getASTContext(); + QualType AnonTy = Context.getRecordType(Anon); + + RecordDecl *Owner = dyn_cast(Anon->getDeclContext()); + if (!Owner) + return llvm::Optional(); + + unsigned Index = 0; + for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), + DEnd = Owner->noload_decls_end(); + D != DEnd; ++D) { + FieldDecl *F = dyn_cast(*D); + if (!F || !F->isAnonymousStructOrUnion()) + continue; + + if (Context.hasSameType(F->getType(), AnonTy)) + break; + + ++Index; + } + + return Index; +} + /// \brief Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { @@ -887,7 +930,20 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } return false; } - + + if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { + // If both anonymous structs/unions are in a record context, make sure + // they occur in the same location in the context records. + if (llvm::Optional Index1 + = findAnonymousStructOrUnionIndex(D1)) { + if (llvm::Optional Index2 + = findAnonymousStructOrUnionIndex(D2)) { + if (*Index1 != *Index2) + return false; + } + } + } + // If both declarations are class template specializations, we know // the ODR applies, so check the template and template arguments. ClassTemplateSpecializationDecl *Spec1 @@ -2371,6 +2427,20 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } if (RecordDecl *FoundRecord = dyn_cast(Found)) { + if (D->isAnonymousStructOrUnion() && + FoundRecord->isAnonymousStructOrUnion()) { + // If both anonymous structs/unions are in a record context, make sure + // they occur in the same location in the context records. + if (llvm::Optional Index1 + = findAnonymousStructOrUnionIndex(D)) { + if (llvm::Optional Index2 + = findAnonymousStructOrUnionIndex(FoundRecord)) { + if (*Index1 != *Index2) + continue; + } + } + } + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { if ((SearchName && !D->isCompleteDefinition()) || (D->isCompleteDefinition() && @@ -2679,6 +2749,25 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) { return VisitCXXMethodDecl(D); } +static unsigned getFieldIndex(Decl *F) { + RecordDecl *Owner = dyn_cast(F->getDeclContext()); + if (!Owner) + return 0; + + unsigned Index = 1; + for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), + DEnd = Owner->noload_decls_end(); + D != DEnd; ++D) { + if (*D == F) + return Index; + + if (isa(*D) || isa(*D)) + ++Index; + } + + return Index; +} + Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; @@ -2692,6 +2781,10 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (FieldDecl *FoundField = dyn_cast(FoundDecls[I])) { + // For anonymous fields, match up by index. + if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); @@ -2725,6 +2818,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { ToField->setLexicalDeclContext(LexicalDC); if (ToField->hasInClassInitializer()) ToField->setInClassInitializer(D->getInClassInitializer()); + ToField->setImplicit(D->isImplicit()); Importer.Imported(D, ToField); LexicalDC->addDeclInternal(ToField); return ToField; @@ -2744,6 +2838,10 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (IndirectFieldDecl *FoundField = dyn_cast(FoundDecls[I])) { + // For anonymous indirect fields, match up by index. + if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), Name)) {