]> granicus.if.org Git - clang/commitdiff
Fix PCH bug with member templates of local classes in nontemplate functions.
authorFaisal Vali <faisalv@yahoo.com>
Wed, 26 Jun 2013 02:34:24 +0000 (02:34 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Wed, 26 Jun 2013 02:34:24 +0000 (02:34 +0000)
As noted by Richard in the post:
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130624/082605.html, the following code should not add an entry
into PendingLocalImplicitInstantiations, since local instantiations
should only occur within the context of other instantiations:

int foo(double y) {
   struct Lambda {
      template<class T> T operator()(T t) const { return t; };
   } lambda;
   return lambda(y);
}

Hence the attached code does the following:
  1) In MarkFunctionReferenced, check if ActiveInstantiations.size()
      is non-zero before adding to PendingLocalImplicitInstantiations.
  2) In InstantiateFunctionDefinition, we swap out/in
      PendingLocalImplicitInstantiations so that only those
      pending local instantiations that are added during the instantiation
      of the current function are instantiated recursively.

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

lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/PCH/cxx-local-templates.cpp [new file with mode: 0644]
test/PCH/cxx1y-local-templates.cpp [new file with mode: 0644]

index 0c3ae1853aff5d020cb920daadacccc5b49ffbdc..2059a1e07644087cadc7a91a9cd2040f090a3636 100644 (file)
@@ -10893,7 +10893,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
 
     if (!AlreadyInstantiated || Func->isConstexpr()) {
       if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
-          cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
+          cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+          ActiveTemplateInstantiations.size())
         PendingLocalImplicitInstantiations.push_back(
             std::make_pair(Func, PointOfInstantiation));
       else if (Func->isConstexpr())
index c947bcc9f2a060a51c9f79e1ee70d22c0db21d2e..21a4cb12591ae78eeae559f01b93a4a5c51b061b 100644 (file)
@@ -2918,6 +2918,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   // while we're still within our own instantiation context.
   SmallVector<VTableUse, 16> SavedVTableUses;
   std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+  std::deque<PendingImplicitInstantiation> 
+                              SavedPendingLocalImplicitInstantiations;
+  SavedPendingLocalImplicitInstantiations.swap(
+                                  PendingLocalImplicitInstantiations);
   if (Recursive) {
     VTableUses.swap(SavedVTableUses);
     PendingInstantiations.swap(SavedPendingInstantiations);
@@ -2998,6 +3002,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
            "PendingInstantiations should be empty before it is discarded.");
     PendingInstantiations.swap(SavedPendingInstantiations);
   }
+  SavedPendingLocalImplicitInstantiations.swap(
+                            PendingLocalImplicitInstantiations);
 }
 
 /// \brief Instantiate the definition of the given variable from its
diff --git a/test/PCH/cxx-local-templates.cpp b/test/PCH/cxx-local-templates.cpp
new file mode 100644 (file)
index 0000000..277ad83
--- /dev/null
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11\r
+// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++11 -include-pch %t-cxx11  %s | FileCheck -check-prefix=CHECK-PRINT %s\r
+\r
+#ifndef HEADER_INCLUDED\r
+\r
+#define HEADER_INCLUDED\r
+\r
+int nontemplate_test(double d) {\r
+  struct Local {\r
+    template<class T> T foo(T t) {\r
+      return t;\r
+    }\r
+  };\r
+  return Local{}.foo(d);\r
+}\r
+\r
+template<class U>\r
+U template_test(U d) {\r
+  struct Local {\r
+    template<class T> T foo(T t) {\r
+      return t;\r
+    }\r
+  };\r
+  return Local{}.foo(d);\r
+}\r
+\r
+int nested_local() {\r
+  struct Inner1 {\r
+    int inner1_foo(char c) {\r
+      struct Inner2 {\r
+        template<class T> T inner2_foo(T t) {\r
+          return t;\r
+        }\r
+      };\r
+      return Inner2{}.inner2_foo(3.14);\r
+    }\r
+  };\r
+  return Inner1{}.inner1_foo('a');\r
+}\r
+\r
+#else\r
+\r
+// CHECK-PRINT: U template_test\r
+\r
+// CHECK-PRINT: int nontemplate_test(double)\r
+\r
+int nontemplate_test(double);\r
+\r
+template double template_test(double);\r
+int test2(int y) {\r
+  return nontemplate_test(y) + template_test(y);\r
+}\r
+\r
+\r
+#endif\r
diff --git a/test/PCH/cxx1y-local-templates.cpp b/test/PCH/cxx1y-local-templates.cpp
new file mode 100644 (file)
index 0000000..ccab03d
--- /dev/null
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++1y -emit-pch %s -o %t-cxx1y\r
+// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++1y -include-pch %t-cxx1y  %s | FileCheck -check-prefix=CHECK-PRINT %s\r
+\r
+#ifndef HEADER_INCLUDED\r
+\r
+#define HEADER_INCLUDED\r
+\r
+auto nested_local_call_all() {\r
+  struct Inner1 {\r
+    auto inner1_foo(char c) {\r
+      struct Inner2 {\r
+        template<class T> T inner2_foo(T t) {\r
+          return t;\r
+        }\r
+      };\r
+      return Inner2{};\r
+    }\r
+  };\r
+  return Inner1{}.inner1_foo('a').inner2_foo(4);\r
+}\r
+\r
+\r
+auto nested_local() {\r
+  struct Inner1 {\r
+    auto inner1_foo(char c) {\r
+      struct Inner2 {\r
+        template<class T> T inner2_foo(T t) {\r
+          return t;\r
+        }\r
+      };\r
+      return Inner2{};\r
+    }\r
+  };\r
+  return Inner1{};\r
+}\r
+\r
+\r
+int test() {\r
+  auto A = nested_local_call_all();\r
+  auto B = nested_local();\r
+  auto C = B.inner1_foo('a');\r
+  C.inner2_foo(3.14);\r
+\r
+}\r
+\r
+\r
+#else\r
+\r
+// CHECK-PRINT: int nested_local_call_all\r
+// CHECK-PRINT: nested_local\r
+auto nested_local_call_all();\r
+\r
+int test(int y) {\r
+  return nested_local_call_all();\r
+}\r
+\r
+\r
+#endif\r