r184903 - Fix PCH bug with member templates of local classes in nontemplate functions.

Faisal Vali faisalv at yahoo.com
Tue Jun 25 19:34:24 PDT 2013


Author: faisalv
Date: Tue Jun 25 21:34:24 2013
New Revision: 184903

URL: http://llvm.org/viewvc/llvm-project?rev=184903&view=rev
Log:
Fix PCH bug with member templates of local classes in nontemplate functions. 

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.

Added:
    cfe/trunk/test/PCH/cxx-local-templates.cpp
    cfe/trunk/test/PCH/cxx1y-local-templates.cpp
Modified:
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=184903&r1=184902&r2=184903&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 25 21:34:24 2013
@@ -10893,7 +10893,8 @@ void Sema::MarkFunctionReferenced(Source
 
     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())

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=184903&r1=184902&r2=184903&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Jun 25 21:34:24 2013
@@ -2918,6 +2918,10 @@ void Sema::InstantiateFunctionDefinition
   // 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
            "PendingInstantiations should be empty before it is discarded.");
     PendingInstantiations.swap(SavedPendingInstantiations);
   }
+  SavedPendingLocalImplicitInstantiations.swap(
+                            PendingLocalImplicitInstantiations);
 }
 
 /// \brief Instantiate the definition of the given variable from its

Added: cfe/trunk/test/PCH/cxx-local-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-local-templates.cpp?rev=184903&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx-local-templates.cpp (added)
+++ cfe/trunk/test/PCH/cxx-local-templates.cpp Tue Jun 25 21:34:24 2013
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
+// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++11 -include-pch %t-cxx11  %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+int nontemplate_test(double d) {
+  struct Local {
+    template<class T> T foo(T t) {
+      return t;
+    }
+  };
+  return Local{}.foo(d);
+}
+
+template<class U>
+U template_test(U d) {
+  struct Local {
+    template<class T> T foo(T t) {
+      return t;
+    }
+  };
+  return Local{}.foo(d);
+}
+
+int nested_local() {
+  struct Inner1 {
+    int inner1_foo(char c) {
+      struct Inner2 {
+        template<class T> T inner2_foo(T t) {
+          return t;
+        }
+      };
+      return Inner2{}.inner2_foo(3.14);
+    }
+  };
+  return Inner1{}.inner1_foo('a');
+}
+
+#else
+
+// CHECK-PRINT: U template_test
+
+// CHECK-PRINT: int nontemplate_test(double)
+
+int nontemplate_test(double);
+
+template double template_test(double);
+int test2(int y) {
+  return nontemplate_test(y) + template_test(y);
+}
+
+
+#endif

Added: cfe/trunk/test/PCH/cxx1y-local-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1y-local-templates.cpp?rev=184903&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx1y-local-templates.cpp (added)
+++ cfe/trunk/test/PCH/cxx1y-local-templates.cpp Tue Jun 25 21:34:24 2013
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++1y -emit-pch %s -o %t-cxx1y
+// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++1y -include-pch %t-cxx1y  %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+auto nested_local_call_all() {
+  struct Inner1 {
+    auto inner1_foo(char c) {
+      struct Inner2 {
+        template<class T> T inner2_foo(T t) {
+          return t;
+        }
+      };
+      return Inner2{};
+    }
+  };
+  return Inner1{}.inner1_foo('a').inner2_foo(4);
+}
+
+
+auto nested_local() {
+  struct Inner1 {
+    auto inner1_foo(char c) {
+      struct Inner2 {
+        template<class T> T inner2_foo(T t) {
+          return t;
+        }
+      };
+      return Inner2{};
+    }
+  };
+  return Inner1{};
+}
+
+
+int test() {
+  auto A = nested_local_call_all();
+  auto B = nested_local();
+  auto C = B.inner1_foo('a');
+  C.inner2_foo(3.14);
+
+}
+
+
+#else
+
+// CHECK-PRINT: int nested_local_call_all
+// CHECK-PRINT: nested_local
+auto nested_local_call_all();
+
+int test(int y) {
+  return nested_local_call_all();
+}
+
+
+#endif





More information about the cfe-commits mailing list