]> granicus.if.org Git - clang/commitdiff
Merging r195827:
authorBill Wendling <isanbard@gmail.com>
Thu, 28 Nov 2013 00:34:08 +0000 (00:34 +0000)
committerBill Wendling <isanbard@gmail.com>
Thu, 28 Nov 2013 00:34:08 +0000 (00:34 +0000)
------------------------------------------------------------------------
r195827 | majnemer | 2013-11-27 00:20:38 -0800 (Wed, 27 Nov 2013) | 9 lines

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.

------------------------------------------------------------------------

git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_34@195900 91177308-0d34-0410-b5e6-96231b3b80d8

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 e9977d42aa21081463601c1f0eea851e327b1566..5977b3cbae24a55a58ce74bc8ce8b0783748e0bb 100644 (file)
@@ -6270,7 +6270,10 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
   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 3c621dafab9dc33e02337e8dab5356fe25827c5f..7888e27eb5b02a73be078e6603c4615da2e50963 100644 (file)
@@ -2457,6 +2457,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
                               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 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
           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 f5c4c72cb349155e0f2e0a16827b8cbdeb4551d2..32f304338cec5be0fa8fc7f14b0c8857b9aedd47 100644 (file)
 
 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 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
     }
   }
 
-  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;
 }
@@ -1120,13 +1129,26 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
     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;
 }
 
index 8684fc4dabd9cb0f437ebaae093a816fc0a1226f..adf812b714d1ad99c215cf392342ea3c62e72839 100644 (file)
@@ -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}}
 }
index c151fbb9a5ba66edc308992bfd50230f00e1e461..2b5db0fda3ece947e6eb9774c4eb7c2c6ef7b46e 100644 (file)
@@ -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([]() {});
+}
+}