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