diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 63bad2663e0b..cc53b8ceb0cc 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -499,7 +499,8 @@ private: typedef ArrayRef LexicalContents; /// \brief Map from a DeclContext to its lexical contents. - llvm::DenseMap LexicalDecls; + llvm::DenseMap> + LexicalDecls; /// \brief Map from the TU to its lexical contents from each module file. std::vector> TULexicalDecls; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ad528b0213ab..91dc4bdbc90e 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -975,11 +975,18 @@ bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, assert(!isa(DC) && "expected a TU_UPDATE_LEXICAL record for TU"); - // FIXME: Once we remove RewriteDecl, assert that we didn't already have - // lexical decls for this context. - LexicalDecls[DC] = llvm::makeArrayRef( - reinterpret_cast(Blob.data()), - Blob.size() / 4); + // If we are handling a C++ class template instantiation, we can see multiple + // lexical updates for the same record. It's important that we select only one + // of them, so that field numbering works properly. Just pick the first one we + // see. + auto &Lex = LexicalDecls[DC]; + if (!Lex.first) { + Lex = std::make_pair( + &M, llvm::makeArrayRef( + reinterpret_cast( + Blob.data()), + Blob.size() / 4)); + } DC->setHasExternalLexicalStorage(true); return false; } @@ -6253,7 +6260,7 @@ void ASTReader::FindExternalLexicalDecls( } else { auto I = LexicalDecls.find(DC); if (I != LexicalDecls.end()) - Visit(getOwningModuleFile(cast(DC)), I->second); + Visit(I->second.first, I->second.second); } ++NumLexicalDeclContextsRead; diff --git a/clang/test/Modules/Inputs/templates-right.h b/clang/test/Modules/Inputs/templates-right.h index daea97b86b88..32487c60c269 100644 --- a/clang/test/Modules/Inputs/templates-right.h +++ b/clang/test/Modules/Inputs/templates-right.h @@ -38,6 +38,10 @@ int defineListDoubleRight() { return ld.size; } +inline void defineListLongRight() { + List ll; +} + template struct MergePatternDecl; void outOfLineInlineUseRightF(void (OutOfLineInline::*)() = &OutOfLineInline::f); diff --git a/clang/test/Modules/Inputs/templates-top.h b/clang/test/Modules/Inputs/templates-top.h index 31f5e4199281..a08268352399 100644 --- a/clang/test/Modules/Inputs/templates-top.h +++ b/clang/test/Modules/Inputs/templates-top.h @@ -10,6 +10,7 @@ public: }; extern List *instantiateListDoubleDeclaration; +extern List *instantiateListLongDeclaration; namespace A { class Y { diff --git a/clang/test/Modules/templates.mm b/clang/test/Modules/templates.mm index 4c6e4723a3bb..190084ad2b74 100644 --- a/clang/test/Modules/templates.mm +++ b/clang/test/Modules/templates.mm @@ -28,6 +28,8 @@ void testTemplateClasses() { N::Set set_char; set_char.insert('A'); + static_assert(sizeof(List) == sizeof(List), ""); + List list_double; list_double.push_back(0.0); }