r195827 - Sema: Instantiate local class and their members appropriately

David Majnemer david.majnemer at gmail.com
Wed Nov 27 00:20:39 PST 2013


Author: majnemer
Date: Wed Nov 27 02:20:38 2013
New Revision: 195827

URL: http://llvm.org/viewvc/llvm-project?rev=195827&view=rev
Log:
Sema: Instantiate local class and their members appropriately

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.

This fixes PR9685.

Modified:
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp
    cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=195827&r1=195826&r2=195827&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Nov 27 02:20:38 2013
@@ -6265,7 +6265,10 @@ Sema::CheckSpecializationInstantiationRe
   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) {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=195827&r1=195826&r2=195827&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Nov 27 02:20:38 2013
@@ -2456,6 +2456,11 @@ Sema::InstantiateClassMembers(SourceLoca
                               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) {
@@ -2496,6 +2501,9 @@ Sema::InstantiateClassMembers(SourceLoca
           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)) {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=195827&r1=195826&r2=195827&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Nov 27 02:20:38 2013
@@ -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())
@@ -655,19 +666,17 @@ Decl *TemplateDeclInstantiator::VisitEnu
     }
   }
 
-  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()))
+  //
+  // DR1484 clarifies that enumeration definitions inside of a template
+  // declaration aren't considered entities that can be separately instantiated
+  // from the rest of the entity they are declared inside of.
+  if (isDeclWithinFunction(D) ? D == Def : Def && !Enum->isScoped()) {
+    SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
     InstantiateEnumDefinition(Enum, Def);
+  }
 
   return Enum;
 }
@@ -1118,13 +1127,26 @@ Decl *TemplateDeclInstantiator::VisitCXX
     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);
+
+  // DR1484 clarifies that the members of a local class are instantiated as part
+  // of the instantiation of their enclosing entity.
+  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;
 }
 

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp?rev=195827&r1=195826&r2=195827&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp Wed Nov 27 02:20:38 2013
@@ -33,24 +33,23 @@ namespace ScopedEnum {
   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.
+  // DR1484 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}}
 }

Modified: cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp?rev=195827&r1=195826&r2=195827&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-local-class.cpp Wed Nov 27 02:20:38 2013
@@ -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,97 @@ namespace PR8801 {
 
   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([]() {});
+}
+}





More information about the cfe-commits mailing list