/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
- void PerformPendingInstantiations(bool LocalOnly = false);
+ bool PerformPendingInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
- // 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.
// 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)
// 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<CXXRecordDecl>(Class->getCanonicalDecl());
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
}
VTableUses.clear();
- return true;
+ return DefinedAnything;
}
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
/// \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;
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired);
+ InstantiatedAnything = true;
continue;
}
TSK_ExplicitInstantiationDefinition;
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
DefinitionRequired);
+ InstantiatedAnything = true;
}
+
+ return InstantiatedAnything;
}
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
c2.c2(); // expected-note {{in instantiation of member function}}
}
+namespace PR9325 {
+ template<typename T>
+ 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<typename T>
+ struct Provider
+ {
+ static Target<T> Instance;
+ };
+
+ template<typename T>
+ Target<T> Provider<T>::Instance; // expected-note{{in instantiation of}}
+
+ void f()
+ {
+ Target<int*>* traits = &Provider<int*>::Instance;
+ }
+
+}