From: John McCall Date: Tue, 15 Dec 2009 02:19:47 +0000 (+0000) Subject: Diagnose the use of typedefs for template specialization types in the scope X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4b2b02b26cd51e2e44fa315143618285fd72ce77;p=clang Diagnose the use of typedefs for template specialization types in the scope specifiers for out-of-line declarations, e.g. typedef Temp MyTemp; template <> MyTemp::foo; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91395 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e33fbe96d4..a890323e6c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -971,6 +971,9 @@ def err_template_tag_noparams : Error< def err_template_decl_ref : Error< "cannot refer to class template %0 without a template argument list">; +def err_typedef_in_def_scope : Error< + "cannot use typedef %0 in scope specifier for out-of-line declaration">; + // C++ Template Argument Lists def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 9fa57c03ea..ac1b1ec0ee 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1170,8 +1170,27 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, ExplicitSpecializationsInSpecifier; for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); NNS; NNS = NNS->getPrefix()) { + const Type *T = NNS->getAsType(); + if (!T) break; + + // C++0x [temp.expl.spec]p17: + // A member or a member template may be nested within many + // enclosing class templates. In an explicit specialization for + // such a member, the member declaration shall be preceded by a + // template<> for each enclosing class template that is + // explicitly specialized. + // We interpret this as forbidding typedefs of template + // specializations in the scope specifiers of out-of-line decls. + if (const TypedefType *TT = dyn_cast(T)) { + const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr(); + if (isa(UnderlyingT)) + // FIXME: better source location information. + Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0); + T = UnderlyingT; + } + if (const TemplateSpecializationType *SpecType - = dyn_cast_or_null(NNS->getAsType())) { + = dyn_cast(T)) { TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); if (!Template) continue; // FIXME: should this be an error? probably... diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp index 883cb71d56..06653044c3 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp @@ -10,3 +10,15 @@ template<> template<> class A::B; template<> template<> void A::B::mf(); template<> void A::B::mf(); // expected-error{{requires 'template<>'}} + +namespace test1 { + template class A { + static int foo; + static int bar; + }; + typedef A AA; + + template <> int AA::foo = 0; // expected-error {{cannot use typedef}} + int AA::bar = 1; // expected-error {{cannot use typedef}} expected-error {{template specialization requires 'template<>'}} + int A::bar = 2; // expected-error {{template specialization requires 'template<>'}} +}