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).

llvm-svn: 327705
This commit is contained in:
Richard Smith 2018-03-16 13:36:56 +00:00
parent 8dcf6fa308
commit c660c8f5d2
27 changed files with 155 additions and 291 deletions

View File

@ -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<CXX11>;
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<CXX98Compat>, 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<MicrosoftTemplate>;
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<MicrosoftTemplate>;
def ext_explicit_specialization_storage_class : ExtWarn<
"explicit specialization cannot have a storage class">;
def err_explicit_specialization_inconsistent_storage_class : Error<

View File

@ -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,

View File

@ -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());
}

View File

@ -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<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(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<CXXMethodDecl>(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<FunctionTemplateDecl>(OldDecl)) {
if (FunctionTemplateDecl *OldTemplateDecl =
dyn_cast<FunctionTemplateDecl>(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<CXXMethodDecl>(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<CXXMethodDecl>(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));

View File

@ -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();

View File

@ -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();
// 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 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<FunctionTemplateDecl>(Specialized) ||
isa<FunctionDecl>(Specialized) ||
isa<VarTemplateDecl>(Specialized) ||
isa<VarDecl>(Specialized))) {
// 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<TranslationUnitDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
<< EntityKind << Specialized;
else if (isa<NamespaceDecl>(SpecializedContext)) {
else {
auto *ND = cast<NamedDecl>(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<NamedDecl>(SpecializedContext);
} else
llvm_unreachable("unexpected namespace context for specialization");
<< ND << isa<CXXRecordDecl>(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<TranslationUnitDecl>(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<NamespaceDecl>(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<NamedDecl>(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;

View File

@ -1653,6 +1653,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
NameInfo, T, TInfo, D->getSourceRange().getEnd());
if (DGuide->isCopyDeductionCandidate())
cast<CXXDeductionGuideDecl>(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;
}

View File

@ -499,10 +499,10 @@ namespace dr42 { // dr42: yes
// dr43: na
namespace dr44 { // dr44: yes
namespace dr44 { // dr44: sup 727
struct A {
template<int> void f();
template<> void f<0>(); // expected-error {{explicit specialization of 'f' in class scope}}
template<> void f<0>();
};
}

View File

@ -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<typename T> void f();
template<typename T> struct A { void f(); };
@ -933,11 +933,6 @@ namespace dr374 { // dr374: yes c++11
template<> void N::f<char>() {}
template<> void N::A<char>::f() {}
template<> struct N::A<int> {};
#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

View File

@ -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<typename T> struct C; // expected-note 6{{here}}
template<typename T> void f(); // expected-note {{here}}
template<typename T> static int N; // expected-error 0-1{{C++14}} expected-note 6{{here}}
template<> struct C<int>;
template<> void f<int>();
template<> static int N<int>;
template<typename T> struct C<T*>;
template<typename T> static int N<T*>;
struct B {
template<> struct C<float>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<> void f<float>(); // expected-error {{no function template matches}}
template<> static int N<float>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<typename T> struct C<T**>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<typename T> static int N<T**>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<> struct A::C<double>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<> void A::f<double>(); // expected-error {{no function template matches}} expected-error {{cannot have a qualified name}}
template<> static int A::N<double>; // expected-error {{not in class 'A' or an enclosing namespace}} expected-error {{cannot have a qualified name}}
template<typename T> struct A::C<T***>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<typename T> static int A::N<T***>; // expected-error {{not in class 'A' or an enclosing namespace}} expected-error {{cannot have a qualified name}}
};
};
template<> struct A::C<char>;
template<> void A::f<char>();
template<> int A::N<char>;
template<typename T> struct A::C<T****>;
template<typename T> int A::N<T****>;
namespace C {
template<> struct A::C<long>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<> void A::f<long>(); // expected-error {{not in class 'A' or an enclosing namespace}}
template<> int A::N<long>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<typename T> struct A::C<T*****>; // expected-error {{not in class 'A' or an enclosing namespace}}
template<typename T> int A::N<T*****>; // expected-error {{not in class 'A' or an enclosing namespace}}
}
}
namespace dr777 { // dr777: 3.7
#if __cplusplus >= 201103L
template <typename... T>
@ -16,5 +63,3 @@ template <typename... T>
void h(int i = 0, T ...args, int j = 1) {}
#endif
}
// expected-no-diagnostics

View File

@ -101,7 +101,7 @@ namespace ExplicitInst {
struct X {
template<typename T> struct C {};
template<typename T> C(T) -> C<T>;
template<> C(int) -> C<int>; // expected-error {{explicit specialization of '<deduction guide for C>' in class scope}}
template<> C(int) -> C<int>; // expected-error {{deduction guide cannot be explicitly specialized}}
extern template C(float) -> C<float>; // expected-error {{expected member name or ';'}}
template C(char) -> C<char>; // expected-error {{expected '<' after 'template'}}
};

View File

@ -28,10 +28,8 @@ T pi1 = T(3.1415926535897932385); // expected-note 0-2 {{here}}
// Should recover as if specialization
template float pi1<float> = 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<double> = 1.5; // expected-error {{variable template specialization of 'pi1' must originally be declared in the global scope}}
template int pi1<int> = 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<int> = 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
}

View File

@ -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<typename T> 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<volatile void> {
// -- variable template [C++1y]
namespace N0 {
template<typename T> int v0; // expected-note +{{here}}
template<typename T> int v0; // expected-note 4{{explicitly specialized declaration is here}}
template<> extern int v0<char[1]>;
template<> extern int v0<char[2]>;
template<> extern int v0<char[5]>;
@ -102,32 +99,32 @@ template<> extern int v0<char[6]>;
}
using N0::v0;
template<typename T> int v1; // expected-note +{{here}}
template<typename T> int v1; // expected-note 4{{explicitly specialized declaration is here}}
template<> extern int v1<char[3]>;
template<> extern int v1<char[4]>;
template<> extern int v1<char[7]>;
template<> extern int v1<char[8]>;
template<> int N0::v0<int[1]>;
template<> int v0<int[2]>; // FIXME: ill-formed
template<> int v0<int[2]>;
template<> int ::v1<int[3]>; // expected-warning {{extra qualification}}
template<> int v1<int[4]>;
template<> int N0::v0<char[1]>;
template<> int v0<char[2]>; // FIXME: ill-formed
template<> int v0<char[2]>;
template<> int ::v1<char[3]>; // expected-warning {{extra qualification}}
template<> int v1<char[4]>;
namespace N1 {
template<> int N0::v0<int[5]>; // expected-error {{must originally be declared in namespace 'N0'}} expected-error {{does not enclose namespace}}
template<> int v0<int[6]>; // expected-error {{must originally be declared in namespace 'N0'}}
template<> int ::v1<int[7]>; // expected-error {{must originally be declared in the global scope}} expected-error {{cannot name the global scope}}
template<> int v1<int[8]>; // expected-error {{must originally be declared in the global scope}}
template<> int N0::v0<int[5]>; // expected-error {{not in a namespace enclosing 'N0'}}
template<> int v0<int[6]>; // expected-error {{not in a namespace enclosing 'N0'}}
template<> int ::v1<int[7]>; // expected-error {{must occur at global scope}}
template<> int v1<int[8]>; // expected-error {{must occur at global scope}}
template<> int N0::v0<char[5]>; // expected-error {{does not enclose namespace 'N0'}}
template<> int v0<char[6]>; // FIXME: ill-formed
template<> int ::v1<char[7]>; // expected-error {{cannot name the global scope}}
template<> int v1<char[8]>; // FIXME: ill-formed
template<> int N0::v0<char[5]>; // expected-error {{not in a namespace enclosing 'N0'}}
template<> int v0<char[6]>; // expected-error {{not in a namespace enclosing 'N0'}}
template<> int ::v1<char[7]>; // expected-error {{must occur at global scope}}
template<> int v1<char[8]>; // expected-error {{must occur at global scope}}
}
// -- member function of a class template

View File

@ -20,9 +20,6 @@ struct NonDefaultConstructible {
// -- function template
namespace N0 {
template<typename T> 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<typename T> 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<typename T>
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<typename U>
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<typename U>
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<T>::ft1(T t, U u) {
template<typename T> T N0::X0<T>::member;
template<> struct N0::X0<void> { };
#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<void> test_X0;
namespace N1 {
@ -124,9 +97,6 @@ template<> struct N0::X0<volatile void> {
// -- member function of a class template
template<> void N0::X0<void*>::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<void*> xvp, void *vp) {
xvp.f1(vp);
@ -160,9 +130,6 @@ NonDefaultConstructible &get_static_member() {
}
template<> int N0::X0<int>::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<float>::member = 3.14f;
@ -191,9 +158,6 @@ namespace N0 {
template<>
struct N0::X0<long>::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<float>::Inner { };
@ -233,9 +197,6 @@ struct N0::X0<int>::InnerTemplate<long> { }; // okay
template<> template<>
struct N0::X0<int>::InnerTemplate<float> { };
#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<void*>::ft1(void *, unsigned) { } // okay
template<> template<>
void N0::X0<void*>::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<typename T, typename U> void f(Inner<T, U>&);
typedef Inner<OtherInner, OtherInner> MyInner;
template<> void f(MyInner&); // expected-error{{cannot specialize a function 'f' within class scope}}
template<> void f(MyInner&);
};
}

View File

@ -4,17 +4,9 @@
namespace N {
template<class T> 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<int> { /* ... */ }; // 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 {

View File

@ -360,7 +360,9 @@ class TestClassScopeFunctionSpecialization {
template<> void foo<int>(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 {

View File

@ -489,7 +489,6 @@ void AfterClassBody() {
namespace PR24246 {
template <typename TX> struct A {
template <bool> 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<false> {
blah x; // expected-error {{unknown type name 'blah'}}
};

View File

@ -15,8 +15,8 @@ class A {
template<typename T> static CONST T right<T,int> = 5;
template<typename T> CONST int right<int,T>; // expected-error {{member 'right' declared as a template}}
template<typename T> CONST float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
template<> static CONST int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
template<> static CONST float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
template<> static CONST int right<int,int> = 7;
template<> static CONST float right<float,int>;
template static CONST int right<int,int>; // expected-error {{expected '<' after 'template'}}
};
@ -163,8 +163,8 @@ namespace constexpred {
template<typename T> constexpr int right<int,T>; // 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<typename T> constexpr float right<float,T> = 5; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
template<> static constexpr int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
template<> static constexpr float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
template<> static constexpr int right<int,int> = 7;
template<> static constexpr float right<float,int>; // expected-error {{requires an initializer}}
template static constexpr int right<int,int>; // expected-error {{expected '<' after 'template'}}
};
}

View File

@ -409,7 +409,7 @@ namespace nested {
#endif
float f1 = pi1a<float>;
template<> double pi1a<double> = 5.2; // expected-error {{variable template specialization of 'pi1a' must originally be declared in namespace 'n1'}}
template<> double pi1a<double> = 5.2; // expected-error {{not in a namespace enclosing 'n1'}}
double d1 = pi1a<double>;
}
@ -422,8 +422,7 @@ namespace nested {
#endif
float f1 = n1::pi1b<float>;
template<> double n1::pi1b<double> = 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<double> = 5.2; // expected-error {{not in a namespace enclosing 'n1'}}
double d1 = n1::pi1b<double>;
}
}

View File

@ -185,9 +185,9 @@ namespace RedundantParensInAddressTemplateParam {
}
namespace TemplateSpecOutOfScopeNs {
template<typename T> struct S {}; // expected-note {{here}}
template<typename T> struct S {};
}
template<> struct TemplateSpecOutOfScopeNs::S<char> {}; // expected-warning {{class template specialization of 'S' outside namespace 'TemplateSpecOutOfScopeNs' is incompatible with C++98}}
template<> struct TemplateSpecOutOfScopeNs::S<char> {};
struct Typename {
template<typename T> struct Inner {};

View File

@ -78,9 +78,6 @@ template<> struct ::A<double>;
namespace N {
template<typename T> struct B; // expected-note {{explicitly specialized}}
#if __cplusplus <= 199711L
// expected-note@-2 {{explicitly specialized}}
#endif
template<> struct ::N::B<char>; // okay
template<> struct ::N::B<short>; // okay
@ -92,9 +89,6 @@ namespace N {
template<> struct N::B<int> { }; // okay
template<> struct N::B<float> { };
#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<int> { }; // expected-error{{cannot specialize a template template
namespace rdar9676205 {
template<typename T>
struct X {
struct X { // expected-note {{here}}
template<typename U>
struct X<U*> { // expected-error{{explicit specialization of 'X' in class scope}}
struct X<U*> { // expected-error{{partial specialization of 'X' not in a namespace enclosing}}
};
};

View File

@ -18,16 +18,16 @@ template <typename T> struct X {
namespace B {
template <>
class A::ClassTemplate<int>; // expected-warning {{class template specialization of 'ClassTemplate' outside namespace enclosing 'A' is a Microsoft extension}}
class A::ClassTemplate<int>; // expected-warning {{class template specialization of 'ClassTemplate' not in a namespace enclosing 'A' is a Microsoft extension}}
template <class T1>
class A::ClassTemplatePartial<T1, T1 *> {}; // expected-warning {{class template partial specialization of 'ClassTemplatePartial' outside namespace enclosing 'A' is a Microsoft extension}}
class A::ClassTemplatePartial<T1, T1 *> {}; // expected-warning {{class template partial specialization of 'ClassTemplatePartial' not in a namespace enclosing 'A' is a Microsoft extension}}
template <>
struct A::X<int>::MemberClass; // expected-warning {{member class specialization of 'MemberClass' outside namespace enclosing 'A' is a Microsoft extension}}
struct A::X<int>::MemberClass; // expected-warning {{member class specialization of 'MemberClass' not in class 'X' or an enclosing namespace is a Microsoft extension}}
template <>
enum A::X<int>::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<int>::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}}
}

View File

@ -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}}
};

View File

@ -185,7 +185,7 @@ namespace SameSignatureAfterInstantiation {
namespace PR22040 {
template <typename T> 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() {

View File

@ -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<class U> 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<class U> 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 T> class B {
public:
template<class U> B(U p) {}
template<> B(int p) {
// expected-warning@-1 {{explicit specialization of 'B<T>' within class scope is a Microsoft extension}}
}
template<> B(int p) {}
template<class U> 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<bool b> void specialized_member_template() {}
template<> void specialized_member_template<false>() {
// expected-warning@-1 {{explicit specialization of 'specialized_member_template' within class scope is a Microsoft extension}}
}
template<> void specialized_member_template<false>() {}
};
void f() { TemplateClass<int> t; }
@ -67,8 +59,8 @@ namespace PR12709 {
namespace Duplicates {
template<typename T> struct A {
template<typename U> void f();
template<> void f<int>() {} // expected-warning {{Microsoft extension}}
template<> void f<T>() {} // expected-warning {{Microsoft extension}}
template<> void f<int>() {}
template<> void f<T>() {}
};
// FIXME: We should diagnose the duplicate explicit specialization definitions
@ -81,6 +73,6 @@ struct S {
template <int>
int f(int = 0);
template <>
int f<0>(int); // expected-warning {{Microsoft extension}}
int f<0>(int);
};
}

View File

@ -7,17 +7,11 @@ template<typename T> struct vector;
namespace N {
namespace M {
template<typename T> struct A;
#if __cplusplus <= 199711L // C++03 or earlier modes
// expected-note@-2{{explicitly specialized declaration is here}}
#endif
}
}
template<typename T>
struct N::M::A<T*> { };
#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

View File

@ -303,7 +303,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#44">44</a></td>
<td>CD1</td>
<td>Member specializations</td>
<td class="full" align="center">Yes</td>
<td class="svn" align="center">Superseded by <a href="#727">727</a></td>
</tr>
<tr id="45">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45">45</a></td>
@ -2285,7 +2285,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#374">374</a></td>
<td>CD2</td>
<td>Can explicit specialization outside namespace use qualified name?</td>
<td class="full" align="center">Yes (C++11 onwards)</td>
<td class="full" align="center">Yes</td>
</tr>
<tr id="375">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#375">375</a></td>
@ -4387,7 +4387,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#727">727</a></td>
<td>C++17</td>
<td>In-class explicit specializations</td>
<td class="none" align="center">Unknown</td>
<td class="svn" align="center">SVN</td>
</tr>
<tr class="open" id="728">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#728">728</a></td>