diff options
author | David Majnemer <david.majnemer@gmail.com> | 2013-10-22 04:14:18 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2013-10-22 04:14:18 +0000 |
commit | 588a51a471b4cb23613e8183e05d2d193d2ab813 (patch) | |
tree | 6694aba70d5968f2b4e245f4fa0b2bfd64f0c312 | |
parent | 2cfbf0552f90c7ef42975ca1b9064888550ca2ee (diff) | |
download | clang-588a51a471b4cb23613e8183e05d2d193d2ab813.tar.gz |
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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193144 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 16 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.mem/p2.cpp | 12 | ||||
-rw-r--r-- | test/CodeGenCXX/mangle-local-class-names.cpp | 10 | ||||
-rw-r--r-- | test/PCH/cxx-local-templates.cpp | 55 | ||||
-rw-r--r-- | test/PCH/cxx1y-local-templates.cpp | 58 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-exception-spec-cxx11.cpp | 13 | ||||
-rw-r--r-- | test/SemaTemplate/local-member-templates.cpp | 99 |
8 files changed, 35 insertions, 230 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fa5a3115b0..415c4b2963 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 596995071d..c49756d9aa 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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 index 0000000000..c24d5a9b50 --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.mem/p2.cpp @@ -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}} + }; +} diff --git a/test/CodeGenCXX/mangle-local-class-names.cpp b/test/CodeGenCXX/mangle-local-class-names.cpp index 186d76a225..8b950fcd17 100644 --- a/test/CodeGenCXX/mangle-local-class-names.cpp +++ b/test/CodeGenCXX/mangle-local-class-names.cpp @@ -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 index 277ad83109..0000000000 --- a/test/PCH/cxx-local-templates.cpp +++ /dev/null @@ -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
diff --git a/test/PCH/cxx1y-local-templates.cpp b/test/PCH/cxx1y-local-templates.cpp deleted file mode 100644 index ccab03d4b4..0000000000 --- a/test/PCH/cxx1y-local-templates.cpp +++ /dev/null @@ -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
diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index 97bf00303b..5f43ea2c27 100644 --- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -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 index 847d483a00..0000000000 --- a/test/SemaTemplate/local-member-templates.cpp +++ /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 |