From: Richard Smith Date: Fri, 16 Mar 2018 13:36:56 +0000 (+0000) Subject: Implement C++ DR727, which permits explicit specializations at class scope. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=68e1ba46fe5a41c099c01869ebc7a5f5bf58b73e;p=clang Implement C++ DR727, which permits explicit specializations at class scope. More generally, this permits a template to be specialized in any scope in which it could be defined, so this also supersedes DR44 and DR374 (the latter of which we previously only implemented in C++11 mode onwards due to unclarity as to whether it was a DR). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@327705 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7c22e03a92..809d37ea58 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4144,42 +4144,20 @@ def note_explicit_specialization_declared_here : Note< "explicit specialization declared here">; def err_template_spec_decl_function_scope : Error< "explicit specialization of %0 in function scope">; -def err_template_spec_decl_class_scope : Error< - "explicit specialization of %0 in class scope">; def err_template_spec_decl_friend : Error< "cannot declare an explicit specialization in a friend">; -def err_template_spec_decl_out_of_scope_global : Error< - "%select{class template|class template partial|variable template|" - "variable template partial|function template|member function|" - "static data member|member class|member enumeration}0 " - "specialization of %1 must originally be declared in the global scope">; -def err_template_spec_decl_out_of_scope : Error< - "%select{class template|class template partial|variable template|" - "variable template partial|function template|member " - "function|static data member|member class|member enumeration}0 " - "specialization of %1 must originally be declared in namespace %2">; -def ext_template_spec_decl_out_of_scope : ExtWarn< - "first declaration of %select{class template|class template partial|" - "variable template|variable template partial|" - "function template|member function|static data member|member class|" - "member enumeration}0 specialization of %1 outside namespace %2 is a " - "C++11 extension">, InGroup; -def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< - "%select{class template|class template partial|variable template|" - "variable template partial|function template|member " - "function|static data member|member class|member enumeration}0 " - "specialization of %1 outside namespace %2 is incompatible with C++98">, - InGroup, DefaultIgnore; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " - "specialization of %1 not in a namespace enclosing %2">; + "specialization of %1 not in %select{a namespace enclosing %2|" + "class %2 or an enclosing namespace}3">; def ext_ms_template_spec_redecl_out_of_scope: ExtWarn< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " - "specialization of %1 outside namespace enclosing %2 " + "specialization of %1 not in %select{a namespace enclosing %2|" + "class %2 or an enclosing namespace}3 " "is a Microsoft extension">, InGroup; def err_template_spec_redecl_global_scope : Error< "%select{class template|class template partial|variable template|" @@ -4201,11 +4179,6 @@ def err_template_spec_default_arg : Error< def err_not_class_template_specialization : Error< "cannot specialize a %select{dependent template|template template " "parameter}0">; -def err_function_specialization_in_class : Error< - "cannot specialize a function %0 within class scope">; -def ext_function_specialization_in_class : ExtWarn< - "explicit specialization of %0 within class scope is a Microsoft extension">, - InGroup; def ext_explicit_specialization_storage_class : ExtWarn< "explicit specialization cannot have a storage class">; def err_explicit_specialization_inconsistent_storage_class : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5a681720d4..70c94949ba 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1849,8 +1849,8 @@ public: void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, - DeclarationName Name, - SourceLocation Loc); + DeclarationName Name, SourceLocation Loc, + bool IsTemplateId); void diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation FallbackLoc, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index e264d056e4..0ac29087d6 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1602,7 +1602,7 @@ void ASTDumper::VisitClassTemplatePartialSpecializationDecl( void ASTDumper::VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D) { - dumpDeclRef(D->getSpecialization()); + dumpDecl(D->getSpecialization()); if (D->hasExplicitTemplateArgs()) dumpTemplateArgumentListInfo(D->templateArgs()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index db598b05b3..612761177c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5231,10 +5231,13 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, /// /// \param Loc The location of the name of the entity being declared. /// +/// \param IsTemplateId Whether the name is a (simple-)template-id, and thus +/// we're declaring an explicit / partial specialization / instantiation. +/// /// \returns true if we cannot safely recover from this error, false otherwise. bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc, bool IsTemplateId) { DeclContext *Cur = CurContext; while (isa(Cur) || isa(Cur)) Cur = Cur->getParent(); @@ -5261,8 +5264,9 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, } // Check whether the qualifying scope encloses the scope of the original - // declaration. - if (!Cur->Encloses(DC)) { + // declaration. For a template-id, we perform the checks in + // CheckTemplateSpecializationScope. + if (!Cur->Encloses(DC) && !IsTemplateId) { if (Cur->isRecord()) Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); @@ -5374,8 +5378,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, return nullptr; } if (!D.getDeclSpec().isFriendSpecified()) { - if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, - Name, D.getIdentifierLoc())) { + if (diagnoseQualifiedDeclaration( + D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId)) { if (DC->isRecord()) return nullptr; @@ -8828,10 +8833,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; - Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? - diag::ext_function_specialization_in_class : - diag::err_function_specialization_in_class) - << NewFD->getDeclName(); } else if (!NewFD->isInvalidDecl() && CheckFunctionTemplateSpecialization( NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), @@ -9117,12 +9118,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Here we have an function template explicit specialization at class scope. - // The actually specialization will be postponed to template instatiation + // The actual specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, SourceLocation(), + Context, CurContext, NewFD->getLocation(), cast(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); @@ -9633,16 +9634,16 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Previous.clear(); Previous.addDecl(OldDecl); - if (FunctionTemplateDecl *OldTemplateDecl - = dyn_cast(OldDecl)) { + if (FunctionTemplateDecl *OldTemplateDecl = + dyn_cast(OldDecl)) { auto *OldFD = OldTemplateDecl->getTemplatedDecl(); NewFD->setPreviousDeclaration(OldFD); adjustDeclContextForDeclaratorDecl(NewFD, OldFD); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); - if (auto *Method = dyn_cast(NewFD)) { - Method->setAccess(OldTemplateDecl->getAccess()); + if (NewFD->isCXXClassMember()) { + NewFD->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } @@ -9668,7 +9669,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(OldFD); adjustDeclContextForDeclaratorDecl(NewFD, OldFD); - if (isa(NewFD)) + if (NewFD->isCXXClassMember()) NewFD->setAccess(OldFD->getAccess()); } } @@ -14310,13 +14311,10 @@ CreateNewDecl: if (SS.isNotEmpty()) { if (SS.isSet()) { // If this is either a declaration or a definition, check the - // nested-name-specifier against the current context. We don't do this - // for explicit specializations, because they have similar checking - // (with more specific diagnostics) in the call to - // CheckMemberSpecialization, below. - if (!isMemberSpecialization && - (TUK == TUK_Definition || TUK == TUK_Declaration) && - diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc)) + // nested-name-specifier against the current context. + if ((TUK == TUK_Definition || TUK == TUK_Declaration) && + diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc, + isMemberSpecialization)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9e3647548b..6160eccabe 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3051,7 +3051,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // int X::member; // }; if (DeclContext *DC = computeDeclContext(SS, false)) - diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc()); + diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc(), + D.getName().getKind() == + UnqualifiedIdKind::IK_TemplateId); else Diag(D.getIdentifierLoc(), diag::err_member_qualification) << Name << SS.getRange(); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 12a74c1b64..b5583d1395 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1262,7 +1262,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) Invalid = true; } else if (TUK != TUK_Friend && TUK != TUK_Reference) - diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc); + diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc, false); LookupQualifiedName(Previous, SemanticContext); } else { @@ -7124,120 +7124,43 @@ static bool CheckTemplateSpecializationScope(Sema &S, } // C++ [temp.expl.spec]p2: - // An explicit specialization shall be declared in the namespace - // of which the template is a member, or, for member templates, in - // the namespace of which the enclosing class or enclosing class - // template is a member. An explicit specialization of a member - // function, member class or static data member of a class - // template shall be declared in the namespace of which the class - // template is a member. Such a declaration may also be a - // definition. If the declaration is not a definition, the - // specialization may be defined later in the name- space in which - // the explicit specialization was declared, or in a namespace - // that encloses the one in which the explicit specialization was - // declared. + // An explicit specialization may be declared in any scope in which + // the corresponding primary template may be defined. if (S.CurContext->getRedeclContext()->isFunctionOrMethod()) { S.Diag(Loc, diag::err_template_spec_decl_function_scope) << Specialized; return true; } - if (S.CurContext->isRecord() && !IsPartialSpecialization) { - if (S.getLangOpts().MicrosoftExt) { - // Do not warn for class scope explicit specialization during - // instantiation, warning was already emitted during pattern - // semantic analysis. - if (!S.inTemplateInstantiation()) - S.Diag(Loc, diag::ext_function_specialization_in_class) - << Specialized; - } else { - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; - } - } - - if (S.CurContext->isRecord() && - !S.CurContext->Equals(Specialized->getDeclContext())) { - // Make sure that we're specializing in the right record context. - // Otherwise, things can go horribly wrong. - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; - } - // C++ [temp.class.spec]p6: - // A class template partial specialization may be declared or redeclared - // in any namespace scope in which its definition may be defined (14.5.1 - // and 14.5.2). - DeclContext *SpecializedContext - = Specialized->getDeclContext()->getEnclosingNamespaceContext(); - DeclContext *DC = S.CurContext->getEnclosingNamespaceContext(); - - // Make sure that this redeclaration (or definition) occurs in an enclosing - // namespace. - // Note that HandleDeclarator() performs this check for explicit - // specializations of function templates, static data members, and member - // functions, so we skip the check here for those kinds of entities. - // FIXME: HandleDeclarator's diagnostics aren't quite as good, though. - // Should we refactor that check, so that it occurs later? - if (!DC->Encloses(SpecializedContext) && - !(isa(Specialized) || - isa(Specialized) || - isa(Specialized) || - isa(Specialized))) { + // A class template partial specialization may be declared in any + // scope in which the primary template may be defined. + DeclContext *SpecializedContext = + Specialized->getDeclContext()->getRedeclContext(); + DeclContext *DC = S.CurContext->getRedeclContext(); + + // Make sure that this redeclaration (or definition) occurs in the same + // scope or an enclosing namespace. + if (!(DC->isFileContext() ? DC->Encloses(SpecializedContext) + : DC->Equals(SpecializedContext))) { if (isa(SpecializedContext)) S.Diag(Loc, diag::err_template_spec_redecl_global_scope) << EntityKind << Specialized; - else if (isa(SpecializedContext)) { + else { + auto *ND = cast(SpecializedContext); int Diag = diag::err_template_spec_redecl_out_of_scope; - if (S.getLangOpts().MicrosoftExt) + if (S.getLangOpts().MicrosoftExt && !DC->isRecord()) Diag = diag::ext_ms_template_spec_redecl_out_of_scope; S.Diag(Loc, Diag) << EntityKind << Specialized - << cast(SpecializedContext); - } else - llvm_unreachable("unexpected namespace context for specialization"); + << ND << isa(ND); + } S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } else if ((!PrevDecl || - getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared || - getTemplateSpecializationKind(PrevDecl) == - TSK_ImplicitInstantiation)) { - // C++ [temp.exp.spec]p2: - // An explicit specialization shall be declared in the namespace of which - // the template is a member, or, for member templates, in the namespace - // of which the enclosing class or enclosing class template is a member. - // An explicit specialization of a member function, member class or - // static data member of a class template shall be declared in the - // namespace of which the class template is a member. - // - // C++11 [temp.expl.spec]p2: - // An explicit specialization shall be declared in a namespace enclosing - // the specialized template. - // C++11 [temp.explicit]p3: - // An explicit instantiation shall appear in an enclosing namespace of its - // template. - if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) { - bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext); - if (isa(SpecializedContext)) { - assert(!IsCPlusPlus11Extension && - "DC encloses TU but isn't in enclosing namespace set"); - S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) - << EntityKind << Specialized; - } else if (isa(SpecializedContext)) { - int Diag; - if (!IsCPlusPlus11Extension) - Diag = diag::err_template_spec_decl_out_of_scope; - else if (!S.getLangOpts().CPlusPlus11) - Diag = diag::ext_template_spec_decl_out_of_scope; - else - Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope; - S.Diag(Loc, Diag) - << EntityKind << Specialized << cast(SpecializedContext); - } - S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } + // Don't allow specializing in the wrong class during error recovery. + // Otherwise, things can go horribly wrong. + if (DC->isRecord()) + return true; } return false; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index df11315cbe..6f04dedeed 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1653,6 +1653,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, NameInfo, T, TInfo, D->getSourceRange().getEnd()); if (DGuide->isCopyDeductionCandidate()) cast(Function)->setIsCopyDeductionCandidate(); + Function->setAccess(D->getAccess()); } else { Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, @@ -2711,6 +2712,8 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( assert(Specialization && "Class scope Specialization is null"); SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); + // FIXME: If this is a definition, check for redefinition errors! + return NewFD; } diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp index fbca6635ec..a311d8f339 100644 --- a/test/CXX/drs/dr0xx.cpp +++ b/test/CXX/drs/dr0xx.cpp @@ -499,10 +499,10 @@ namespace dr42 { // dr42: yes // dr43: na -namespace dr44 { // dr44: yes +namespace dr44 { // dr44: sup 727 struct A { template void f(); - template<> void f<0>(); // expected-error {{explicit specialization of 'f' in class scope}} + template<> void f<0>(); }; } diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp index 3342148461..0de2d495a3 100644 --- a/test/CXX/drs/dr3xx.cpp +++ b/test/CXX/drs/dr3xx.cpp @@ -925,7 +925,7 @@ namespace dr373 { // dr373: 5 using namespace A::B; // expected-error {{expected namespace name}} } -namespace dr374 { // dr374: yes c++11 +namespace dr374 { // dr374: yes namespace N { template void f(); template struct A { void f(); }; @@ -933,11 +933,6 @@ namespace dr374 { // dr374: yes c++11 template<> void N::f() {} template<> void N::A::f() {} template<> struct N::A {}; -#if __cplusplus < 201103L - // expected-error@-4 {{extension}} expected-note@-7 {{here}} - // expected-error@-4 {{extension}} expected-note@-7 {{here}} - // expected-error@-4 {{extension}} expected-note@-8 {{here}} -#endif } // dr375: dup 345 diff --git a/test/CXX/drs/dr7xx.cpp b/test/CXX/drs/dr7xx.cpp index fe4a2dc5ee..982ffdddab 100644 --- a/test/CXX/drs/dr7xx.cpp +++ b/test/CXX/drs/dr7xx.cpp @@ -3,6 +3,53 @@ // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +namespace dr727 { // dr727: 7 + struct A { + template struct C; // expected-note 6{{here}} + template void f(); // expected-note {{here}} + template static int N; // expected-error 0-1{{C++14}} expected-note 6{{here}} + + template<> struct C; + template<> void f(); + template<> static int N; + + template struct C; + template static int N; + + struct B { + template<> struct C; // expected-error {{not in class 'A' or an enclosing namespace}} + template<> void f(); // expected-error {{no function template matches}} + template<> static int N; // expected-error {{not in class 'A' or an enclosing namespace}} + + template struct C; // expected-error {{not in class 'A' or an enclosing namespace}} + template static int N; // expected-error {{not in class 'A' or an enclosing namespace}} + + template<> struct A::C; // expected-error {{not in class 'A' or an enclosing namespace}} + template<> void A::f(); // expected-error {{no function template matches}} expected-error {{cannot have a qualified name}} + template<> static int A::N; // expected-error {{not in class 'A' or an enclosing namespace}} expected-error {{cannot have a qualified name}} + + template struct A::C; // expected-error {{not in class 'A' or an enclosing namespace}} + template static int A::N; // expected-error {{not in class 'A' or an enclosing namespace}} expected-error {{cannot have a qualified name}} + }; + }; + + template<> struct A::C; + template<> void A::f(); + template<> int A::N; + + template struct A::C; + template int A::N; + + namespace C { + template<> struct A::C; // expected-error {{not in class 'A' or an enclosing namespace}} + template<> void A::f(); // expected-error {{not in class 'A' or an enclosing namespace}} + template<> int A::N; // expected-error {{not in class 'A' or an enclosing namespace}} + + template struct A::C; // expected-error {{not in class 'A' or an enclosing namespace}} + template int A::N; // expected-error {{not in class 'A' or an enclosing namespace}} + } +} + namespace dr777 { // dr777: 3.7 #if __cplusplus >= 201103L template @@ -16,5 +63,3 @@ template void h(int i = 0, T ...args, int j = 1) {} #endif } - -// expected-no-diagnostics diff --git a/test/CXX/temp/temp.deduct.guide/p1.cpp b/test/CXX/temp/temp.deduct.guide/p1.cpp index c0a2ba1129..8bb9da8a97 100644 --- a/test/CXX/temp/temp.deduct.guide/p1.cpp +++ b/test/CXX/temp/temp.deduct.guide/p1.cpp @@ -101,7 +101,7 @@ namespace ExplicitInst { struct X { template struct C {}; template C(T) -> C; - template<> C(int) -> C; // expected-error {{explicit specialization of '' in class scope}} + template<> C(int) -> C; // expected-error {{deduction guide cannot be explicitly specialized}} extern template C(float) -> C; // expected-error {{expected member name or ';'}} template C(char) -> C; // expected-error {{expected '<' after 'template'}} }; diff --git a/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp index 425d527e52..741ebc5de4 100644 --- a/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp +++ b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp @@ -28,10 +28,8 @@ T pi1 = T(3.1415926535897932385); // expected-note 0-2 {{here}} // Should recover as if specialization template float pi1 = 1.0; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} -#ifndef FIXING namespace expected_global { - template<> double pi1 = 1.5; // expected-error {{variable template specialization of 'pi1' must originally be declared in the global scope}} - template int pi1 = 10; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \ - expected-error {{variable template specialization of 'pi1' must originally be declared in the global scope}} -} +#ifndef FIXING + template int pi1 = 10; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} expected-error {{must occur at global scope}} #endif +} diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp index d0e24f5477..c29646dd94 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp @@ -10,9 +10,6 @@ struct NonDefaultConstructible { NonDefaultConstructible(int); }; -// FIXME: The "must originally be declared in namespace" diagnostics throughout -// this file are wrong. - // C++ [temp.expl.spec]p1: // An explicit specialization of any of the following: @@ -43,7 +40,7 @@ template<> void N0::f0(double) { } struct X1 { template void f(T); - template<> void f(int); // expected-error{{in class scope}} + template<> void f(int); // OK (DR727) }; // -- class template @@ -94,7 +91,7 @@ template<> struct N0::X0 { // -- variable template [C++1y] namespace N0 { -template int v0; // expected-note +{{here}} +template int v0; // expected-note 4{{explicitly specialized declaration is here}} template<> extern int v0; template<> extern int v0; template<> extern int v0; @@ -102,32 +99,32 @@ template<> extern int v0; } using N0::v0; -template int v1; // expected-note +{{here}} +template int v1; // expected-note 4{{explicitly specialized declaration is here}} template<> extern int v1; template<> extern int v1; template<> extern int v1; template<> extern int v1; template<> int N0::v0; -template<> int v0; // FIXME: ill-formed +template<> int v0; template<> int ::v1; // expected-warning {{extra qualification}} template<> int v1; template<> int N0::v0; -template<> int v0; // FIXME: ill-formed +template<> int v0; template<> int ::v1; // expected-warning {{extra qualification}} template<> int v1; namespace N1 { -template<> int N0::v0; // expected-error {{must originally be declared in namespace 'N0'}} expected-error {{does not enclose namespace}} -template<> int v0; // expected-error {{must originally be declared in namespace 'N0'}} -template<> int ::v1; // expected-error {{must originally be declared in the global scope}} expected-error {{cannot name the global scope}} -template<> int v1; // expected-error {{must originally be declared in the global scope}} - -template<> int N0::v0; // expected-error {{does not enclose namespace 'N0'}} -template<> int v0; // FIXME: ill-formed -template<> int ::v1; // expected-error {{cannot name the global scope}} -template<> int v1; // FIXME: ill-formed +template<> int N0::v0; // expected-error {{not in a namespace enclosing 'N0'}} +template<> int v0; // expected-error {{not in a namespace enclosing 'N0'}} +template<> int ::v1; // expected-error {{must occur at global scope}} +template<> int v1; // expected-error {{must occur at global scope}} + +template<> int N0::v0; // expected-error {{not in a namespace enclosing 'N0'}} +template<> int v0; // expected-error {{not in a namespace enclosing 'N0'}} +template<> int ::v1; // expected-error {{must occur at global scope}} +template<> int v1; // expected-error {{must occur at global scope}} } // -- member function of a class template diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp index 21399b6204..904f950df4 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp @@ -20,9 +20,6 @@ struct NonDefaultConstructible { // -- function template namespace N0 { template void f0(T) { -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif T t; } @@ -43,16 +40,13 @@ namespace N1 { } template<> void N0::f0(double); -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of function template specialization of 'f0' outside namespace 'N0' is a C++11 extension}} -#endif template<> void N0::f0(double) { } struct X1 { template void f(T); - template<> void f(int); // expected-error{{in class scope}} + template<> void f(int); }; // -- class template @@ -60,38 +54,20 @@ namespace N0 { template struct X0 { // expected-note {{explicitly specialized declaration is here}} -#if __cplusplus <= 199711L -// expected-note@-2 {{explicitly specialized declaration is here}} -#endif static T member; -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif void f1(T t) { -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif t = 17; } struct Inner : public T { }; // expected-note 2{{explicitly specialized declaration is here}} -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif template struct InnerTemplate : public T { }; // expected-note {{explicitly specialized declaration is here}} -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif - // expected-error@-4 {{base specifier must name a class}} + // expected-error@-1 {{base specifier must name a class}} template void ft1(T t, U u); -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif }; } @@ -105,9 +81,6 @@ void N0::X0::ft1(T t, U u) { template T N0::X0::member; template<> struct N0::X0 { }; -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of class template specialization of 'X0' outside namespace 'N0' is a C++11 extension}} -#endif N0::X0 test_X0; namespace N1 { @@ -124,9 +97,6 @@ template<> struct N0::X0 { // -- member function of a class template template<> void N0::X0::f1(void *) { } -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of member function specialization of 'f1' outside namespace 'N0' is a C++11 extension}} -#endif void test_spec(N0::X0 xvp, void *vp) { xvp.f1(vp); @@ -160,9 +130,6 @@ NonDefaultConstructible &get_static_member() { } template<> int N0::X0::member; -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of static data member specialization of 'member' outside namespace 'N0' is a C++11 extension}} -#endif template<> float N0::X0::member = 3.14f; @@ -191,9 +158,6 @@ namespace N0 { template<> struct N0::X0::Inner { }; -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of member class specialization of 'Inner' outside namespace 'N0' is a C++11 extension}} -#endif template<> struct N0::X0::Inner { }; @@ -233,9 +197,6 @@ struct N0::X0::InnerTemplate { }; // okay template<> template<> struct N0::X0::InnerTemplate { }; -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of class template specialization of 'InnerTemplate' outside namespace 'N0' is a C++11 extension}} -#endif namespace N1 { template<> template<> @@ -268,9 +229,6 @@ void N0::X0::ft1(void *, unsigned) { } // okay template<> template<> void N0::X0::ft1(void *, float) { } -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of function template specialization of 'ft1' outside namespace 'N0' is a C++11 extension}} -#endif namespace N1 { template<> template<> @@ -293,6 +251,6 @@ namespace PR8979 { template void f(Inner&); typedef Inner MyInner; - template<> void f(MyInner&); // expected-error{{cannot specialize a function 'f' within class scope}} + template<> void f(MyInner&); }; } diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp index d82691c7c8..ca55c54a5e 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp @@ -4,17 +4,9 @@ namespace N { template class X; // expected-note {{'N::X' declared here}} -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized declaration is here}} -#endif } -// TODO: Don't add a namespace qualifier to the template if it would trigger -// the warning about the specialization being outside of the namespace. template<> class X { /* ... */ }; // expected-error {{no template named 'X'; did you mean 'N::X'?}} -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of class template specialization of 'X' outside namespace 'N' is a C++11 extension}} -#endif namespace N { diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp index c689149af0..21ba7ec8da 100644 --- a/test/Misc/ast-dump-decl.cpp +++ b/test/Misc/ast-dump-decl.cpp @@ -360,7 +360,9 @@ class TestClassScopeFunctionSpecialization { template<> void foo(int a) { } }; // CHECK: ClassScopeFunctionSpecializationDecl -// CHECK-NEXT: CXXMethod{{.*}} 'foo' 'void (int)' +// CHECK-NEXT: CXXMethod{{.*}} foo 'void (int)' +// CHECK-NEXT: ParmVarDecl +// CHECK-NEXT: CompoundStmt // CHECK-NEXT: TemplateArgument{{.*}} 'int' namespace TestTemplateTypeParmDecl { diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index c605dcb912..55adb68d2e 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -489,7 +489,6 @@ void AfterClassBody() { namespace PR24246 { template struct A { template struct largest_type_select; - // expected-warning@+1 {{explicit specialization of 'largest_type_select' within class scope is a Microsoft extension}} template <> struct largest_type_select { blah x; // expected-error {{unknown type name 'blah'}} }; diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index 66f0f10f0f..04c4429368 100644 --- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -15,8 +15,8 @@ class A { template static CONST T right = 5; template CONST int right; // expected-error {{member 'right' declared as a template}} template CONST float right = 5; // expected-error {{member 'right' declared as a template}} - template<> static CONST int right = 7; // expected-error {{explicit specialization of 'right' in class scope}} - template<> static CONST float right; // expected-error {{explicit specialization of 'right' in class scope}} + template<> static CONST int right = 7; + template<> static CONST float right; template static CONST int right; // expected-error {{expected '<' after 'template'}} }; @@ -163,8 +163,8 @@ namespace constexpred { template constexpr int right; // expected-error {{member 'right' declared as a template}} \ // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}} template constexpr float right = 5; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}} - template<> static constexpr int right = 7; // expected-error {{explicit specialization of 'right' in class scope}} - template<> static constexpr float right; // expected-error {{explicit specialization of 'right' in class scope}} + template<> static constexpr int right = 7; + template<> static constexpr float right; // expected-error {{requires an initializer}} template static constexpr int right; // expected-error {{expected '<' after 'template'}} }; } diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp index a78548b6f1..ecd9593c67 100644 --- a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -409,7 +409,7 @@ namespace nested { #endif float f1 = pi1a; - template<> double pi1a = 5.2; // expected-error {{variable template specialization of 'pi1a' must originally be declared in namespace 'n1'}} + template<> double pi1a = 5.2; // expected-error {{not in a namespace enclosing 'n1'}} double d1 = pi1a; } @@ -422,8 +422,7 @@ namespace nested { #endif float f1 = n1::pi1b; - template<> double n1::pi1b = 5.2; // expected-error {{cannot define or redeclare 'pi1b' here because namespace 'use_n1b' does not enclose namespace 'n1'}} \ - // expected-error {{variable template specialization of 'pi1b' must originally be declared in namespace 'n1'}} + template<> double n1::pi1b = 5.2; // expected-error {{not in a namespace enclosing 'n1'}} double d1 = n1::pi1b; } } diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 4a9baf5100..33516f7068 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -185,9 +185,9 @@ namespace RedundantParensInAddressTemplateParam { } namespace TemplateSpecOutOfScopeNs { - template struct S {}; // expected-note {{here}} + template struct S {}; } -template<> struct TemplateSpecOutOfScopeNs::S {}; // expected-warning {{class template specialization of 'S' outside namespace 'TemplateSpecOutOfScopeNs' is incompatible with C++98}} +template<> struct TemplateSpecOutOfScopeNs::S {}; struct Typename { template struct Inner {}; diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index 00e03ef61e..d763944371 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -78,9 +78,6 @@ template<> struct ::A; namespace N { template struct B; // expected-note {{explicitly specialized}} -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized}} -#endif template<> struct ::N::B; // okay template<> struct ::N::B; // okay @@ -92,9 +89,6 @@ namespace N { template<> struct N::B { }; // okay template<> struct N::B { }; -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of class template specialization of 'B' outside namespace 'N' is a C++11 extension}} -#endif namespace M { @@ -121,9 +115,9 @@ class Wibble { }; // expected-error{{cannot specialize a template template namespace rdar9676205 { template - struct X { + struct X { // expected-note {{here}} template - struct X { // expected-error{{explicit specialization of 'X' in class scope}} + struct X { // expected-error{{partial specialization of 'X' not in a namespace enclosing}} }; }; diff --git a/test/SemaTemplate/ext_ms_template_spec.cpp b/test/SemaTemplate/ext_ms_template_spec.cpp index fc2ed16f9f..cb303217ea 100644 --- a/test/SemaTemplate/ext_ms_template_spec.cpp +++ b/test/SemaTemplate/ext_ms_template_spec.cpp @@ -18,16 +18,16 @@ template struct X { namespace B { template <> -class A::ClassTemplate; // expected-warning {{class template specialization of 'ClassTemplate' outside namespace enclosing 'A' is a Microsoft extension}} +class A::ClassTemplate; // expected-warning {{class template specialization of 'ClassTemplate' not in a namespace enclosing 'A' is a Microsoft extension}} template -class A::ClassTemplatePartial {}; // expected-warning {{class template partial specialization of 'ClassTemplatePartial' outside namespace enclosing 'A' is a Microsoft extension}} +class A::ClassTemplatePartial {}; // expected-warning {{class template partial specialization of 'ClassTemplatePartial' not in a namespace enclosing 'A' is a Microsoft extension}} template <> -struct A::X::MemberClass; // expected-warning {{member class specialization of 'MemberClass' outside namespace enclosing 'A' is a Microsoft extension}} +struct A::X::MemberClass; // expected-warning {{member class specialization of 'MemberClass' not in class 'X' or an enclosing namespace is a Microsoft extension}} template <> -enum A::X::MemberEnumeration; // expected-warning {{member enumeration specialization of 'MemberEnumeration' outside namespace enclosing 'A' is a Microsoft extension}} // expected-error {{ISO C++ forbids forward references to 'enum' types}} +enum A::X::MemberEnumeration; // expected-warning {{member enumeration specialization of 'MemberEnumeration' not in class 'X' or an enclosing namespace is a Microsoft extension}} // expected-error {{ISO C++ forbids forward references to 'enum' types}} } diff --git a/test/SemaTemplate/function-template-specialization.cpp b/test/SemaTemplate/function-template-specialization.cpp index 6327ff64c3..a3669fd7fd 100644 --- a/test/SemaTemplate/function-template-specialization.cpp +++ b/test/SemaTemplate/function-template-specialization.cpp @@ -54,5 +54,5 @@ class Foo { // Don't crash here. template<> - static void Bar(const long& input) {} // expected-error{{explicit specialization of 'Bar' in class scope}} + static void Bar(const long& input) {} // expected-warning{{explicit specialization cannot have a storage class}} }; diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index 961884417b..9cd668dacf 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -185,7 +185,7 @@ namespace SameSignatureAfterInstantiation { namespace PR22040 { template struct Foobar { - template <> void bazqux(typename T::type) {} // expected-error {{cannot specialize a function 'bazqux' within class scope}} expected-error 2{{cannot be used prior to '::' because it has no members}} + template <> void bazqux(typename T::type) {} // expected-error 2{{cannot be used prior to '::' because it has no members}} }; void test() { diff --git a/test/SemaTemplate/ms-function-specialization-class-scope.cpp b/test/SemaTemplate/ms-function-specialization-class-scope.cpp index 3c7111d058..dcab9bfaea 100644 --- a/test/SemaTemplate/ms-function-specialization-class-scope.cpp +++ b/test/SemaTemplate/ms-function-specialization-class-scope.cpp @@ -1,18 +1,15 @@ // RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s // RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s +// expected-no-diagnostics class A { public: template A(U p) {} - template<> A(int p) { - // expected-warning@-1 {{explicit specialization of 'A' within class scope is a Microsoft extension}} - } + template<> A(int p) {} template void f(U p) {} - template<> void f(int p) { - // expected-warning@-1 {{explicit specialization of 'f' within class scope is a Microsoft extension}} - } + template<> void f(int p) {} void f(int p) {} }; @@ -28,14 +25,11 @@ void test1() { template class B { public: template B(U p) {} - template<> B(int p) { - // expected-warning@-1 {{explicit specialization of 'B' within class scope is a Microsoft extension}} - } + template<> B(int p) {} template void f(U p) { T y = 9; } template<> void f(int p) { - // expected-warning@-1 {{explicit specialization of 'f' within class scope is a Microsoft extension}} T a = 3; } @@ -56,9 +50,7 @@ namespace PR12709 { template void specialized_member_template() {} - template<> void specialized_member_template() { - // expected-warning@-1 {{explicit specialization of 'specialized_member_template' within class scope is a Microsoft extension}} - } + template<> void specialized_member_template() {} }; void f() { TemplateClass t; } @@ -67,8 +59,8 @@ namespace PR12709 { namespace Duplicates { template struct A { template void f(); - template<> void f() {} // expected-warning {{Microsoft extension}} - template<> void f() {} // expected-warning {{Microsoft extension}} + template<> void f() {} + template<> void f() {} }; // FIXME: We should diagnose the duplicate explicit specialization definitions @@ -81,6 +73,6 @@ struct S { template int f(int = 0); template <> - int f<0>(int); // expected-warning {{Microsoft extension}} + int f<0>(int); }; } diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp index 6366a528ff..7465e5e8ca 100644 --- a/test/SemaTemplate/temp_class_spec_neg.cpp +++ b/test/SemaTemplate/temp_class_spec_neg.cpp @@ -7,17 +7,11 @@ template struct vector; namespace N { namespace M { template struct A; -#if __cplusplus <= 199711L // C++03 or earlier modes - // expected-note@-2{{explicitly specialized declaration is here}} -#endif } } template struct N::M::A { }; -#if __cplusplus <= 199711L -// expected-warning@-2{{first declaration of class template partial specialization of 'A' outside namespace 'M' is a C++11 extension}} -#endif // C++ [temp.class.spec]p9 // bullet 1, as amended by DR1315 diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index 6afb978978..c5a8ac87c9 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -303,7 +303,7 @@ 44 CD1 Member specializations - Yes + Superseded by 727 45 @@ -2285,7 +2285,7 @@ of class templates 374 CD2 Can explicit specialization outside namespace use qualified name? - Yes (C++11 onwards) + Yes 375 @@ -4387,7 +4387,7 @@ and POD class 727 C++17 In-class explicit specializations - Unknown + SVN 728