[PATCH] Sema: Instantiate local class and their members appropriately

David Majnemer david.majnemer at gmail.com
Wed Nov 20 16:08:51 PST 2013


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>(); }
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2236.1.patch
Type: text/x-patch
Size: 6717 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131120/f0ed1d20/attachment.bin>


More information about the cfe-commits mailing list