Hi rsmith, doug.gregor,

We wouldn't properly save and restore the pending local instantiations
we had built up prior to instantiation of a variable definition.  This
would lead to us instantiating too much causing crashes and other
general badness.

Depends on D2236.
Fixes PR14374.

http://llvm-reviews.chandlerc.com/D2238

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CXX/temp/temp.spec/temp.inst/p1.cpp
  test/SemaTemplate/instantiate-local-class.cpp
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -6406,6 +6406,24 @@
   /// types, static variables, enumerators, etc.
   std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
 
+  class SavePendingLocalImplicitInstantiationsRAII {
+  public:
+    SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) {
+      SavedPendingLocalImplicitInstantiations.swap(
+          S.PendingLocalImplicitInstantiations);
+    }
+
+    ~SavePendingLocalImplicitInstantiationsRAII() {
+      SavedPendingLocalImplicitInstantiations.swap(
+          S.PendingLocalImplicitInstantiations);
+    }
+
+  private:
+    Sema &S;
+    std::deque<PendingImplicitInstantiation>
+    SavedPendingLocalImplicitInstantiations;
+  };
+
   void PerformPendingInstantiations(bool LocalOnly = false);
 
   TypeSourceInfo *SubstType(TypeSourceInfo *T,
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -6270,7 +6270,10 @@
   switch (NewTSK) {
   case TSK_Undeclared:
   case TSK_ImplicitInstantiation:
-    llvm_unreachable("Don't check implicit instantiations here");
+    assert(
+        (PrevTSK == TSK_Undeclared || PrevTSK == TSK_ImplicitInstantiation) &&
+        "previous declaration must be implicit!");
+    return false;
 
   case TSK_ExplicitSpecialization:
     switch (PrevTSK) {
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -2457,6 +2457,11 @@
                               CXXRecordDecl *Instantiation,
                         const MultiLevelTemplateArgumentList &TemplateArgs,
                               TemplateSpecializationKind TSK) {
+  assert(
+      (TSK == TSK_ExplicitInstantiationDefinition ||
+       TSK == TSK_ExplicitInstantiationDeclaration ||
+       (TSK == TSK_ImplicitInstantiation && Instantiation->isLocalClass())) &&
+      "Unexpected template specialization kind!");
   for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
                                DEnd = Instantiation->decls_end();
        D != DEnd; ++D) {
@@ -2497,6 +2502,9 @@
           InstantiateFunctionDefinition(PointOfInstantiation, Function);
         } else {
           Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+          if (TSK == TSK_ImplicitInstantiation)
+            PendingLocalImplicitInstantiations.push_back(
+                std::make_pair(Function, PointOfInstantiation));
         }
       }
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -25,6 +25,17 @@
 
 using namespace clang;
 
+static bool isDeclWithinFunction(const Decl *D) {
+  const DeclContext *DC = D->getDeclContext();
+  if (DC->isFunctionOrMethod())
+    return true;
+
+  if (DC->isRecord())
+    return cast<CXXRecordDecl>(DC)->isLocalClass();
+
+  return false;
+}
+
 bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
                                               DeclaratorDecl *NewDecl) {
   if (!OldDecl->getQualifierLoc())
@@ -657,19 +668,17 @@
     }
   }
 
-  if (D->getDeclContext()->isFunctionOrMethod())
-    SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
-
   // C++11 [temp.inst]p1: The implicit instantiation of a class template
   // specialization causes the implicit instantiation of the declarations, but
   // not the definitions of scoped member enumerations.
   // FIXME: There appears to be no wording for what happens for an enum defined
   // within a block scope, but we treat that much like a member template. Only
   // instantiate the definition when visiting the definition in that case, since
   // we will visit all redeclarations.
-  if (!Enum->isScoped() && Def &&
-      (!D->getDeclContext()->isFunctionOrMethod() || D->isCompleteDefinition()))
+  if (isDeclWithinFunction(D) ? D == Def : (Def && !Enum->isScoped())) {
+    SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
     InstantiateEnumDefinition(Enum, Def);
+  }
 
   return Enum;
 }
@@ -724,7 +733,7 @@
       LastEnumConst = EnumConst;
 
       if (Pattern->getDeclContext()->isFunctionOrMethod() &&
-          !Enum->isScoped()) {
+          !Enum->isScoped() && !Enum->isScoped()) {
         // If the enumeration is within a function or method, record the enum
         // constant as a local.
         SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
@@ -1120,13 +1129,24 @@
     Record->setObjectOfFriendDecl();
 
   // Make sure that anonymous structs and unions are recorded.
-  if (D->isAnonymousStructOrUnion()) {
+  if (D->isAnonymousStructOrUnion())
     Record->setAnonymousStructOrUnion(true);
-    if (Record->getDeclContext()->getRedeclContext()->isFunctionOrMethod())
-      SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
-  }
+
+  if (D->isLocalClass())
+    SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
 
   Owner->addDecl(Record);
+
+  if (D->isCompleteDefinition() && D->isLocalClass()) {
+    if (SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
+                                 TSK_ImplicitInstantiation,
+                                 /*Complain=*/true)) {
+      llvm_unreachable("InstantiateClass shouldn't fail here!");
+    } else {
+      SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+                                      TSK_ImplicitInstantiation);
+    }
+  }
   return Record;
 }
 
@@ -3202,10 +3222,8 @@
   // while we're still within our own instantiation context.
   SmallVector<VTableUse, 16> SavedVTableUses;
   std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
-  std::deque<PendingImplicitInstantiation> 
-                              SavedPendingLocalImplicitInstantiations;
-  SavedPendingLocalImplicitInstantiations.swap(
-                                  PendingLocalImplicitInstantiations);
+  SavePendingLocalImplicitInstantiationsRAII
+      SavedPendingLocalImplicitInstantiations(*this);
   if (Recursive) {
     VTableUses.swap(SavedVTableUses);
     PendingInstantiations.swap(SavedPendingInstantiations);
@@ -3286,8 +3304,6 @@
            "PendingInstantiations should be empty before it is discarded.");
     PendingInstantiations.swap(SavedPendingInstantiations);
   }
-  SavedPendingLocalImplicitInstantiations.swap(
-                            PendingLocalImplicitInstantiations);
 }
 
 VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
@@ -3705,6 +3721,8 @@
   // while we're still within our own instantiation context.
   SmallVector<VTableUse, 16> SavedVTableUses;
   std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+  SavePendingLocalImplicitInstantiationsRAII
+      SavedPendingLocalImplicitInstantiations(*this);
   if (Recursive) {
     VTableUses.swap(SavedVTableUses);
     PendingInstantiations.swap(SavedPendingInstantiations);
Index: test/CXX/temp/temp.spec/temp.inst/p1.cpp
===================================================================
--- test/CXX/temp/temp.spec/temp.inst/p1.cpp
+++ test/CXX/temp/temp.spec/temp.inst/p1.cpp
@@ -33,24 +33,23 @@
   ScopedEnum1<double>::E e1; // ok
   ScopedEnum1<double>::E e2 = decltype(e2)::e; // expected-note {{in instantiation of enumeration 'ScopedEnum::ScopedEnum1<double>::E' requested here}}
 
-  // The behavior for enums defined within function templates is not clearly
-  // specified by the standard. We follow the rules for enums defined within
-  // class templates.
+  // CWG1484 specifies that enumerations cannot be separately instantiated,
+  // they will be instantiated with the rest of the template declaration.
   template<typename T>
   int f() {
     enum class E {
-      e = T::error
+      e = T::error // expected-error {{has no members}}
     };
     return (int)E();
   }
-  int test1 = f<int>();
+  int test1 = f<int>(); // expected-note {{here}}
 
   template<typename T>
   int g() {
     enum class E {
       e = T::error // expected-error {{has no members}}
     };
-    return E::e; // expected-note {{here}}
+    return E::e;
   }
   int test2 = g<int>(); // expected-note {{here}}
 }
Index: test/SemaTemplate/instantiate-local-class.cpp
===================================================================
--- test/SemaTemplate/instantiate-local-class.cpp
+++ test/SemaTemplate/instantiate-local-class.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
 // expected-no-diagnostics
 template<typename T>
 void f0() {
@@ -66,3 +66,117 @@
 
   template void foo<Y>();
 }
+
+namespace TemplatePacksAndLambdas {
+  template <typename ...T> int g(T...);
+  struct S {
+    template <typename ...T> static void f(int f = g([]{ static T t; return ++t; }()...)) {}
+  };
+  void h() { S::f<int, int, int>(); }
+}
+
+namespace PR9685 {
+  template <class Thing> void forEach(Thing t) { t.func(); }
+
+  template <typename T> void doIt() {
+    struct Functor {
+      void func() { (void)i; }
+      int i;
+    };
+
+    forEach(Functor());
+  }
+
+  void call() {
+    doIt<int>();
+  }
+}
+
+namespace PR12702 {
+  struct S {
+    template <typename F> bool apply(F f) { return f(); }
+  };
+
+  template <typename> struct T {
+    void foo() {
+      struct F {
+        int x;
+
+        bool operator()() { return x == 0; }
+      };
+
+      S().apply(F());
+    }
+  };
+
+  void call() { T<int>().foo(); }
+}
+
+namespace PR17139 {
+  template <class T> void foo(const T &t) { t.foo(); }
+
+  template <class F> void bar(F *f) {
+    struct B {
+      F *fn;
+      void foo() const { fn(); }
+    } b = { f };
+    foo(b);
+  }
+
+  void go() {}
+
+  void test() { bar(go); }
+}
+
+namespace PR17740 {
+class C {
+public:
+  template <typename T> static void foo(T function);
+  template <typename T> static void bar(T function);
+  template <typename T> static void func(T function);
+};
+
+template <typename T> void C::foo(T function) { function(); }
+
+template <typename T> void C::bar(T function) {
+  foo([&function]() { function(); });
+}
+
+template <typename T> void C::func(T function) {
+  struct Struct {
+    T mFunction;
+
+    Struct(T function) : mFunction(function) {};
+
+    void operator()() {
+      mFunction();
+    };
+  };
+
+  bar(Struct(function));
+}
+
+void call() {
+  C::func([]() {});
+}
+}
+
+namespace PR14373 {
+  struct function {
+    template <typename _Functor> function(_Functor __f) { __f(); }
+  };
+  template <typename Func> function exec_func(Func f) {
+    struct functor {
+      functor(Func f) : func(f) {}
+      void operator()() const { func(); }
+      Func func;
+    };
+    return functor(f);
+  }
+  struct Type {
+    void operator()() const {}
+  };
+  int call() {
+    exec_func(Type());
+  }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to