r290647 - DR1315: a non-type template argument in a partial specialization is permitted
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 27 18:37:26 PST 2016
Author: rsmith
Date: Tue Dec 27 20:37:25 2016
New Revision: 290647
URL: http://llvm.org/viewvc/llvm-project?rev=290647&view=rev
Log:
DR1315: a non-type template argument in a partial specialization is permitted
to make reference to template parameters. This is only a partial
implementation; we retain the restriction that the argument must not be
type-dependent, since it's unclear how that would work given the existence of
other language rules requiring an exact type match in this context, even for
type-dependent cases (a question has been raised on the core reflector).
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/CXX/drs/dr13xx.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
cfe/trunk/test/SemaTemplate/class-template-spec.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
cfe/trunk/www/cxx_dr_status.html
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Dec 27 20:37:25 2016
@@ -4032,8 +4032,8 @@ def err_specialize_member_of_template :
def err_default_arg_in_partial_spec : Error<
"default template argument in a class template partial specialization">;
def err_dependent_non_type_arg_in_partial_spec : Error<
- "non-type template argument depends on a template parameter of the "
- "partial specialization">;
+ "type of specialized non-type template argument depends on a template "
+ "parameter of the partial specialization">;
def note_dependent_non_type_default_arg_in_partial_spec : Note<
"template parameter is used in default argument declared here">;
def err_dependent_typed_non_type_arg_in_partial_spec : Error<
@@ -4048,11 +4048,11 @@ def ext_partial_spec_not_more_specialize
"more specialized than the primary template">, DefaultError,
InGroup<DiagGroup<"invalid-partial-specialization">>;
def note_partial_spec_not_more_specialized_than_primary : Note<"%0">;
-def warn_partial_specs_not_deducible : Warning<
+def ext_partial_specs_not_deducible : ExtWarn<
"%select{class|variable}0 template partial specialization contains "
"%select{a template parameter|template parameters}1 that cannot be "
"deduced; this partial specialization will never be used">,
- InGroup<DiagGroup<"unusable-partial-specialization">>;
+ DefaultError, InGroup<DiagGroup<"unusable-partial-specialization">>;
def note_partial_spec_unused_parameter : Note<
"non-deducible template parameter %0">;
def err_partial_spec_ordering_ambiguous : Error<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Dec 27 20:37:25 2016
@@ -5927,6 +5927,15 @@ public:
MultiTemplateParamsArg TemplateParameterLists,
SkipBodyInfo *SkipBody = nullptr);
+ bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc,
+ TemplateDecl *PrimaryTemplate,
+ unsigned NumExplicitArgs,
+ ArrayRef<TemplateArgument> Args);
+ void CheckTemplatePartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *Partial);
+ void CheckTemplatePartialSpecialization(
+ VarTemplatePartialSpecializationDecl *Partial);
+
Decl *ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 27 20:37:25 2016
@@ -1638,12 +1638,22 @@ struct DependencyChecker : RecursiveASTV
typedef RecursiveASTVisitor<DependencyChecker> super;
unsigned Depth;
+
+ // Whether we're looking for a use of a template parameter that makes the
+ // overall construct type-dependent / a dependent type. This is strictly
+ // best-effort for now; we may fail to match at all for a dependent type
+ // in some cases if this is set.
+ bool IgnoreNonTypeDependent;
+
bool Match;
SourceLocation MatchLoc;
- DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {}
+ DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent)
+ : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent),
+ Match(false) {}
- DependencyChecker(TemplateParameterList *Params) : Match(false) {
+ DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent)
+ : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {
NamedDecl *ND = Params->getParam(0);
if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) {
Depth = PD->getDepth();
@@ -1664,12 +1674,31 @@ struct DependencyChecker : RecursiveASTV
return false;
}
+ bool TraverseStmt(Stmt *S, DataRecursionQueue *Q = nullptr) {
+ // Prune out non-type-dependent expressions if requested. This can
+ // sometimes result in us failing to find a template parameter reference
+ // (if a value-dependent expression creates a dependent type), but this
+ // mode is best-effort only.
+ if (auto *E = dyn_cast_or_null<Expr>(S))
+ if (IgnoreNonTypeDependent && !E->isTypeDependent())
+ return true;
+ return super::TraverseStmt(S, Q);
+ }
+
+ bool TraverseTypeLoc(TypeLoc TL) {
+ if (IgnoreNonTypeDependent && !TL.isNull() &&
+ !TL.getType()->isDependentType())
+ return true;
+ return super::TraverseTypeLoc(TL);
+ }
+
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc());
}
bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
- return !Matches(T->getDepth());
+ // For a best-effort search, keep looking until we find a location.
+ return IgnoreNonTypeDependent || !Matches(T->getDepth());
}
bool TraverseTemplateName(TemplateName N) {
@@ -1707,7 +1736,7 @@ struct DependencyChecker : RecursiveASTV
/// list.
static bool
DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) {
- DependencyChecker Checker(Params);
+ DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false);
Checker.TraverseType(T);
return Checker.Match;
}
@@ -2539,10 +2568,6 @@ TypeResult Sema::ActOnTagTemplateIdType(
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
-static bool CheckTemplatePartialSpecializationArgs(
- Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams,
- unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &TemplateArgs);
-
static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
NamedDecl *PrevDecl,
SourceLocation Loc,
@@ -2654,6 +2679,59 @@ static void checkMoreSpecializedThanPrim
S.Diag(Template->getLocation(), diag::note_template_decl_here);
}
+template<typename PartialSpecDecl>
+static void checkTemplatePartialSpecialization(Sema &S,
+ PartialSpecDecl *Partial) {
+ // C++1z [temp.class.spec]p8: (DR1495)
+ // - The specialization shall be more specialized than the primary
+ // template (14.5.5.2).
+ checkMoreSpecializedThanPrimary(S, Partial);
+
+ // C++ [temp.class.spec]p8: (DR1315)
+ // - Each template-parameter shall appear at least once in the
+ // template-id outside a non-deduced context.
+ // C++1z [temp.class.spec.match]p3 (P0127R2)
+ // If the template arguments of a partial specialization cannot be
+ // deduced because of the structure of its template-parameter-list
+ // and the template-id, the program is ill-formed.
+ auto *TemplateParams = Partial->getTemplateParameters();
+ llvm::SmallBitVector DeducibleParams(TemplateParams->size());
+ S.MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
+ TemplateParams->getDepth(), DeducibleParams);
+
+ if (!DeducibleParams.all()) {
+ unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count();
+ S.Diag(Partial->getLocation(), diag::ext_partial_specs_not_deducible)
+ << isa<VarTemplatePartialSpecializationDecl>(Partial)
+ << (NumNonDeducible > 1)
+ << SourceRange(Partial->getLocation(),
+ Partial->getTemplateArgsAsWritten()->RAngleLoc);
+ for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
+ if (!DeducibleParams[I]) {
+ NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
+ if (Param->getDeclName())
+ S.Diag(Param->getLocation(),
+ diag::note_partial_spec_unused_parameter)
+ << Param->getDeclName();
+ else
+ S.Diag(Param->getLocation(),
+ diag::note_partial_spec_unused_parameter)
+ << "(anonymous)";
+ }
+ }
+ }
+}
+
+void Sema::CheckTemplatePartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *Partial) {
+ checkTemplatePartialSpecialization(*this, Partial);
+}
+
+void Sema::CheckTemplatePartialSpecialization(
+ VarTemplatePartialSpecializationDecl *Partial) {
+ checkTemplatePartialSpecialization(*this, Partial);
+}
+
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
TemplateParameterList *TemplateParams, StorageClass SC,
@@ -2703,11 +2781,12 @@ DeclResult Sema::ActOnVarTemplateSpecial
// Find the variable template (partial) specialization declaration that
// corresponds to these arguments.
if (IsPartialSpecialization) {
- if (CheckTemplatePartialSpecializationArgs(
- *this, TemplateNameLoc, VarTemplate->getTemplateParameters(),
- TemplateArgs.size(), Converted))
+ if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate,
+ TemplateArgs.size(), Converted))
return true;
+ // FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we
+ // also do them during instantiation.
bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
@@ -2779,37 +2858,7 @@ DeclResult Sema::ActOnVarTemplateSpecial
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
PrevPartial->setMemberSpecialization();
- // C++1z [temp.class.spec]p8: (DR1495)
- // - The specialization shall be more specialized than the primary
- // template (14.5.5.2).
- checkMoreSpecializedThanPrimary(*this, Partial);
-
- // Check that all of the template parameters of the variable template
- // partial specialization are deducible from the template
- // arguments. If not, this variable template partial specialization
- // will never be used.
- llvm::SmallBitVector DeducibleParams(TemplateParams->size());
- MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
- TemplateParams->getDepth(), DeducibleParams);
-
- if (!DeducibleParams.all()) {
- unsigned NumNonDeducible =
- DeducibleParams.size() - DeducibleParams.count();
- Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
- << /*variable template*/ 1 << (NumNonDeducible > 1)
- << SourceRange(TemplateNameLoc, RAngleLoc);
- for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
- if (!DeducibleParams[I]) {
- NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
- if (Param->getDeclName())
- Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
- << Param->getDeclName();
- else
- Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
- << "(anonymous)";
- }
- }
- }
+ CheckTemplatePartialSpecialization(Partial);
} else {
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
@@ -6208,12 +6257,12 @@ static bool CheckTemplateSpecializationS
return false;
}
-static SourceRange findTemplateParameter(unsigned Depth, Expr *E) {
- if (!E->isInstantiationDependent())
+static SourceRange findTemplateParameterInType(unsigned Depth, Expr *E) {
+ if (!E->isTypeDependent())
return SourceLocation();
- DependencyChecker Checker(Depth);
+ DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true);
Checker.TraverseStmt(E);
- if (Checker.Match && Checker.MatchLoc.isInvalid())
+ if (Checker.MatchLoc.isInvalid())
return E->getSourceRange();
return Checker.MatchLoc;
}
@@ -6221,9 +6270,9 @@ static SourceRange findTemplateParameter
static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) {
if (!TL.getType()->isDependentType())
return SourceLocation();
- DependencyChecker Checker(Depth);
+ DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true);
Checker.TraverseTypeLoc(TL);
- if (Checker.Match && Checker.MatchLoc.isInvalid())
+ if (Checker.MatchLoc.isInvalid())
return TL.getSourceRange();
return Checker.MatchLoc;
}
@@ -6275,8 +6324,16 @@ static bool CheckNonTypeTemplatePartialS
// shall not involve a template parameter of the partial
// specialization except when the argument expression is a
// simple identifier.
+ // -- The type of a template parameter corresponding to a
+ // specialized non-type argument shall not be dependent on a
+ // parameter of the specialization.
+ // DR1315 removes the first bullet, leaving an incoherent set of rules.
+ // We implement a compromise between the original rules and DR1315:
+ // -- A specialized non-type template argument shall not be
+ // type-dependent and the corresponding template parameter
+ // shall have a non-dependent type.
SourceRange ParamUseRange =
- findTemplateParameter(Param->getDepth(), ArgExpr);
+ findTemplateParameterInType(Param->getDepth(), ArgExpr);
if (ParamUseRange.isValid()) {
if (IsDefaultArgument) {
S.Diag(TemplateNameLoc,
@@ -6292,26 +6349,15 @@ static bool CheckNonTypeTemplatePartialS
return true;
}
- // -- The type of a template parameter corresponding to a
- // specialized non-type argument shall not be dependent on a
- // parameter of the specialization.
- //
- // FIXME: We need to delay this check until instantiation in some cases:
- //
- // template<template<typename> class X> struct A {
- // template<typename T, X<T> N> struct B;
- // template<typename T> struct B<T, 0>;
- // };
- // template<typename> using X = int;
- // A<X>::B<int, 0> b;
ParamUseRange = findTemplateParameter(
- Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc());
+ Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc());
if (ParamUseRange.isValid()) {
S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getLocStart(),
diag::err_dependent_typed_non_type_arg_in_partial_spec)
- << Param->getType() << ParamUseRange;
+ << Param->getType();
S.Diag(Param->getLocation(), diag::note_template_param_here)
- << (IsDefaultArgument ? ParamUseRange : SourceRange());
+ << (IsDefaultArgument ? ParamUseRange : SourceRange())
+ << ParamUseRange;
return true;
}
}
@@ -6330,20 +6376,25 @@ static bool CheckNonTypeTemplatePartialS
/// partial specialization.
///
/// \returns \c true if there was an error, \c false otherwise.
-static bool CheckTemplatePartialSpecializationArgs(
- Sema &S, SourceLocation TemplateNameLoc,
- TemplateParameterList *TemplateParams, unsigned NumExplicit,
- SmallVectorImpl<TemplateArgument> &TemplateArgs) {
- const TemplateArgument *ArgList = TemplateArgs.data();
+bool Sema::CheckTemplatePartialSpecializationArgs(
+ SourceLocation TemplateNameLoc, TemplateDecl *PrimaryTemplate,
+ unsigned NumExplicit, ArrayRef<TemplateArgument> TemplateArgs) {
+ // We have to be conservative when checking a template in a dependent
+ // context.
+ if (PrimaryTemplate->getDeclContext()->isDependentContext())
+ return false;
+ TemplateParameterList *TemplateParams =
+ PrimaryTemplate->getTemplateParameters();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
NonTypeTemplateParmDecl *Param
= dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
if (!Param)
continue;
- if (CheckNonTypeTemplatePartialSpecializationArgs(
- S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit))
+ if (CheckNonTypeTemplatePartialSpecializationArgs(*this, TemplateNameLoc,
+ Param, &TemplateArgs[I],
+ 1, I >= NumExplicit))
return true;
}
@@ -6487,11 +6538,12 @@ Sema::ActOnClassTemplateSpecialization(S
// Find the class template (partial) specialization declaration that
// corresponds to these arguments.
if (isPartialSpecialization) {
- if (CheckTemplatePartialSpecializationArgs(
- *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(),
- TemplateArgs.size(), Converted))
+ if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate,
+ TemplateArgs.size(), Converted))
return true;
+ // FIXME: Move this to CheckTemplatePartialSpecializationArgs so we
+ // also do it during instantiation.
bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
@@ -6581,39 +6633,7 @@ Sema::ActOnClassTemplateSpecialization(S
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
PrevPartial->setMemberSpecialization();
- // C++1z [temp.class.spec]p8: (DR1495)
- // - The specialization shall be more specialized than the primary
- // template (14.5.5.2).
- checkMoreSpecializedThanPrimary(*this, Partial);
-
- // Check that all of the template parameters of the class template
- // partial specialization are deducible from the template
- // arguments. If not, this class template partial specialization
- // will never be used.
- llvm::SmallBitVector DeducibleParams(TemplateParams->size());
- MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
- TemplateParams->getDepth(),
- DeducibleParams);
-
- if (!DeducibleParams.all()) {
- unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count();
- Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
- << /*class template*/0 << (NumNonDeducible > 1)
- << SourceRange(TemplateNameLoc, RAngleLoc);
- for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
- if (!DeducibleParams[I]) {
- NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
- if (Param->getDeclName())
- Diag(Param->getLocation(),
- diag::note_partial_spec_unused_parameter)
- << Param->getDeclName();
- else
- Diag(Param->getLocation(),
- diag::note_partial_spec_unused_parameter)
- << "(anonymous)";
- }
- }
- }
+ CheckTemplatePartialSpecialization(Partial);
} else {
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Dec 27 20:37:25 2016
@@ -3086,6 +3086,12 @@ TemplateDeclInstantiator::InstantiateCla
Converted))
return nullptr;
+ // Check these arguments are valid for a template partial specialization.
+ if (SemaRef.CheckTemplatePartialSpecializationArgs(
+ PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(),
+ Converted))
+ return nullptr;
+
// Figure out where to insert this class template partial specialization
// in the member template's set of class template partial specializations.
void *InsertPos = nullptr;
@@ -3156,6 +3162,9 @@ TemplateDeclInstantiator::InstantiateCla
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
+ // Check the completed partial specialization.
+ SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec);
+
// Add this partial specialization to the set of class template partial
// specializations.
ClassTemplate->AddPartialSpecialization(InstPartialSpec,
@@ -3208,6 +3217,12 @@ TemplateDeclInstantiator::InstantiateVar
InstTemplateArgs, false, Converted))
return nullptr;
+ // Check these arguments are valid for a template partial specialization.
+ if (SemaRef.CheckTemplatePartialSpecializationArgs(
+ PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(),
+ Converted))
+ return nullptr;
+
// Figure out where to insert this variable template partial specialization
// in the member template's set of variable template partial specializations.
void *InsertPos = nullptr;
@@ -3282,6 +3297,9 @@ TemplateDeclInstantiator::InstantiateVar
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
+ // Check the completed partial specialization.
+ SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec);
+
// Add this partial specialization to the set of variable template partial
// specializations. The instantiation of the initializer is not necessary.
VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/nullptr);
Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr13xx.cpp Tue Dec 27 20:37:25 2016
@@ -3,6 +3,34 @@
// 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 dr1315 { // dr1315: partial
+ template <int I, int J> struct A {};
+ template <int I> // expected-note {{non-deducible template parameter 'I'}}
+ struct A<I + 5, I * 2> {}; // expected-error {{contains a template parameter that cannot be deduced}}
+ template <int I> struct A<I, I> {};
+
+ template <int I, int J, int K> struct B;
+ template <int I, int K> struct B<I, I * 2, K> {}; // expected-note {{matches}}
+ B<1, 2, 3> b1;
+
+ // Multiple declarations with the same dependent expression are equivalent
+ // for partial ordering purposes.
+ template <int I> struct B<I, I * 2, 2> { typedef int type; };
+ B<1, 2, 2>::type b2;
+
+ // Multiple declarations with differing dependent expressions are unordered.
+ template <int I, int K> struct B<I, I + 1, K> {}; // expected-note {{matches}}
+ B<1, 2, 4> b3; // expected-error {{ambiguous}}
+
+ // FIXME: Under dr1315, this is perhaps valid, but that is not clear: this
+ // fails the "more specialized than the primary template" test because the
+ // dependent type of T::value is not the same as 'int'.
+ // A core issue will be opened to decide what is supposed to happen here.
+ template <typename T, int I> struct C;
+ template <typename T> struct C<T, T::value>;
+ // expected-error at -1 {{type of specialized non-type template argument depends on a template parameter of the partial specialization}}
+}
+
namespace dr1330 { // dr1330: 4.0 c++11
// exception-specifications are parsed in a context where the class is complete.
struct A {
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp Tue Dec 27 20:37:25 2016
@@ -2,7 +2,10 @@
template<int ...Values> struct X1;
-template<int ...Values>
-struct X1<0, Values+1 ...>; // expected-error{{non-type template argument depends on a template parameter of the partial specialization}}
-
+template<int ...Values> // expected-note {{non-deducible}}
+struct X1<0, Values+1 ...>; // expected-error{{contains a template parameter that cannot be deduced}}
+template<typename T, int ...Values> struct X2; // expected-note {{here}}
+template<int ...Values> struct X2<X1<Values...>, Values+1 ...> {}; // ok (DR1315)
+X2<X1<1, 2, 3>, 2, 3, 4> x2; // ok
+X2<X1<1, 2, 3>, 2, 3, 4, 5> x3; // expected-error {{undefined template}}
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp Tue Dec 27 20:37:25 2016
@@ -21,15 +21,16 @@ template<template<typename> class...X> i
template<typename Outer> struct X {
template<typename Inner> static int y;
- template<typename Inner> static int y<Outer>; // expected-warning {{cannot be deduced}} expected-note {{'Inner'}}
+ // FIXME: It would be preferable to only diagnose this once.
+ template<typename Inner> static int y<Outer>; // expected-error 3{{cannot be deduced}} expected-note 3{{'Inner'}}
template<typename Inner> static int y<Inner>; // expected-error {{does not specialize}}
+
+ template<typename, int> static int z;
+ template<Outer N> static int z<int, N>; // expected-error {{not implicitly convertible}}
};
-template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-warning {{cannot be deduced}} expected-note {{'Inner'}}
+template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-error {{cannot be deduced}} expected-note {{'Inner'}}
template<typename Outer> template<typename Inner> int X<Outer>::y<Inner>; // expected-error {{does not specialize}}
+template<> template<typename Inner> int X<int>::y<Inner>; // expected-error {{does not specialize}} expected-note {{instantiation of}}
-// FIXME: Merging this with the above class causes an assertion failure when
-// instantiating one of the bogus partial specializations.
-template<typename Outer> struct Y {
- template<typename Inner> static int y;
-};
-template<> template<typename Inner> int Y<int>::y<Inner>; // expected-error {{does not specialize}}
+X<int> xi;
+X<int*> xf; // expected-note {{instantiation of}}
Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp Tue Dec 27 20:37:25 2016
@@ -32,7 +32,7 @@ namespace PackExpansionNotAtEnd {
template<typename ... Types, // expected-note{{non-deducible template parameter 'Types'}}
typename Tail> // expected-note{{non-deducible template parameter 'Tail'}}
- struct UselessPartialSpec<Types..., Tail>; // expected-warning{{class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used}}
+ struct UselessPartialSpec<Types..., Tail>; // expected-error{{class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used}}
}
namespace DeduceNonTypeTemplateArgsInArray {
Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Tue Dec 27 20:37:25 2016
@@ -137,12 +137,16 @@ namespace PR18009 {
A<int>::S<8, sizeof(int)> a; // ok
template <typename T> struct B {
- template <int N, int M> struct S; // expected-note {{declared here}}
- template <int N> struct S<N, sizeof(T) +
- N // expected-error {{non-type template argument depends on a template parameter of the partial specialization}}
- > {};
+ template <int N, int M> struct S;
+ template <int N> struct S<N, sizeof(T) + N> {}; // ok (dr1315)
};
- B<int>::S<8, sizeof(int) + 8> s; // expected-error {{undefined}}
+ B<int>::S<8, sizeof(int) + 8> b;
+
+ template <typename T> struct C {
+ template <int N, int M> struct S;
+ template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}}
+ };
+ C<int> c; // expected-note {{in instantiation of}}
template<int A> struct outer {
template<int B, int C> struct inner {};
@@ -222,9 +226,9 @@ namespace DefaultArgVsPartialSpec {
// Check that the diagnostic points at the partial specialization, not just at
// the default argument.
template<typename T, int N =
- sizeof(T) // expected-note {{template parameter is used in default argument declared here}}
+ sizeof(T) // ok (dr1315)
> struct X {};
- template<typename T> struct X<T> {}; // expected-error {{non-type template argument depends on a template parameter of the partial specialization}}
+ template<typename T> struct X<T> {};
template<typename T,
T N = 0 // expected-note {{template parameter is declared here}}
Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Dec 27 20:37:25 2016
@@ -408,3 +408,29 @@ namespace partial_order_references {
extern const int K = 5;
D<0, K> d; // expected-error {{undefined}}
}
+
+namespace dependent_nested_partial_specialization {
+ template<typename> using X = int; // expected-warning {{C++11}}
+ template<typename T> using Y = T*; // expected-warning {{C++11}}
+ int n;
+
+ template<template<typename> class X> struct A {
+ template<typename T, X<T> N> struct B; // expected-note 2{{here}}
+ template<typename T> struct B<T, 0> {}; // expected-error {{specializes a template parameter with dependent type 'Y<T>'}}
+ };
+ A<X>::B<int, 0> ax;
+ A<Y>::B<int, &n> ay; // expected-error {{undefined}} expected-note {{instantiation of}}
+
+ template<template<typename> class X> struct C {
+ template<typename T, int N, int M> struct D; // expected-note {{here}}
+ template<typename T, X<T> N> struct D<T*, N, N + 1> {}; // expected-error {{type of specialized non-type template argument depends on}}
+ };
+ C<X>::D<int*, 0, 1> cx;
+ C<Y>::D<int*, 0, 1> cy; // expected-error {{undefined}} expected-note {{instantiation of}}
+
+ template<typename T> struct E {
+ template<typename U, U V> struct F; // expected-note {{template}}
+ template<typename W, T V> struct F<W, V> {}; // expected-error {{not more specialized than the primary}} expected-note {{does not have the same type}}
+ };
+ E<int>::F<int, 0> e1; // expected-note {{instantiation of}}
+}
Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp Tue Dec 27 20:37:25 2016
@@ -34,5 +34,5 @@ namespace check_conversion_early {
template<X &x> struct A<x> {}; // expected-error {{not implicitly convertible}}
struct Y { constexpr operator int() const { return 0; } };
- template<Y &y> struct A<y> {}; // expected-error {{depends on a template parameter of the partial specialization}}
+ template<Y &y> struct A<y> {}; // expected-error {{cannot be deduced}} expected-note {{'y'}}
}
Modified: cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp Tue Dec 27 20:37:25 2016
@@ -20,9 +20,9 @@ struct N::M::A<T*> { };
#endif
// C++ [temp.class.spec]p9
-// bullet 1
+// bullet 1, as amended by DR1315
template <int I, int J> struct A {};
-template <int I> struct A<I+5, I*2> {}; // expected-error{{depends on}}
+template <int I> struct A<I+5, I*2> {}; // expected-error{{cannot be deduced}} expected-note {{'I'}}
template <int I, int J> struct B {};
template <int I> struct B<I, I> {}; //OK
@@ -50,4 +50,4 @@ template<typename T = int, // expected-e
template<typename T> struct Test1;
template<typename T, typename U> // expected-note{{non-deducible}}
- struct Test1<T*> { }; // expected-warning{{never be used}}
+ struct Test1<T*> { }; // expected-error{{never be used}}
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Tue Dec 27 20:37:25 2016
@@ -688,7 +688,7 @@ TEST(TemplateTypeParmDecl, VarTemplatePa
"};\n"
"template<typename U>\n"
"template<typename U2>\n"
- "int Struct<U>::field<char> = 123;\n";
+ "int Struct<U>::field<U2*> = 123;\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
@@ -703,7 +703,7 @@ TEST(TemplateTypeParmDecl, ClassTemplate
"};\n"
"template<typename U>\n"
"template<typename U2>\n"
- "struct Class<U>::Struct<int> {};\n";
+ "struct Class<U>::Struct<U2*> {};\n";
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2"))));
EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=290647&r1=290646&r2=290647&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Tue Dec 27 20:37:25 2016
@@ -7705,7 +7705,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1315">1315</a></td>
<td>DR</td>
<td>Restrictions on non-type template arguments in partial specializations</td>
- <td class="none" align="center">Unknown</td>
+ <td class="partial" align="center">Partial</td>
</tr>
<tr id="1316">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1316">1316</a></td>
More information about the cfe-commits
mailing list