This patch changes InstantiateFunctionDefinition to also define used vtables
as it goes recursively instantiating templates. This should allow us to
track where delayed vtable instantiations were requested, fixing PR8640.
Also, this removes the while(1) loop in ActOnEndOfTranslationUnit(). It's
replaced with "PerformPendingInstantiations(); if (DefineUsedVTables())
{ PerformPendingInstantiations(); }" and it's a mystery to me why we need
the first instantiation call. Removing it causes a single test failure in
test/SemaCXX/destructor.cpp (namespace test6):
// ... class A is defined with a virtual destructor ...
class B : A<int> { B(); };
B::B() {} // expected-note {{in instantiation of member function
'test6::A<int>::~A' requested here}}
the note moves onto the previous line. If the existing behaviour is correct
(deriving A<int> instantiates the class but not any of the methods, then
B::B() requires ~A to destruct the object in case of exceptions) then
there's probably another bug in clang where we're adding that the vtable is
needed on the line declaring class B. Alternately, the test is wrong. :)
Please review!
Nick
Index: test/SemaCXX/vtable-instantiation.cc
===================================================================
--- test/SemaCXX/vtable-instantiation.cc (revision 0)
+++ test/SemaCXX/vtable-instantiation.cc (revision 0)
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<class T1> struct C1 {
+ virtual void c1() {
+ T1 t1 = 3; // expected-error {{cannot initialize a variable}}
+ }
+};
+
+template<class T2> struct C2 {
+ void c2() {
+ new C1<T2>(); // expected-note {{in instantiation of member function}}
+ }
+};
+
+void f() {
+ C2<int*> c2;
+ c2.c2(); // expected-note {{in instantiation of member function}}
+}
+
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h (revision 119886)
+++ include/clang/Sema/Sema.h (working copy)
@@ -2554,9 +2554,12 @@
/// \brief The list of classes whose vtables have been used within
/// this translation unit, and the source locations at which the
/// first use occurred.
- llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 16>
- VTableUses;
+ typedef std::pair<CXXRecordDecl*, SourceLocation> VTableUse;
+ /// \brief The list of vtables that are required but have not yet been
+ /// materialized.
+ llvm::SmallVector<VTableUse, 16> VTableUses;
+
/// \brief The set of classes whose vtables have been used within
/// this translation unit, and a bit that will be true if the vtable is
/// required to be emitted (otherwise, it should be emitted only if needed
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp (revision 119886)
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp (working copy)
@@ -2085,9 +2085,12 @@
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
+ llvm::SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
- if (Recursive)
+ if (Recursive) {
+ VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
+ }
EnterExpressionEvaluationContext EvalContext(*this,
Sema::PotentiallyEvaluated);
@@ -2150,10 +2153,16 @@
Scope.Exit();
if (Recursive) {
+ // Define any pending vtables.
+ DefineUsedVTables();
+
// Instantiate any pending implicit instantiations found during the
// instantiation of this template.
PerformPendingInstantiations();
+ // Restore the set of pending vtables.
+ VTableUses.swap(SavedVTableUses);
+
// Restore the set of pending implicit instantiations.
PendingInstantiations.swap(SavedPendingInstantiations);
}
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp (revision 119886)
+++ lib/Sema/Sema.cpp (working copy)
@@ -284,26 +284,25 @@
void Sema::ActOnEndOfTranslationUnit() {
// At PCH writing, implicit instantiations and VTable handling info are
// stored and performed when the PCH is included.
- if (CompleteTranslationUnit)
- while (1) {
- // 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();
+ if (CompleteTranslationUnit) {
+ // 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();
- /// If DefinedUsedVTables ends up marking any virtual member
- /// functions it might lead to more pending template
- /// instantiations, which is why we need to loop here.
- if (!DefineUsedVTables())
- break;
- }
+ // 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())
+ PerformPendingInstantiations();
+ }
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(),
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits