diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6108259d97cf0f..a26e14b64b33d5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5423,9 +5423,6 @@ def err_not_class_template_specialization : Error< "parameter}0">; def ext_explicit_specialization_storage_class : ExtWarn< "explicit specialization cannot have a storage class">, InGroup; -def err_explicit_specialization_inconsistent_storage_class : Error< - "explicit specialization has extraneous, inconsistent storage class " - "'%select{none|extern|static|__private_extern__|auto|register}0'">; def err_dependent_function_template_spec_no_match : Error< "no candidate function template was found for dependent" " %select{member|friend}0 function template specialization">; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 6f2ce48a0c8955..6f0f5a0311bc18 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3317,7 +3317,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( DeclSpec::SCS_static && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - !DS.isFriendSpecified()) { + !DS.isFriendSpecified() && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate) { // It's a default member initializer. if (BitfieldSize.get()) Diag(Tok, getLangOpts().CPlusPlus20 @@ -3416,7 +3417,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( } else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid()); - } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) + } else if (ThisDecl && DeclaratorInfo.isStaticMember()) // No initializer. Actions.ActOnUninitializedDecl(ThisDecl); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 66448935a1baaf..12d2d3f6060c63 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -418,6 +418,7 @@ bool Declarator::isDeclarationOfFunction() const { bool Declarator::isStaticMember() { assert(getContext() == DeclaratorContext::Member); return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || + (!isDeclarationOfFunction() && !getTemplateParameterLists().empty()) || (getName().getKind() == UnqualifiedIdKind::IK_OperatorFunctionId && CXXMethodDecl::isStaticOverloadedOperator( getName().OperatorFunctionId.Operator)); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 30f63b472677a3..31bf50a32a83c3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7494,80 +7494,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( NTCUC_AutoVar, NTCUK_Destruct); } else { bool Invalid = false; - - if (DC->isRecord() && !CurContext->isRecord()) { - // This is an out-of-line definition of a static data member. - switch (SC) { - case SC_None: - break; - case SC_Static: - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_out_of_line) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - break; - case SC_Auto: - case SC_Register: - case SC_Extern: - // [dcl.stc] p2: The auto or register specifiers shall be applied only - // to names of variables declared in a block or to function parameters. - // [dcl.stc] p6: The extern specifier cannot be used in the declaration - // of class members - - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_storage_class_for_static_member) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - break; - case SC_PrivateExtern: - llvm_unreachable("C storage class in c++!"); - } - } - - if (SC == SC_Static && CurContext->isRecord()) { - if (const CXXRecordDecl *RD = dyn_cast(DC)) { - // Walk up the enclosing DeclContexts to check for any that are - // incompatible with static data members. - const DeclContext *FunctionOrMethod = nullptr; - const CXXRecordDecl *AnonStruct = nullptr; - for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) { - if (Ctxt->isFunctionOrMethod()) { - FunctionOrMethod = Ctxt; - break; - } - const CXXRecordDecl *ParentDecl = dyn_cast(Ctxt); - if (ParentDecl && !ParentDecl->getDeclName()) { - AnonStruct = ParentDecl; - break; - } - } - if (FunctionOrMethod) { - // C++ [class.static.data]p5: A local class shall not have static data - // members. - Diag(D.getIdentifierLoc(), - diag::err_static_data_member_not_allowed_in_local_class) - << Name << RD->getDeclName() - << llvm::to_underlying(RD->getTagKind()); - } else if (AnonStruct) { - // C++ [class.static.data]p4: Unnamed classes and classes contained - // directly or indirectly within unnamed classes shall not contain - // static data members. - Diag(D.getIdentifierLoc(), - diag::err_static_data_member_not_allowed_in_anon_struct) - << Name << llvm::to_underlying(AnonStruct->getTagKind()); - Invalid = true; - } else if (RD->isUnion()) { - // C++98 [class.union]p1: If a union contains a static data member, - // the program is ill-formed. C++11 drops this restriction. - Diag(D.getIdentifierLoc(), - getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_static_data_member_in_union - : diag::ext_static_data_member_in_union) << Name; - } - } - } - // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. - bool InvalidScope = false; TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), D.getCXXScopeSpec(), @@ -7575,8 +7503,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( ? D.getName().TemplateId : nullptr, TemplateParamLists, - /*never a friend*/ false, IsMemberSpecialization, InvalidScope); - Invalid |= InvalidScope; + /*never a friend*/ false, IsMemberSpecialization, Invalid); if (TemplateParams) { if (DC->isDependentContext()) { @@ -7625,6 +7552,102 @@ NamedDecl *Sema::ActOnVariableDeclarator( "should have a 'template<>' for this decl"); } + bool IsExplicitSpecialization = + IsVariableTemplateSpecialization && !IsPartialSpecialization; + + // C++ [temp.expl.spec]p2: + // The declaration in an explicit-specialization shall not be an + // export-declaration. An explicit specialization shall not use a + // storage-class-specifier other than thread_local. + // + // We use the storage-class-specifier from DeclSpec because we may have + // added implicit 'extern' for declarations with __declspec(dllimport)! + if (SCSpec != DeclSpec::SCS_unspecified && + (IsExplicitSpecialization || IsMemberSpecialization)) { + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::ext_explicit_specialization_storage_class) + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + } + + if (CurContext->isRecord()) { + if (SC == SC_Static) { + if (const CXXRecordDecl *RD = dyn_cast(DC)) { + // Walk up the enclosing DeclContexts to check for any that are + // incompatible with static data members. + const DeclContext *FunctionOrMethod = nullptr; + const CXXRecordDecl *AnonStruct = nullptr; + for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) { + if (Ctxt->isFunctionOrMethod()) { + FunctionOrMethod = Ctxt; + break; + } + const CXXRecordDecl *ParentDecl = dyn_cast(Ctxt); + if (ParentDecl && !ParentDecl->getDeclName()) { + AnonStruct = ParentDecl; + break; + } + } + if (FunctionOrMethod) { + // C++ [class.static.data]p5: A local class shall not have static + // data members. + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_local_class) + << Name << RD->getDeclName() + << llvm::to_underlying(RD->getTagKind()); + } else if (AnonStruct) { + // C++ [class.static.data]p4: Unnamed classes and classes contained + // directly or indirectly within unnamed classes shall not contain + // static data members. + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_anon_struct) + << Name << llvm::to_underlying(AnonStruct->getTagKind()); + Invalid = true; + } else if (RD->isUnion()) { + // C++98 [class.union]p1: If a union contains a static data member, + // the program is ill-formed. C++11 drops this restriction. + Diag(D.getIdentifierLoc(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_static_data_member_in_union + : diag::ext_static_data_member_in_union) + << Name; + } + } + } else if (IsVariableTemplate || IsPartialSpecialization) { + // There is no such thing as a member field template. + Diag(D.getIdentifierLoc(), diag::err_template_member) + << II << TemplateParams->getSourceRange(); + // Recover by pretending this is a static data member template. + SC = SC_Static; + } + } else if (DC->isRecord()) { + // This is an out-of-line definition of a static data member. + switch (SC) { + case SC_None: + break; + case SC_Static: + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << FixItHint::CreateRemoval( + D.getDeclSpec().getStorageClassSpecLoc()); + break; + case SC_Auto: + case SC_Register: + case SC_Extern: + // [dcl.stc] p2: The auto or register specifiers shall be applied only + // to names of variables declared in a block or to function parameters. + // [dcl.stc] p6: The extern specifier cannot be used in the declaration + // of class members + + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_storage_class_for_static_member) + << FixItHint::CreateRemoval( + D.getDeclSpec().getStorageClassSpecLoc()); + break; + case SC_PrivateExtern: + llvm_unreachable("C storage class in c++!"); + } + } + if (IsVariableTemplateSpecialization) { SourceLocation TemplateKWLoc = TemplateParamLists.size() > 0 @@ -7670,8 +7693,6 @@ NamedDecl *Sema::ActOnVariableDeclarator( // the variable (matching the scope specifier), store them. // An explicit variable template specialization does not own any template // parameter lists. - bool IsExplicitSpecialization = - IsVariableTemplateSpecialization && !IsPartialSpecialization; unsigned VDTemplateParamLists = (TemplateParams && !IsExplicitSpecialization) ? 1 : 0; if (TemplateParamLists.size() > VDTemplateParamLists) @@ -10073,25 +10094,45 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setImplicitlyInline(ImplicitInlineCXX20); } - if (SC == SC_Static && isa(NewFD) && - !CurContext->isRecord()) { - // C++ [class.static]p1: - // A data or function member of a class may be declared static - // in a class definition, in which case it is a static member of - // the class. + if (!isFriend && SC != SC_None) { + // C++ [temp.expl.spec]p2: + // The declaration in an explicit-specialization shall not be an + // export-declaration. An explicit specialization shall not use a + // storage-class-specifier other than thread_local. + // + // We diagnose friend declarations with storage-class-specifiers + // elsewhere. + if (isFunctionTemplateSpecialization || isMemberSpecialization) { + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::ext_explicit_specialization_storage_class) + << FixItHint::CreateRemoval( + D.getDeclSpec().getStorageClassSpecLoc()); + } - // Complain about the 'static' specifier if it's on an out-of-line - // member function definition. + if (SC == SC_Static && !CurContext->isRecord() && DC->isRecord()) { + assert(isa(NewFD) && + "Out-of-line member function should be a CXXMethodDecl"); + // C++ [class.static]p1: + // A data or function member of a class may be declared static + // in a class definition, in which case it is a static member of + // the class. - // MSVC permits the use of a 'static' storage specifier on an out-of-line - // member function template declaration and class member template - // declaration (MSVC versions before 2015), warn about this. - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - ((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && - cast(DC)->getDescribedClassTemplate()) || - (getLangOpts().MSVCCompat && NewFD->getDescribedFunctionTemplate())) - ? diag::ext_static_out_of_line : diag::err_static_out_of_line) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + // Complain about the 'static' specifier if it's on an out-of-line + // member function definition. + + // MSVC permits the use of a 'static' storage specifier on an + // out-of-line member function template declaration and class member + // template declaration (MSVC versions before 2015), warn about this. + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + ((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && + cast(DC)->getDescribedClassTemplate()) || + (getLangOpts().MSVCCompat && + NewFD->getDescribedFunctionTemplate())) + ? diag::ext_static_out_of_line + : diag::err_static_out_of_line) + << FixItHint::CreateRemoval( + D.getDeclSpec().getStorageClassSpecLoc()); + } } // C++11 [except.spec]p15: @@ -10459,27 +10500,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Previous)) NewFD->setInvalidDecl(); } - - // C++ [dcl.stc]p1: - // A storage-class-specifier shall not be specified in an explicit - // specialization (14.7.3) - // FIXME: We should be checking this for dependent specializations. - FunctionTemplateSpecializationInfo *Info = - NewFD->getTemplateSpecializationInfo(); - if (Info && SC != SC_None) { - if (SC != Info->getTemplate()->getTemplatedDecl()->getStorageClass()) - Diag(NewFD->getLocation(), - diag::err_explicit_specialization_inconsistent_storage_class) - << SC - << FixItHint::CreateRemoval( - D.getDeclSpec().getStorageClassSpecLoc()); - - else - Diag(NewFD->getLocation(), - diag::ext_explicit_specialization_storage_class) - << FixItHint::CreateRemoval( - D.getDeclSpec().getStorageClassSpecLoc()); - } } else if (isMemberSpecialization && !FunctionTemplate) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index daaa55e4513898..aa08c4772d9131 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3413,9 +3413,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, break; } - bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified || - DS.getStorageClassSpec() == DeclSpec::SCS_mutable) && - !isFunc); + bool isInstField = (DS.getStorageClassSpec() == DeclSpec::SCS_unspecified || + DS.getStorageClassSpec() == DeclSpec::SCS_mutable) && + !isFunc && TemplateParameterLists.empty(); if (DS.hasConstexprSpecifier() && isInstField) { SemaDiagnosticBuilder B = @@ -3464,28 +3464,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } IdentifierInfo *II = Name.getAsIdentifierInfo(); - - // Member field could not be with "template" keyword. - // So TemplateParameterLists should be empty in this case. - if (TemplateParameterLists.size()) { - TemplateParameterList* TemplateParams = TemplateParameterLists[0]; - if (TemplateParams->size()) { - // There is no such thing as a member field template. - Diag(D.getIdentifierLoc(), diag::err_template_member) - << II - << SourceRange(TemplateParams->getTemplateLoc(), - TemplateParams->getRAngleLoc()); - } else { - // There is an extraneous 'template<>' for this member. - Diag(TemplateParams->getTemplateLoc(), - diag::err_template_member_noparams) - << II - << SourceRange(TemplateParams->getTemplateLoc(), - TemplateParams->getRAngleLoc()); - } - return nullptr; - } - if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) { Diag(D.getIdentifierLoc(), diag::err_member_with_template_arguments) << II diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp index cbb439ef5fecde..f6b5d2487e73d0 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp @@ -7,7 +7,7 @@ template void f(T) {} template static void g(T) {} -template<> static void f(int); // expected-error{{explicit specialization has extraneous, inconsistent storage class 'static'}} +template<> static void f(int); // expected-warning{{explicit specialization cannot have a storage class}} template static void f(float); // expected-error{{explicit instantiation cannot have a storage class}} template<> void f(double); @@ -29,4 +29,5 @@ int X::value = 17; template static int X::value; // expected-error{{explicit instantiation cannot have a storage class}} -template<> static int X::value; // expected-error{{'static' can only be specified inside the class definition}} +template<> static int X::value; // expected-warning{{explicit specialization cannot have a storage class}} + // expected-error@-1{{'static' can only be specified inside the class definition}} diff --git a/clang/test/CXX/drs/cwg7xx.cpp b/clang/test/CXX/drs/cwg7xx.cpp index 04650e9e1120b3..507eb8fb714350 100644 --- a/clang/test/CXX/drs/cwg7xx.cpp +++ b/clang/test/CXX/drs/cwg7xx.cpp @@ -107,7 +107,7 @@ namespace cwg727 { // cwg727: partial template<> struct C; template<> void f(); - template<> static int N; + template<> int N; template struct C; template static int N; @@ -118,7 +118,7 @@ namespace cwg727 { // cwg727: partial // expected-note@#cwg727-C {{explicitly specialized declaration is here}} template<> void f(); // expected-error@-1 {{no function template matches function template specialization 'f'}} - template<> static int N; + template<> int N; // expected-error@-1 {{variable template specialization of 'N' not in class 'A' or an enclosing namespace}} // expected-note@#cwg727-N {{explicitly specialized declaration is here}} @@ -136,7 +136,7 @@ namespace cwg727 { // cwg727: partial template<> void A::f(); // expected-error@-1 {{o function template matches function template specialization 'f'}} // expected-error@-2 {{non-friend class member 'f' cannot have a qualified name}} - template<> static int A::N; + template<> int A::N; // expected-error@-1 {{non-friend class member 'N' cannot have a qualified name}} // expected-error@-2 {{variable template specialization of 'N' not in class 'A' or an enclosing namespace}} // expected-note@#cwg727-N {{explicitly specialized declaration is here}} @@ -193,7 +193,7 @@ namespace cwg727 { // cwg727: partial template<> struct C {}; template<> void f() {} - template<> static const int N; + template<> const int N; template struct C {}; template static const int N; @@ -235,18 +235,18 @@ namespace cwg727 { // cwg727: partial #if __cplusplus >= 201402L template struct B { template static const int u = 1; - template<> static const int u<0> = 2; // #cwg727-u0 + template<> const int u<0> = 2; // #cwg727-u0 // Note that in C++17 onwards, these are implicitly inline, and so the // initializer of v<0> is not instantiated with the declaration. In // C++14, v<0> is a non-defining declaration and its initializer is // instantiated with the class. template static constexpr int v = 1; - template<> static constexpr int v<0> = 2; // #cwg727-v0 + template<> constexpr int v<0> = 2; // #cwg727-v0 template static const inline int w = 1; // cxx14-error@-1 {{inline variables are a C++17 extension}} - template<> static const inline int w<0> = 2; + template<> const inline int w<0> = 2; // cxx14-error@-1 {{inline variables are a C++17 extension}} }; @@ -294,8 +294,8 @@ namespace cwg727 { // cwg727: partial template static int v1; // cxx98-11-error@-1 {{variable templates are a C++14 extension}} - template<> static int v1; // #cwg727-v1-T - template<> static int v1; + template<> int v1; // #cwg727-v1-T + template<> int v1; // expected-error@-1 {{duplicate member 'v1'}} // expected-note@#cwg727-Collision-int-int {{in instantiation of template class 'cwg727::Collision' requested here}} // expected-note@#cwg727-v1-T {{previous}} @@ -303,9 +303,9 @@ namespace cwg727 { // cwg727: partial template static inline int v2; // cxx98-11-error@-1 {{variable templates are a C++14 extension}} // cxx98-14-error@-2 {{inline variables are a C++17 extension}} - template<> static inline int v2; // #cwg727-v2-T - // cxx98-14-error@-1 {{inline variables are a C++17 extension}} - template<> static inline int v2; + template<> inline int v2; // #cwg727-v2-T + // cxx98-14-error@-1 {{inline variables are a C++17 extension}} + template<> inline int v2; // cxx98-14-error@-1 {{inline variables are a C++17 extension}} // expected-error@-2 {{duplicate member 'v2'}} // expected-note@#cwg727-v2-T {{previous declaration is here}} diff --git a/clang/test/CXX/temp/temp.decls/temp.mem/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.mem/p2.cpp index feeb362e34b402..2a74429bd72901 100644 --- a/clang/test/CXX/temp/temp.decls/temp.mem/p2.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.mem/p2.cpp @@ -9,6 +9,6 @@ void fun() { template void baz() {} // expected-error{{templates cannot be declared inside of a local class}} template void qux(); // expected-error{{templates cannot be declared inside of a local class}} template using corge = int; // expected-error{{templates cannot be declared inside of a local class}} - template static T grault; // expected-error{{static data member}} expected-error{{templates cannot be declared inside of a local class}} + template static T grault; // expected-error{{templates cannot be declared inside of a local class}} }; } diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 3c500c2c4dc4a7..16e668e971a214 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -408,7 +408,7 @@ namespace Specializations { template constexpr static int InnerVar = 0; template<> - constexpr static int InnerVar = 0; // expected-error{{explicit specialization contains unexpanded parameter pack 'Ts'}} + constexpr int InnerVar = 0; // expected-error{{explicit specialization contains unexpanded parameter pack 'Ts'}} template constexpr static int InnerVar = 0; // expected-error{{partial specialization contains unexpanded parameter pack 'Ts'}} #endif diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp index 1b039627a1d3a9..904058e71a7b81 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp @@ -1,12 +1,12 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template +template class A { template class B { void mf(); }; }; -template<> template<> class A::B; +template<> template<> class A::B; template<> template<> void A::B::mf(); template<> void A::B::mf(); // expected-error{{requires 'template<>'}} @@ -17,15 +17,15 @@ namespace test1 { static int bar; }; typedef A AA; - - template <> int AA::foo = 0; + + template <> int AA::foo = 0; int AA::bar = 1; // expected-error {{template specialization requires 'template<>'}} int A::bar = 2; // expected-error {{template specialization requires 'template<>'}} - template <> class A { + template <> class A { public: static int foo; - static int bar; + static int bar; }; typedef A AB; @@ -40,7 +40,8 @@ struct S { int j; // expected-error {{member 'j' cannot have template arguments}} static int k<12>; // expected-error {{template specialization requires 'template<>'}} \ - expected-error{{no variable template matches specialization}} + expected-error {{no variable template matches specialization}} \ + expected-warning {{explicit specialization cannot have a storage class}} void f<12>(); // expected-error {{template specialization requires 'template<>'}} \ // expected-error {{no function template matches function template specialization 'f'}} }; diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp index c29646dd945590..80fae707de0c48 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp @@ -24,7 +24,7 @@ namespace N0 { void test_f0(NonDefaultConstructible NDC) { f0(NDC); } - + template<> void f0(int); template<> void f0(long); } @@ -39,34 +39,34 @@ template<> void N0::f0(double) { } struct X1 { template void f(T); - + template<> void f(int); // OK (DR727) }; // -- class template namespace N0 { - + template struct X0 { // expected-note {{here}} static T member; - + void f1(T t) { t = 17; } - + struct Inner : public T { }; // expected-note 2{{here}} - + template struct InnerTemplate : public T { }; // expected-note 1{{explicitly specialized}} \ // expected-error{{base specifier}} - + template void ft1(T t, U u); }; } -template +template template void N0::X0::ft1(T t, U u) { t = u; @@ -85,35 +85,36 @@ namespace N0 { template<> struct X0; } -template<> struct N0::X0 { +template<> struct N0::X0 { void f1(void *); }; // -- variable template [C++1y] namespace N0 { template int v0; // expected-note 4{{explicitly specialized declaration is here}} -template<> extern int v0; -template<> extern int v0; -template<> extern int v0; -template<> extern int v0; +template<> int v0; // expected-note {{previous definition is here}} +template<> int v0; +template<> int v0; // expected-note {{previous definition is here}} +template<> int v0; } using N0::v0; 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 v1; // expected-note {{previous definition is here}} +template<> int v1; // expected-note {{previous definition is here}} +template<> int v1; // expected-note {{previous definition is here}} +template<> int v1; template<> int N0::v0; template<> int v0; template<> int ::v1; // expected-warning {{extra qualification}} template<> int v1; -template<> int N0::v0; +template<> int N0::v0; // expected-error {{redefinition of 'v0'}} template<> int v0; template<> int ::v1; // expected-warning {{extra qualification}} -template<> int v1; + // expected-error@-1 {{redefinition of 'v1'}} +template<> int v1; // expected-error {{redefinition of 'v1'}} namespace N1 { template<> int N0::v0; // expected-error {{not in a namespace enclosing 'N0'}} @@ -122,8 +123,10 @@ 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'}} + // expected-error@-1 {{redefinition of 'v0'}} template<> int v0; // expected-error {{not in a namespace enclosing 'N0'}} template<> int ::v1; // expected-error {{must occur at global scope}} + // expected-error@-1 {{redefinition of 'v1'}} template<> int v1; // expected-error {{must occur at global scope}} } @@ -147,13 +150,13 @@ void test_x0_cvvoid(N0::X0 x0, const volatile void *cvp) { // -- static data member of a class template namespace N0 { // This actually tests p15; the following is a declaration, not a definition. - template<> + template<> NonDefaultConstructible X0::member; - + template<> long X0::member = 17; template<> float X0::member; - + template<> double X0::member; } @@ -171,7 +174,7 @@ namespace N1 { // -- member class of a class template namespace N0 { - + template<> struct X0::Inner { }; @@ -213,7 +216,7 @@ namespace N0 { template<> template<> struct X0::InnerTemplate { }; - + template<> template<> struct X0::InnerTemplate; // expected-note{{forward declaration}} @@ -245,7 +248,7 @@ namespace N0 { template<> template<> void X0::ft1(void*, const void*) { } - + template<> template<> void X0::ft1(void *, int); @@ -279,7 +282,7 @@ namespace has_inline_namespaces { inline namespace inner { template void f(T&); - template + template struct X0 { struct MemberClass; @@ -330,10 +333,10 @@ template<> struct has_inline_namespaces::X0::MemberClass { }; template<> void has_inline_namespaces::X0::mem_func(); -template<> template +template<> template struct has_inline_namespaces::X0::MemberClassTemplate { }; -template<> template +template<> template void has_inline_namespaces::X0::mem_func_template(T&) { } template<> int has_inline_namespaces::X0::value = 13; diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-20.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-20.cpp index e2a763252056e7..935dd360847bc4 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-20.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-20.cpp @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s -// XFAIL: * template int x; diff --git a/clang/test/Modules/Inputs/redecl-templates/a.h b/clang/test/Modules/Inputs/redecl-templates/a.h index fd25fcf0768d2d..205483fc01f124 100644 --- a/clang/test/Modules/Inputs/redecl-templates/a.h +++ b/clang/test/Modules/Inputs/redecl-templates/a.h @@ -5,4 +5,4 @@ template constexpr void f(); template<> constexpr void f<1>(); template extern int v; -template<> extern int v<1>; +template<> int v<1>; diff --git a/clang/test/Modules/redecl-templates.cpp b/clang/test/Modules/redecl-templates.cpp index ee42dc9c6a84cf..3ebafb53dc3bc5 100644 --- a/clang/test/Modules/redecl-templates.cpp +++ b/clang/test/Modules/redecl-templates.cpp @@ -1,7 +1,6 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -x c++ -I %S/Inputs/redecl-templates %s -verify -std=c++14 // RUN: %clang_cc1 -x c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/redecl-templates %s -verify -std=c++14 -// expected-no-diagnostics template struct A {}; template using X = A; @@ -29,4 +28,7 @@ int &x = w<1>; // instantiation of this specialization. template<> struct A<1> {}; template<> constexpr void f<1>() {} -template<> int v<1>; +// Variable template explicit specializations are always definitions unless they +// are static data members declared without an initializer. +template<> int v<1>; // expected-error {{redefinition of 'v<1>'}} + // expected-note@Inputs/redecl-templates/a.h:8 {{previous definition is here}} diff --git a/clang/test/PCH/cxx-templates.h b/clang/test/PCH/cxx-templates.h index 95d684e4a92db4..8927fd55dcb836 100644 --- a/clang/test/PCH/cxx-templates.h +++ b/clang/test/PCH/cxx-templates.h @@ -49,7 +49,7 @@ struct Dep { int y = T::template my_templf(0); ovl(y); } - + void ovl(int); void ovl(float); }; @@ -67,7 +67,7 @@ template class UseBase { template class UseA : public UseBase { using UseBase::foo; - using typename UseBase::bar; + using typename UseBase::bar; }; template class Sub : public UseBase { }; @@ -95,7 +95,7 @@ template<> bool isInt<8>(int x) { template int __copy_streambufs_eof(_CharT); -class basic_streambuf +class basic_streambuf { void m() { } friend int __copy_streambufs_eof<>(int); @@ -174,7 +174,7 @@ struct S7 : S6 { }; namespace ZeroLengthExplicitTemplateArgs { template void h(); - struct Y { + struct Y { template void f(); }; @@ -417,11 +417,11 @@ namespace ClassScopeExplicitSpecializations { template struct B { template static const int v = 1; template static const int v = 2; - template<> static const int v = 3; + template<> const int v = 3; template static constexpr int w = 1; template static constexpr int w = 2; - template<> static constexpr int w = 3; + template<> constexpr int w = 3; }; template<> template constexpr int B<0>::v = 4; diff --git a/clang/test/PCH/cxx1y-variable-templates.cpp b/clang/test/PCH/cxx1y-variable-templates.cpp index faa9b3df22c1c3..9063b6ee869384 100644 --- a/clang/test/PCH/cxx1y-variable-templates.cpp +++ b/clang/test/PCH/cxx1y-variable-templates.cpp @@ -67,11 +67,15 @@ namespace spec { namespace spec_join1 { template T va = T(10); - template<> extern float va; +#ifdef ERROR + template<> float va; // expected-note {{previous definition is here}} +#endif extern template int va; template T vb = T(10); - template<> extern float vb; +#ifdef ERROR + template<> float vb; // expected-note {{previous definition is here}} +#endif template T vc = T(10); @@ -102,15 +106,19 @@ namespace join { namespace spec_join1 { template extern T va; - template<> float va = 1.5; +#ifdef ERROR + template<> float va = 1.5; // expected-error {{redefinition of 'va'}} +#endif extern template int va; - - template<> float vb = 1.5; + +#ifdef ERROR + template<> float vb = 1.5; // expected-error {{redefinition of 'vb'}} +#endif template int vb; template<> float vc = 1.5; template int vc; - + template extern T vd; template T* vd = new T(); } @@ -123,9 +131,9 @@ namespace spec_join1 { template int var0a; float fvara = var0a; -template extern T var0a; +template extern T var0a; -template T var0b = T(); +template T var0b = T(); template int var0b; float fvarb = var0b; diff --git a/clang/test/SemaTemplate/explicit-specialization-member.cpp b/clang/test/SemaTemplate/explicit-specialization-member.cpp index 5dc8118556d421..c406fb3e21d40b 100644 --- a/clang/test/SemaTemplate/explicit-specialization-member.cpp +++ b/clang/test/SemaTemplate/explicit-specialization-member.cpp @@ -2,7 +2,7 @@ template struct X0 { typedef T* type; - + void f0(T); void f1(type); }; @@ -71,13 +71,13 @@ namespace PR41607 { }; template static int a; - template<> static constexpr int a<> = N; + template<> constexpr int a<> = N; template static inline int b; - template<> static inline constexpr int b<> = N; + template<> inline constexpr int b<> = N; template static constexpr int f(); - template<> static constexpr int f() { + template<> constexpr int f() { return N; } }; diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp index c896ca0afb670f..a54992a3971878 100644 --- a/clang/test/SemaTemplate/nested-template.cpp +++ b/clang/test/SemaTemplate/nested-template.cpp @@ -1,10 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// XFAIL: * class A; class S { public: - template struct A { + template struct A { struct Nested { typedef T type; }; @@ -18,15 +17,15 @@ template struct Outer { template class Inner0; - + template class Inner1 { struct ReallyInner; - + T foo(U); template T bar(V); template T* bar(V); - + static T value1; static U value2; }; @@ -48,7 +47,7 @@ template template struct Outer::Inner1::ReallyInner { static Y value3; - + void g(X, Y); }; @@ -131,7 +130,7 @@ namespace PR10896 { public: void foo() {} private: - + template T SomeField; // expected-error {{non-static data member 'SomeField' cannot be declared as a template}} template<> int SomeField2; // expected-error {{extraneous 'template<>' in declaration of variable 'SomeField2'}}