Hi rsmith, doug.gregor,

We would fail to instantiate them when the surrounding function was
instantiated.  Instantiate the class and add it's members to the list of
pending instantiations, they should be resolved when we are finished
with the function's body.

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

Files:
  lib/Sema/SemaTemplate.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CXX/temp/temp.spec/temp.inst/p1.cpp
  test/SemaCXX/local-classes.cpp

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) {
@@ -2482,7 +2487,8 @@
         if (Function->isDefined())
           continue;
 
-        if (TSK == TSK_ExplicitInstantiationDefinition) {
+        if (TSK == TSK_ExplicitInstantiationDefinition ||
+            TSK == TSK_ImplicitInstantiation) {
           // C++0x [temp.explicit]p8:
           //   An explicit instantiation definition that names a class template
           //   specialization explicitly instantiates the class template 
@@ -2494,7 +2500,11 @@
         
           Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
                       
-          InstantiateFunctionDefinition(PointOfInstantiation, Function);
+          if (TSK == TSK_ImplicitInstantiation)
+            PendingLocalImplicitInstantiations.push_back(
+                std::make_pair(Function, PointOfInstantiation));
+          else
+            InstantiateFunctionDefinition(PointOfInstantiation, Function);
         } else {
           Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
         }
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,7 +668,7 @@
     }
   }
 
-  if (D->getDeclContext()->isFunctionOrMethod())
+  if (isDeclWithinFunction(D))
     SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
 
   // C++11 [temp.inst]p1: The implicit instantiation of a class template
@@ -667,8 +678,7 @@
   // 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()))
     InstantiateEnumDefinition(Enum, Def);
 
   return Enum;
@@ -723,8 +733,7 @@
       Enumerators.push_back(EnumConst);
       LastEnumConst = EnumConst;
 
-      if (Pattern->getDeclContext()->isFunctionOrMethod() &&
-          !Enum->isScoped()) {
+      if (isDeclWithinFunction(Pattern) && !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,26 @@
     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 (CXXRecordDecl *Def = D->getDefinition()) {
+    if (Def->isLocalClass()) {
+      if (SemaRef.InstantiateClass(D->getLocation(), Record, Def, TemplateArgs,
+                                   TSK_ImplicitInstantiation,
+                                   /*Complain=*/true)) {
+        llvm_unreachable("InstantiateClass shouldn't fail here!");
+      } else {
+        SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+                                        TSK_ImplicitInstantiation);
+      }
+    }
+  }
   return Record;
 }
 
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
@@ -39,18 +39,18 @@
   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/SemaCXX/local-classes.cpp
===================================================================
--- test/SemaCXX/local-classes.cpp
+++ test/SemaCXX/local-classes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
 // expected-no-diagnostics
 
 namespace PR6382 {
@@ -40,3 +40,11 @@
     };
   }
 }
+
+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>(); }
+}
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) {
@@ -2482,7 +2487,8 @@
         if (Function->isDefined())
           continue;
 
-        if (TSK == TSK_ExplicitInstantiationDefinition) {
+        if (TSK == TSK_ExplicitInstantiationDefinition ||
+            TSK == TSK_ImplicitInstantiation) {
           // C++0x [temp.explicit]p8:
           //   An explicit instantiation definition that names a class template
           //   specialization explicitly instantiates the class template 
@@ -2494,7 +2500,11 @@
         
           Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
                       
-          InstantiateFunctionDefinition(PointOfInstantiation, Function);
+          if (TSK == TSK_ImplicitInstantiation)
+            PendingLocalImplicitInstantiations.push_back(
+                std::make_pair(Function, PointOfInstantiation));
+          else
+            InstantiateFunctionDefinition(PointOfInstantiation, Function);
         } else {
           Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
         }
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,7 +668,7 @@
     }
   }
 
-  if (D->getDeclContext()->isFunctionOrMethod())
+  if (isDeclWithinFunction(D))
     SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
 
   // C++11 [temp.inst]p1: The implicit instantiation of a class template
@@ -667,8 +678,7 @@
   // 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()))
     InstantiateEnumDefinition(Enum, Def);
 
   return Enum;
@@ -723,8 +733,7 @@
       Enumerators.push_back(EnumConst);
       LastEnumConst = EnumConst;
 
-      if (Pattern->getDeclContext()->isFunctionOrMethod() &&
-          !Enum->isScoped()) {
+      if (isDeclWithinFunction(Pattern) && !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,26 @@
     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 (CXXRecordDecl *Def = D->getDefinition()) {
+    if (Def->isLocalClass()) {
+      if (SemaRef.InstantiateClass(D->getLocation(), Record, Def, TemplateArgs,
+                                   TSK_ImplicitInstantiation,
+                                   /*Complain=*/true)) {
+        llvm_unreachable("InstantiateClass shouldn't fail here!");
+      } else {
+        SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+                                        TSK_ImplicitInstantiation);
+      }
+    }
+  }
   return Record;
 }
 
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
@@ -39,18 +39,18 @@
   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/SemaCXX/local-classes.cpp
===================================================================
--- test/SemaCXX/local-classes.cpp
+++ test/SemaCXX/local-classes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
 // expected-no-diagnostics
 
 namespace PR6382 {
@@ -40,3 +40,11 @@
     };
   }
 }
+
+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>(); }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to