]> granicus.if.org Git - clang/commitdiff
Limit set of types instantiated in FindInstantiatedDecl.
authorSerge Pavlov <sepavloff@gmail.com>
Fri, 15 May 2015 10:10:28 +0000 (10:10 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Fri, 15 May 2015 10:10:28 +0000 (10:10 +0000)
Starting from r236426 FindInstantiatedDecl may instantiate types that
are referenced before definition. This change limit the set of types
that can be instantiated by this function.

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

lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaTemplate/instantiate-local-class.cpp

index 187478255370bfbc20f796abcd57ef7b0f9468b7..82ff7c0ca4f50774e0151d3a71f8a19c2064eed4 100644 (file)
@@ -2788,9 +2788,14 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
       isa<TemplateTemplateParmDecl>(D))
     return nullptr;
 
-  // Tag type may be referenced prior to definition, in this case it does not
-  // have instantiation yet.
-  if (isa<TagDecl>(D))
+  // Local types referenced prior to definition may require instantiation.
+  if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+    if (RD->isLocalClass())
+      return nullptr;
+
+  // Enumeration types referenced prior to definition may appear as a result of
+  // error recovery.
+  if (isa<EnumDecl>(D))
     return nullptr;
 
   // If we didn't find the decl, then we either have a sema bug, or we have a
index 4a92efdaae2a08660023722b9f3f01281475db22..5c994f86bd2c069750b87fd406613ebb3012ba30 100644 (file)
@@ -4442,9 +4442,25 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
     if (D->isInvalidDecl())
       return nullptr;
 
-    // Tag type may be referenced prior to definition, in this case it must be
-    // instantiated now.
-    if (isa<TagDecl>(D)) {
+    // Normally this function only searches for already instantiated declaration
+    // however we have to make an exclusion for local types used before
+    // definition as in the code:
+    //
+    //   template<typename T> void f1() {
+    //     void g1(struct x1);
+    //     struct x1 {};
+    //   }
+    //
+    // In this case instantiation of the type of 'g1' requires definition of
+    // 'x1', which is defined later. Error recovery may produce an enum used
+    // before definition. In these cases we need to instantiate relevant
+    // declarations here.
+    bool NeedInstantiate = false;
+    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+      NeedInstantiate = RD->isLocalClass();
+    else
+      NeedInstantiate = isa<EnumDecl>(D);
+    if (NeedInstantiate) {
       Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
       CurrentInstantiationScope->InstantiatedLocal(D, Inst);
       return cast<TypeDecl>(Inst);
index ff6cf7923f1b1b0c84070e41d636d40386b181f9..f58d7a49622539388f0cd229f37cb285f99c8b16 100644 (file)
@@ -225,6 +225,12 @@ namespace PR18653 {
   }
   template void f1<int>();
 
+  template<typename T> void f1a() {
+    void g1(union x1);
+    union x1 {};
+  }
+  template void f1a<int>();
+
   template<typename T> void f2() {
     void g2(enum x2);  // expected-error{{ISO C++ forbids forward references to 'enum' types}}
     enum x2 { nothing };
@@ -243,11 +249,17 @@ namespace PR18653 {
   }
   template void f4<int>();
 
+  template<typename T> void f4a() {
+    void g4(union x4 {} x);  // expected-error{{'x4' cannot be defined in a parameter type}}
+  }
+  template void f4a<int>();
+
 
   template <class T> void f();
   template <class T> struct S1 {
     void m() {
       f<class newclass>();
+      f<union newunion>();
     }
   };
   template struct S1<int>;
@@ -274,6 +286,14 @@ namespace PR18653 {
   };
   template struct S4<int>;
 
+  template <class T> struct S4a {
+    union local {};
+    void m() {
+      f<local>();
+    }
+  };
+  template struct S4a<int>;
+
   template <class T> struct S5 {
     enum local { nothing };
     void m() {
@@ -301,6 +321,15 @@ namespace PR18653 {
   };
   template struct S01<int>;
 
+  template <class T> struct S01a {
+    union local { };
+    void m() {
+      local x;
+      fff(&x);
+    }
+  };
+  template struct S01a<int>;
+
   template <class T> struct S02 {
     enum local { nothing };
     void m() {
@@ -328,6 +357,14 @@ namespace PR18653 {
   };
   template struct S04<int>;
 
+  template <class T> struct S04a {
+    void m() {
+      union { } x;
+      fff(&x);
+    }
+  };
+  template struct S04a<int>;
+
   template <class T> struct S05 {
     void m() {
       enum { nothing } x;