]> granicus.if.org Git - clang/commitdiff
Sema: Do not allow template declarations inside local classes
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 22 Oct 2013 04:14:18 +0000 (04:14 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 22 Oct 2013 04:14:18 +0000 (04:14 +0000)
Summary:
Enforce the rule in C++11 [temp.mem]p2 that local classes cannot have
member templates.

This fixes PR16947.

N.B.  C++14 has slightly different wording to afford generic lambdas
declared inside of functions.

Fun fact:  Some formulations of local classes with member templates
would cause clang to crash during Itanium mangling, such as the
following:

void outer_mem() {
  struct Inner {
    template <typename = void>
    struct InnerTemplateClass {
      static void itc_mem() {}
    };
  };
  Inner::InnerTemplateClass<>::itc_mem();
}

Reviewers: eli.friedman, rsmith, doug.gregor, faisalv

Reviewed By: doug.gregor

CC: cfe-commits, ygao
Differential Revision: http://llvm-reviews.chandlerc.com/D1866

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.decls/temp.mem/p2.cpp [new file with mode: 0644]
test/CodeGenCXX/mangle-local-class-names.cpp
test/PCH/cxx-local-templates.cpp [deleted file]
test/PCH/cxx1y-local-templates.cpp [deleted file]
test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
test/SemaTemplate/local-member-templates.cpp [deleted file]

index fa5a3115b02a4463dd3551b47a88a6c5dac9960c..415c4b29633a84d5ef211811e57d3673bfbe6e3d 100644 (file)
@@ -2835,6 +2835,8 @@ def warn_template_export_unsupported : Warning<
   "exported templates are unsupported">;
 def err_template_outside_namespace_or_class_scope : Error<
   "templates can only be declared in namespace or class scope">;
+def err_template_inside_local_class : Error<
+  "templates cannot be declared inside of a local class">;
 def err_template_linkage : Error<"templates must have C++ linkage">;
 def err_template_typedef : Error<"a typedef cannot be a template">;
 def err_template_unnamed_class : Error<
index 596995071dd0df94f43cb65aa076e84c53dc2769..c49756d9aa27df1a113efecbd97c2c627fc95170 100644 (file)
@@ -5459,8 +5459,20 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
   while (Ctx && isa<LinkageSpecDecl>(Ctx))
     Ctx = Ctx->getParent();
 
-  if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
-    return false;
+  if (Ctx) {
+    if (Ctx->isFileContext())
+      return false;
+    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Ctx)) {
+      // C++ [temp.mem]p2:
+      //   A local class shall not have member templates.
+      if (RD->isLocalClass())
+        return Diag(TemplateParams->getTemplateLoc(),
+                    diag::err_template_inside_local_class)
+          << TemplateParams->getSourceRange();
+      else
+        return false;
+    }
+  }
 
   return Diag(TemplateParams->getTemplateLoc(),
               diag::err_template_outside_namespace_or_class_scope)
diff --git a/test/CXX/temp/temp.decls/temp.mem/p2.cpp b/test/CXX/temp/temp.decls/temp.mem/p2.cpp
new file mode 100644 (file)
index 0000000..c24d5a9
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template <typename>
+void quux();
+
+void fun() {
+  struct foo {
+    template <typename> struct bar {};  // expected-error{{templates cannot be declared inside of a local class}}
+    template <typename> void baz() {}   // expected-error{{templates cannot be declared inside of a local class}}
+    template <typename> void qux();     // expected-error{{templates cannot be declared inside of a local class}}
+  };
+}
index 186d76a225a95530980bec540af9501fd4f7e6f2..8b950fcd17766e4f3a2c87ee443d9bb927bde547 100644 (file)
@@ -75,16 +75,6 @@ inline void OmittingCode(float x) {
 }
 void CallOmittingCode() { OmittingCode(1); }
 
-// CHECK: @_ZZ25LocalTemplateFunctionTestdEN5Local3fooIdEET_S1_
-int LocalTemplateFunctionTest(double d) {
-  struct Local {
-    template<class T> T foo(T t) {
-      return t;
-    }
-  };
-  return Local().foo(d);
-}
-
 // CHECK: @_ZZ15LocalAnonStructvENUt0_1gEv
 inline void LocalAnonStruct() {
   if (0) {
diff --git a/test/PCH/cxx-local-templates.cpp b/test/PCH/cxx-local-templates.cpp
deleted file mode 100644 (file)
index 277ad83..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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
deleted file mode 100644 (file)
index ccab03d..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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
index 97bf00303bbe938c247a25bdda9d526068300d27..5f43ea2c27a19ac5498a1b9ce8b1d47a3382af57 100644 (file)
@@ -44,13 +44,14 @@ namespace dr1330_example {
     A<int>().f(42);
   }
 
+  struct S {
+    template<typename T>
+    static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \
+    // expected-note {{instantiation of exception spec}}
+    typedef decltype(f<S>()) X;
+  };
+
   int test2() {
-    struct S {
-      template<typename T>
-      static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \
-      // expected-note {{instantiation of exception spec}}
-      typedef decltype(f<S>()) X;
-    };
     S().f<S>(); // ok
     S().f<int>(); // expected-note {{instantiation of exception spec}}
   }
diff --git a/test/SemaTemplate/local-member-templates.cpp b/test/SemaTemplate/local-member-templates.cpp
deleted file mode 100644 (file)
index 847d483..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-// RUN: %clang_cc1 -std=c++1y -verify %s
-// RUN: %clang_cc1 -std=c++1y -verify %s -fdelayed-template-parsing
-
-namespace nested_local_templates_1 {
-
-template <class T> struct Outer {
-  template <class U> int outer_mem(T t, U u) {
-    struct Inner {
-      template <class V> int inner_mem(T t, U u, V v) {
-        struct InnerInner {
-          template <class W> int inner_inner_mem(W w, T t, U u, V v) {
-            return 0;
-          }
-        };
-        InnerInner().inner_inner_mem("abc", t, u, v);
-        return 0;
-      }
-    };
-    Inner i;
-    i.inner_mem(t, u, 3.14);
-    return 0;
-  }
-
-  template <class U> int outer_mem(T t, U *u);
-};
-
-template int Outer<int>::outer_mem(int, char);
-
-template <class T> template <class U> int Outer<T>::outer_mem(T t, U *u) {
-  struct Inner {
-    template <class V>
-    int inner_mem(T t, U u, V v) { //expected-note{{candidate function}}
-      struct InnerInner {
-        template <class W> int inner_inner_mem(W w, T t, U u, V v) { return 0; }
-      };
-      InnerInner().inner_inner_mem("abc", t, u, v);
-      return 0;
-    }
-  };
-  Inner i;
-  i.inner_mem(t, U{}, i);
-  i.inner_mem(t, u, 3.14); //expected-error{{no matching member function for call to 'inner}}
-  return 0;
-}
-
-template int Outer<int>::outer_mem(int, char *); //expected-note{{in instantiation of function}}
-
-} // end ns
-
-namespace nested_local_templates_2 {
-
-template <class T> struct Outer {
-  template <class U> void outer_mem(T t, U u) {
-    struct Inner {
-      template <class V> struct InnerTemplateClass {
-        template <class W>
-        void itc_mem(T t, U u, V v, W w) { //expected-note{{candidate function}}
-          struct InnerInnerInner {
-            template <class X> void iii_mem(X x) {}
-          };
-          InnerInnerInner i;
-          i.iii_mem("abc");
-        }
-      };
-    };
-    Inner i;
-    typename Inner::template InnerTemplateClass<Inner> ii;
-    ii.itc_mem(t, u, i, "jim");
-    ii.itc_mem(t, u, 0, "abd"); //expected-error{{no matching member function}}
-  }
-};
-
-template void
-Outer<int>::outer_mem(int, char); //expected-note{{in instantiation of}}
-
-}
-
-namespace more_nested_local_templates {
-
-int test() {
-  struct Local {
-    template<class U> void foo(U u) {
-      struct Inner {
-        template<class A> 
-        auto operator()(A a, U u2) -> U {
-          return u2;
-        };
-      };
-      Inner GL; 
-      GL('a', u );
-      GL(3.14, u );
-    }
-  };
-  Local l;
-  l.foo("nmabc");
-  return 0;
-}
-int t = test();
-}
\ No newline at end of file