Local classes should be permitted to have member templates.
2 Before / After Table
Before
After
// Extracted From LLVM test case temp.mem/p2.cppvoid fun(){struct foo {template<typename>struct bar {}; // Errortemplate<typename>void baz(){}// Errortemplate<typename>using corge =int; // Error};}
// Extracted From LLVM test case temp.mem/p2.cppvoid fun(){struct foo {template<typename>struct bar {}; // Allowedtemplate<typename>void baz(){}// Allowedtemplate<typename>using corge =int; // Allowed};}
3 Implementation Experience For C++98
Implemented in clang by deleting the check for template inside local class.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cppindex 5633582d679..d155bf8b5e4 100644--- a/clang/lib/Sema/SemaTemplate.cpp+++ b/clang/lib/Sema/SemaTemplate.cpp@@ -7385,12 +7385,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { 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 false; } }
Built a stage2 bootstrap of llvm, including libc++, which succeeded.
The test suite produced one new set of errors, the tests checking that templates not be declared inside of a local class.
error: 'error' diagnostics expected but not seen: File <snip>/temp/temp.decls/temp.mem/p2.cpp Line 8: templates cannot be declared inside of a local class File <snip>/temp/temp.decls/temp.mem/p2.cpp Line 9: templates cannot be declared inside of a local class File <snip>/temp/temp.decls/temp.mem/p2.cpp Line 10: templates cannot be declared inside of a local class File <snip>/temp/temp.decls/temp.mem/p2.cpp Line 11: templates cannot be declared inside of a local class File <snip>/temp/temp.decls/temp.mem/p2.cpp Line 12: templates cannot be declared inside of a local class5 errors generated.
4 Why C++ 98
In C++98 there is no way for a local class to escape the scope in which it is declared. (Un)Fortunately in C++11 we allowed the auto keyword and the deduction of the return type of a function.
What this means for templates in local classes is that the instantiation point may be outside the scope that the class is declared in. This leads to complications.
If the local class is returned from such a function, and the member template is used, the context defining the member, in existing implementations is lost.
template<typename T>auto f(T t){struct X {template<typename U>void g(){decltype(t) x =123; }};return X();}void h(){ f(nullptr).g<int>();}
With the patch above, clang will ICE. The corresponding lambda expression is diagnosed as an error. ~~~C++ template auto f(T t) { auto y = [](U u) { decltype(t) x = 123;}; return y; }
void h1() { auto k = f(nullptr);}; ~~~ clang reports: ~~~
auto y = []<typename U>(U u) { decltype(t) x = 123;}; ^ ~~~