r282651 - P0127R2: Support type deduction for types of non-type template parameters in
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 28 16:55:28 PDT 2016
Author: rsmith
Date: Wed Sep 28 18:55:27 2016
New Revision: 282651
URL: http://llvm.org/viewvc/llvm-project?rev=282651&view=rev
Log:
P0127R2: Support type deduction for types of non-type template parameters in
C++1z.
Patch by James Touton! Some bugfixes and rebasing by me.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep 28 18:55:27 2016
@@ -1827,7 +1827,8 @@ def err_auto_not_allowed : Error<
"|in exception declaration|in template parameter|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
"|in conversion function type|here|in lambda parameter"
- "|in type allocated by 'new'|in K&R-style function parameter}1">;
+ "|in type allocated by 'new'|in K&R-style function parameter}1"
+ "%select{|||||||| until C++1z||||||||||}1">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
@@ -3656,6 +3657,10 @@ def note_template_nontype_parm_prev_decl
"previous non-type template parameter with type %0 is here">;
def err_template_nontype_parm_bad_type : Error<
"a non-type template parameter cannot have type %0">;
+def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
+ "non-type template parameters declared with %0 are incompatible with C++ "
+ "standards before C++1z">,
+ DefaultIgnore, InGroup<CXXPre1zCompat>;
def err_template_param_default_arg_redefinition : Error<
"template parameter redefines default argument">;
def note_template_param_prev_default_arg : Note<
@@ -3750,8 +3755,10 @@ def warn_cxx98_compat_template_arg_null
def err_template_arg_untyped_null_constant : Error<
"null non-type template argument must be cast to template parameter type %0">;
def err_template_arg_wrongtype_null_constant : Error<
- "null non-type template argument of type %0 does not match template parameter "
- "of type %1">;
+ "null non-type template argument of type %0 does not match template parameter "
+ "of type %1">;
+def err_non_type_template_parm_type_deduction_failure : Error<
+ "non-type template parameter %0 with type %1 has incompatible initializer of type %2">;
def err_deduced_non_type_template_arg_type_mismatch : Error<
"deduced non-type template argument does not have the same type as the "
"its corresponding template parameter%diff{ ($ vs $)|}0,1">;
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Sep 28 18:55:27 2016
@@ -1202,6 +1202,8 @@ static bool HasFeature(const Preprocesso
.Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus14)
.Case("cxx_return_type_deduction", LangOpts.CPlusPlus14)
.Case("cxx_variable_templates", LangOpts.CPlusPlus14)
+ // C++1z features
+ .Case("cxx_template_auto", LangOpts.CPlusPlus1z)
// C++ TSes
//.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
//.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Sep 28 18:55:27 2016
@@ -730,7 +730,13 @@ Sema::CheckNonTypeTemplateParameterType(
T->isNullPtrType() ||
// If T is a dependent type, we can't do the check now, so we
// assume that it is well-formed.
- T->isDependentType()) {
+ T->isDependentType() ||
+ // Allow use of auto in template parameter declarations.
+ T->isUndeducedType()) {
+ if (T->isUndeducedType()) {
+ Diag(Loc, diag::warn_cxx14_compat_template_nontype_parm_auto_type)
+ << QualType(T->getContainedAutoType(), 0);
+ }
// C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
// are ignored when determining its type.
return T.getUnqualifiedType();
@@ -4975,6 +4981,29 @@ ExprResult Sema::CheckTemplateArgument(N
CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getLocStart();
+ // If the parameter type somehow involves auto, deduce the type now.
+ if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) {
+ if (DeduceAutoType(
+ Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
+ Arg, ParamType) == DAR_Failed) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << Param->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
+ // CheckNonTypeTemplateParameterType will produce a diagnostic if there's
+ // an error. The error message normally references the parameter
+ // declaration, but here we'll pass the argument location because that's
+ // where the parameter type is deduced.
+ ParamType = CheckNonTypeTemplateParameterType(ParamType, Arg->getExprLoc());
+ if (ParamType.isNull()) {
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
+ }
+
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || Arg->isTypeDependent()) {
@@ -7255,7 +7284,7 @@ Sema::CheckMemberSpecialization(NamedDec
if (InstantiationFunction->isDeleted()) {
assert(InstantiationFunction->getCanonicalDecl() ==
InstantiationFunction);
- InstantiationFunction->setDeletedAsWritten(false);
+ InstantiationFunction->setDeletedAsWritten(false);
}
}
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Sep 28 18:55:27 2016
@@ -100,7 +100,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
SmallVectorImpl<DeducedTemplateArgument> &
Deduced,
unsigned TDF,
- bool PartialOrdering = false);
+ bool PartialOrdering = false,
+ bool DeducedFromArrayBound = false);
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
@@ -167,6 +168,12 @@ checkDeducedTemplateArguments(ASTContext
Context.hasSameType(X.getAsType(), Y.getAsType()))
return X;
+ // If one of the two arguments was deduced from an array bound, the other
+ // supersedes it.
+ if (X.wasDeducedFromArrayBound() != Y.wasDeducedFromArrayBound())
+ return X.wasDeducedFromArrayBound() ? Y : X;
+
+ // The arguments are not compatible.
return DeducedTemplateArgument();
case TemplateArgument::Integral:
@@ -287,7 +294,8 @@ checkDeducedTemplateArguments(ASTContext
/// \brief Deduce the value of the given non-type template parameter
/// from the given integral constant.
static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
- Sema &S, NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
+ Sema &S, TemplateParameterList *TemplateParams,
+ NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
@@ -306,13 +314,20 @@ static Sema::TemplateDeductionResult Ded
}
Deduced[NTTP->getIndex()] = Result;
- return Sema::TDK_Success;
+ return S.getLangOpts().CPlusPlus1z
+ ? DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, NTTP->getType(), ValueType, Info, Deduced,
+ TDF_ParamWithReferenceType | TDF_SkipNonDependent,
+ /*PartialOrdering=*/false,
+ /*ArrayBound=*/DeducedFromArrayBound)
+ : Sema::TDK_Success;
}
/// \brief Deduce the value of the given non-type template parameter
/// from the given null pointer template argument type.
static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument(
- Sema &S, NonTypeTemplateParmDecl *NTTP, QualType NullPtrType,
+ Sema &S, TemplateParameterList *TemplateParams,
+ NonTypeTemplateParmDecl *NTTP, QualType NullPtrType,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
Expr *Value =
@@ -332,7 +347,11 @@ static Sema::TemplateDeductionResult Ded
}
Deduced[NTTP->getIndex()] = Result;
- return Sema::TDK_Success;
+ return S.getLangOpts().CPlusPlus1z
+ ? DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, NTTP->getType(), Value->getType(), Info,
+ Deduced, TDF_ParamWithReferenceType | TDF_SkipNonDependent)
+ : Sema::TDK_Success;
}
/// \brief Deduce the value of the given non-type template parameter
@@ -341,6 +360,7 @@ static Sema::TemplateDeductionResult Ded
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
+ TemplateParameterList *TemplateParams,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
TemplateDeductionInfo &Info,
@@ -363,7 +383,11 @@ DeduceNonTypeTemplateArgument(Sema &S,
}
Deduced[NTTP->getIndex()] = Result;
- return Sema::TDK_Success;
+ return S.getLangOpts().CPlusPlus1z
+ ? DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, NTTP->getType(), Value->getType(), Info,
+ Deduced, TDF_ParamWithReferenceType | TDF_SkipNonDependent)
+ : Sema::TDK_Success;
}
/// \brief Deduce the value of the given non-type template parameter
@@ -372,8 +396,9 @@ DeduceNonTypeTemplateArgument(Sema &S,
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
+ TemplateParameterList *TemplateParams,
NonTypeTemplateParmDecl *NTTP,
- ValueDecl *D,
+ ValueDecl *D, QualType T,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
@@ -393,7 +418,11 @@ DeduceNonTypeTemplateArgument(Sema &S,
}
Deduced[NTTP->getIndex()] = Result;
- return Sema::TDK_Success;
+ return S.getLangOpts().CPlusPlus1z
+ ? DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, NTTP->getType(), T, Info, Deduced,
+ TDF_ParamWithReferenceType | TDF_SkipNonDependent)
+ : Sema::TDK_Success;
}
static Sema::TemplateDeductionResult
@@ -968,7 +997,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
- bool PartialOrdering) {
+ bool PartialOrdering,
+ bool DeducedFromArrayBound) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
QualType Param = S.Context.getCanonicalType(ParamIn);
@@ -1152,7 +1182,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
if (RecanonicalizeArg)
DeducedType = S.Context.getCanonicalType(DeducedType);
- DeducedTemplateArgument NewDeduced(DeducedType);
+ DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[Index],
NewDeduced);
@@ -1374,7 +1404,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
- return DeduceNonTypeTemplateArgument(S, NTTP, Size,
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size,
S.Context.getSizeType(),
/*ArrayBound=*/true,
Info, Deduced);
@@ -1382,7 +1412,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema
if (const DependentSizedArrayType *DependentArrayArg
= dyn_cast<DependentSizedArrayType>(ArrayArg))
if (DependentArrayArg->getSizeExpr())
- return DeduceNonTypeTemplateArgument(S, NTTP,
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
DependentArrayArg->getSizeExpr(),
Info, Deduced);
@@ -1654,8 +1684,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
ArgSize = VectorArg->getNumElements();
- return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy,
- false, Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
+ S.Context.IntTy, false, Info, Deduced);
}
if (const DependentSizedExtVectorType *VectorArg
@@ -1674,7 +1704,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
if (!NTTP)
return Sema::TDK_Success;
- return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(),
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ VectorArg->getSizeExpr(),
Info, Deduced);
}
@@ -1779,19 +1810,22 @@ DeduceTemplateArguments(Sema &S,
if (NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
- return DeduceNonTypeTemplateArgument(S, NTTP,
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
Arg.getAsIntegral(),
Arg.getIntegralType(),
/*ArrayBound=*/false,
Info, Deduced);
if (Arg.getKind() == TemplateArgument::NullPtr)
- return DeduceNullPtrTemplateArgument(S, NTTP, Arg.getNullPtrType(),
+ return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
+ Arg.getNullPtrType(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
- return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
- Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ Arg.getAsExpr(), Info, Deduced);
if (Arg.getKind() == TemplateArgument::Declaration)
- return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(),
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ Arg.getAsDecl(),
+ Arg.getParamTypeForDecl(),
Info, Deduced);
Info.FirstArg = Param;
@@ -3280,7 +3314,7 @@ DeduceFromInitializerList(Sema &S, Templ
ILE->getNumInits());
Result = DeduceNonTypeTemplateArgument(
- S, NTTP, llvm::APSInt(Size), NTTP->getType(),
+ S, TemplateParams, NTTP, llvm::APSInt(Size), NTTP->getType(),
/*ArrayBound=*/true, Info, Deduced);
}
}
@@ -4700,6 +4734,11 @@ MarkUsedTemplateParameters(ASTContext &C
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
+
+ // In C++1z mode, additional arguments may be deduced from the type of a
+ // non-type argument.
+ if (Ctx.getLangOpts().CPlusPlus1z)
+ MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
@@ -4946,7 +4985,7 @@ MarkUsedTemplateParameters(ASTContext &C
case Type::UnaryTransform:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
- cast<UnaryTransformType>(T)->getUnderlyingType(),
+ cast<UnaryTransformType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Sep 28 18:55:27 2016
@@ -1179,8 +1179,8 @@ ExprResult TemplateInstantiator::transfo
cast<PackExpansionType>(parm->getType())->getPattern(),
TemplateArgs, loc, parm->getDeclName());
} else {
- type = SemaRef.SubstType(parm->getType(), TemplateArgs,
- loc, parm->getDeclName());
+ type = SemaRef.SubstType(VD ? arg.getParamTypeForDecl() : arg.getNullPtrType(),
+ TemplateArgs, loc, parm->getDeclName());
}
assert(!type.isNull() && "type substitution failed for param type");
assert(!type->isDependentType() && "param type still dependent");
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Sep 28 18:55:27 2016
@@ -1582,7 +1582,14 @@ static QualType ConvertDeclSpecToType(Ty
// template type parameter.
Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
} else {
- Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
+ // If auto appears in the declaration of a template parameter, treat
+ // the parameter as type-dependent.
+ bool IsDependent =
+ S.getLangOpts().CPlusPlus1z &&
+ declarator.getContext() == Declarator::TemplateParamContext;
+ Result = Context.getAutoType(QualType(),
+ AutoTypeKeyword::Auto,
+ IsDependent);
}
break;
@@ -2858,7 +2865,8 @@ static QualType GetDeclSpecTypeForDeclar
Error = 7; // Exception declaration
break;
case Declarator::TemplateParamContext:
- Error = 8; // Template parameter
+ if (!SemaRef.getLangOpts().CPlusPlus1z)
+ Error = 8; // Template parameter
break;
case Declarator::BlockLiteralContext:
Error = 9; // Block literal
@@ -5540,7 +5548,7 @@ static bool handleObjCOwnershipTypeAttr(
if (Class->isArcWeakrefUnavailable()) {
S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
S.Diag(ObjT->getInterfaceDecl()->getLocation(),
- diag::note_class_declared);
+ diag::note_class_declared);
}
}
}
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=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx11.cpp Wed Sep 28 18:55:27 2016
@@ -23,3 +23,7 @@ namespace CanonicalNullptr {
B<int> b = MakeB<int>();
C<int> c = MakeC<int>();
}
+
+namespace Auto {
+ template<auto> struct A { }; // expected-error {{until C++1z}}
+}
Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp?rev=282651&r1=282650&r2=282651&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp Wed Sep 28 18:55:27 2016
@@ -155,3 +155,113 @@ namespace PR24921 {
template<int> void f(int);
template<> void f<e>() {}
}
+
+namespace Auto {
+ namespace Basic {
+ // simple auto
+ template<auto x> constexpr auto constant = x; // expected-note {{declared here}}
+
+ auto v1 = constant<5>;
+ auto v2 = constant<true>;
+ auto v3 = constant<'a'>;
+ auto v4 = constant<2.5>; // expected-error {{cannot have type 'double'}}
+
+ using T1 = decltype(v1);
+ using T1 = int;
+ using T2 = decltype(v2);
+ using T2 = bool;
+ using T3 = decltype(v3);
+ using T3 = char;
+
+ // pointers
+ template<auto v> class B { };
+ template<auto* p> class B<p> { };
+ template<auto** pp> class B<pp> { };
+ template<auto* p0> int &f(B<p0> b);
+ template<auto** pp0> float &f(B<pp0> b);
+
+ int a, *b = &a;
+ int &r = f(B<&a>());
+ float &s = f(B<&b>());
+ }
+
+ namespace Chained {
+ // chained template argument deduction
+ template<long n> struct C { };
+ template<class T> struct D;
+ template<class T, T n> struct D<C<n>>
+ {
+ using Q = T;
+ };
+ using DQ = long;
+ using DQ = D<C<short(2)>>::Q;
+
+ // chained template argument deduction from an array bound
+ template<typename T> struct E;
+ template<typename T, T n> struct E<int[n]> {
+ using Q = T;
+ };
+ using EQ = E<int[short(42)]>::Q;
+ using EQ = decltype(sizeof 0);
+
+ template<int N> struct F;
+ template<typename T, T N> int foo(F<N> *) = delete; // expected-note {{explicitly deleted}}
+ void foo(void *); // expected-note {{candidate function}}
+ void bar(F<0> *p) {
+ foo(p); // expected-error {{deleted function}}
+ }
+ }
+
+ namespace ArrayToPointer {
+ constexpr char s[] = "test";
+ template<const auto* p> struct S { };
+ S<s> p;
+ }
+
+ namespace DecltypeAuto {
+ template<auto v> struct A { };
+ template<decltype(auto) v> struct DA { };
+ template<auto&> struct R { };
+
+ auto n = 0; // expected-note + {{declared here}}
+ A<n> a; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
+ DA<n> da1; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
+ DA<(n)> da2;
+ R<n> r;
+ }
+
+ namespace Decomposition {
+ double foo(int, bool);
+ template<auto& f> struct fn_result_type;
+
+ template<class R, class... Args, R (& f)(Args...)>
+ struct fn_result_type<f>
+ {
+ using type = R;
+ };
+
+ using R1 = fn_result_type<foo>::type;
+ using R1 = double;
+ }
+
+ namespace Variadic {
+ template<auto... vs> struct value_list { };
+
+ using size_t = decltype(sizeof 0);
+ template<size_t n, class List> struct nth_element;
+ template<size_t n, class List> constexpr auto nth_element_v = nth_element<n, List>::value;
+
+ template<size_t n, auto v0, auto... vs>
+ struct nth_element<n, value_list<v0, vs...>>
+ {
+ static constexpr auto value = nth_element<n - 1, value_list<vs...>>::value;
+ };
+ template<auto v0, auto... vs>
+ struct nth_element<0, value_list<v0, vs...>>
+ {
+ static constexpr auto value = v0;
+ };
+
+ static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch");
+ }
+}
More information about the cfe-commits
mailing list