r193144 - Sema: Do not allow template declarations inside local classes

David Majnemer david.majnemer at gmail.com
Mon Oct 21 21:14:18 PDT 2013


Author: majnemer
Date: Mon Oct 21 23:14:18 2013
New Revision: 193144

URL: http://llvm.org/viewvc/llvm-project?rev=193144&view=rev
Log:
Sema: Do not allow template declarations inside local classes

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

Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp
Removed:
    cfe/trunk/test/PCH/cxx-local-templates.cpp
    cfe/trunk/test/PCH/cxx1y-local-templates.cpp
    cfe/trunk/test/SemaTemplate/local-member-templates.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp
    cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=193144&r1=193143&r2=193144&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Oct 21 23:14:18 2013
@@ -2835,6 +2835,8 @@ def warn_template_export_unsupported : W
   "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<

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=193144&r1=193143&r2=193144&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Oct 21 23:14:18 2013
@@ -5459,8 +5459,20 @@ Sema::CheckTemplateDeclScope(Scope *S, T
   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)

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp?rev=193144&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.mem/p2.cpp Mon Oct 21 23:14:18 2013
@@ -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}}
+  };
+}

Modified: cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp?rev=193144&r1=193143&r2=193144&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle-local-class-names.cpp Mon Oct 21 23:14:18 2013
@@ -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) {

Removed: cfe/trunk/test/PCH/cxx-local-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-local-templates.cpp?rev=193143&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx-local-templates.cpp (original)
+++ cfe/trunk/test/PCH/cxx-local-templates.cpp (removed)
@@ -1,55 +0,0 @@
-// 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

Removed: cfe/trunk/test/PCH/cxx1y-local-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1y-local-templates.cpp?rev=193143&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx1y-local-templates.cpp (original)
+++ cfe/trunk/test/PCH/cxx1y-local-templates.cpp (removed)
@@ -1,58 +0,0 @@
-// 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

Modified: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=193144&r1=193143&r2=193144&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Mon Oct 21 23:14:18 2013
@@ -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}}
   }

Removed: cfe/trunk/test/SemaTemplate/local-member-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/local-member-templates.cpp?rev=193143&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/local-member-templates.cpp (original)
+++ cfe/trunk/test/SemaTemplate/local-member-templates.cpp (removed)
@@ -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





More information about the cfe-commits mailing list