Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1029,7 +1029,7 @@ /// 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 Optional findAnonymousStructOrUnionIndex(RecordDecl *Anon) { +static Optional findUntaggedStructOrUnionIndex(RecordDecl *Anon) { ASTContext &Context = Anon->getASTContext(); QualType AnonTy = Context.getRecordType(Anon); @@ -1040,13 +1040,29 @@ unsigned Index = 0; for (const auto *D : Owner->noload_decls()) { const auto *F = dyn_cast(D); - if (!F || !F->isAnonymousStructOrUnion()) + if (!F) continue; - if (Context.hasSameType(F->getType(), AnonTy)) - break; + if (F->isAnonymousStructOrUnion()) { + if (Context.hasSameType(F->getType(), AnonTy)) + break; + ++Index; + continue; + } - ++Index; + // If the field looks like this: + // struct { ... } A; + QualType FieldType = F->getType(); + if (const auto *RecType = dyn_cast(FieldType)) { + const RecordDecl *RecDecl = RecType->getDecl(); + if (RecDecl->getDeclContext() == Owner && + !RecDecl->getIdentifier()) { + if (Context.hasSameType(FieldType, AnonTy)) + break; + ++Index; + continue; + } + } } return Index; @@ -1068,8 +1084,8 @@ 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 (Optional Index1 = findAnonymousStructOrUnionIndex(D1)) { - if (Optional Index2 = findAnonymousStructOrUnionIndex(D2)) { + if (Optional Index1 = findUntaggedStructOrUnionIndex(D1)) { + if (Optional Index2 = findUntaggedStructOrUnionIndex(D2)) { if (*Index1 != *Index2) return false; } @@ -2749,9 +2765,9 @@ // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. if (Optional Index1 - = findAnonymousStructOrUnionIndex(D)) { + = findUntaggedStructOrUnionIndex(D)) { if (Optional Index2 = - findAnonymousStructOrUnionIndex(FoundRecord)) { + findUntaggedStructOrUnionIndex(FoundRecord)) { if (*Index1 != *Index2) continue; } Index: test/ASTMerge/Inputs/anonymous-fields1.cpp =================================================================== --- /dev/null +++ test/ASTMerge/Inputs/anonymous-fields1.cpp @@ -0,0 +1,5 @@ +class A { +public: + struct { int foo; } f; + struct { int foo; } g; +}; Index: test/ASTMerge/Inputs/anonymous-fields2.cpp =================================================================== --- /dev/null +++ test/ASTMerge/Inputs/anonymous-fields2.cpp @@ -0,0 +1,9 @@ +class A { +public: + struct { int foo; } f; + struct { int foo; } g; +}; + +inline int useA(A &a) { + return (a.f.foo + a.g.foo); +} Index: test/ASTMerge/anonymous-fields.cpp =================================================================== --- /dev/null +++ test/ASTMerge/anonymous-fields.cpp @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/anonymous-fields1.cpp +// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/anonymous-fields2.cpp +// RUN: %clang_cc1 -emit-obj -o /dev/null -ast-merge %t.1.ast -ast-merge %t.2.ast %s +// expected-no-diagnostics