Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1040,11 +1040,27 @@ 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; + } + } else { + // If the field looks like this: + // struct { ... } A; + QualType FieldType = F->getType(); + if (const RecordType *RecType = dyn_cast(FieldType)) { + const RecordDecl *RecDecl = RecType->getDecl(); + if (RecDecl->getDeclContext() == Owner && + !RecDecl->getIdentifier()) { + if (Context.hasSameType(FieldType, AnonTy)) { + break; + } + } + } + } ++Index; } 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