From 975096917843e32ad4d27e8c52204c94b864689e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 22 Apr 2011 22:25:37 +0000 Subject: [PATCH] At the end of the translation unit, defining a vtable can introduce new templates that need to be instantiated and vice-versa. Iterate until we've instantiated all required templates and defined all required vtables. Fixed PR9325 / . llvm-svn: 130023 --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/Sema.cpp | 40 +++++++++++-------- clang/lib/Sema/SemaDeclCXX.cpp | 4 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 9 ++++- clang/test/SemaCXX/vtable-instantiation.cc | 26 ++++++++++++ 5 files changed, 62 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7cb0ad9970e4..b1746ac30880 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4349,7 +4349,7 @@ public: /// types, static variables, enumerators, etc. std::deque PendingLocalImplicitInstantiations; - void PerformPendingInstantiations(bool LocalOnly = false); + bool PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index dc1270243dd0..c954c64e7d0b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -373,22 +373,30 @@ void Sema::ActOnEndOfTranslationUnit() { } } - // If DefinedUsedVTables ends up marking any virtual member functions it - // might lead to more pending template instantiations, which we then need - // to instantiate. - DefineUsedVTables(); - - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully keep track of the point of instantiation (C++ [temp.point]). - // This means that name lookup that occurs within the template - // instantiation will always happen at the end of the translation unit, - // so it will find some names that should not be found. Although this is - // common behavior for C++ compilers, it is technically wrong. In the - // future, we either need to be able to filter the results of name lookup - // or we need to perform template instantiations earlier. - PerformPendingInstantiations(); + bool SomethingChanged; + do { + SomethingChanged = false; + + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + if (DefineUsedVTables()) + SomethingChanged = true; + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that should not be found. Although this is + // common behavior for C++ compilers, it is technically wrong. In the + // future, we either need to be able to filter the results of name lookup + // or we need to perform template instantiations earlier. + if (PerformPendingInstantiations()) + SomethingChanged = true; + + } while (SomethingChanged); } // Remove file scoped decls that turned out to be used. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5f3f600c8ca8..3a87cfd9665c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7751,6 +7751,7 @@ bool Sema::DefineUsedVTables() { // the members of a class as "used", so we check the size each // time through the loop and prefer indices (with are stable) to // iterators (which are not). + bool DefinedAnything = false; for (unsigned I = 0; I != VTableUses.size(); ++I) { CXXRecordDecl *Class = VTableUses[I].first->getDefinition(); if (!Class) @@ -7803,6 +7804,7 @@ bool Sema::DefineUsedVTables() { // Mark all of the virtual members of this class as referenced, so // that we can build a vtable. Then, tell the AST consumer that a // vtable for this class is required. + DefinedAnything = true; MarkVirtualMembersReferenced(Loc, Class); CXXRecordDecl *Canonical = cast(Class->getCanonicalDecl()); Consumer.HandleVTable(Class, VTablesUsed[Canonical]); @@ -7816,7 +7818,7 @@ bool Sema::DefineUsedVTables() { } VTableUses.clear(); - return true; + return DefinedAnything; } void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 588501f50ede..c972c6602e1f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3109,7 +3109,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -void Sema::PerformPendingInstantiations(bool LocalOnly) { +/// +/// \returns true if anything was instantiated. +bool Sema::PerformPendingInstantiations(bool LocalOnly) { + bool InstantiatedAnything = false; while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -3130,6 +3133,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, DefinitionRequired); + InstantiatedAnything = true; continue; } @@ -3166,7 +3170,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true, DefinitionRequired); + InstantiatedAnything = true; } + + return InstantiatedAnything; } void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, diff --git a/clang/test/SemaCXX/vtable-instantiation.cc b/clang/test/SemaCXX/vtable-instantiation.cc index 5a13d9505b3d..49949a773675 100644 --- a/clang/test/SemaCXX/vtable-instantiation.cc +++ b/clang/test/SemaCXX/vtable-instantiation.cc @@ -18,3 +18,29 @@ void f() { c2.c2(); // expected-note {{in instantiation of member function}} } +namespace PR9325 { + template + class Target + { + public: + virtual T Value() const + { + return 1; // expected-error{{cannot initialize return object of type 'int *' with an rvalue of type 'int'}} + } + }; + + template + struct Provider + { + static Target Instance; + }; + + template + Target Provider::Instance; // expected-note{{in instantiation of}} + + void f() + { + Target* traits = &Provider::Instance; + } + +} -- GitLab