forked from OSchip/llvm-project
Work around a standard defect: template argument deduction for non-type
template parameters of reference type basically doesn't work, because we're always deducing from an argument expression of non-reference type, so the type of the deduced expression never matches. Instead, compare the type of an expression naming the parameter to the type of the argument. llvm-svn: 290586
This commit is contained in:
parent
ce04489515
commit
d92eddf02d
|
@ -5040,7 +5040,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
"non-type template parameter type cannot be qualified");
|
||||
|
||||
if (CTAK == CTAK_Deduced &&
|
||||
!Context.hasSameUnqualifiedType(ParamType, Arg->getType())) {
|
||||
!Context.hasSameType(ParamType.getNonLValueExprType(Context),
|
||||
Arg->getType().getNonLValueExprType(Context))) {
|
||||
// C++ [temp.deduct.type]p17: (DR1770)
|
||||
// If P has a form that contains <i>, and if the type of i differs from
|
||||
// the type of the corresponding template parameter of the template named
|
||||
|
@ -5048,6 +5049,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
//
|
||||
// Note that CTAK will be CTAK_DeducedFromArrayBound if the form was [i]
|
||||
// rather than <i>.
|
||||
//
|
||||
// FIXME: We interpret the 'i' here as referring to the expression
|
||||
// denoting the non-type template parameter rather than the parameter
|
||||
// itself, and so strip off references before comparing types. It's
|
||||
// not clear how this is supposed to work for references.
|
||||
Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
|
||||
<< Arg->getType().getUnqualifiedType()
|
||||
<< ParamType.getUnqualifiedType();
|
||||
|
|
|
@ -327,13 +327,18 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
|
|||
}
|
||||
|
||||
Deduced[NTTP->getIndex()] = Result;
|
||||
return S.getLangOpts().CPlusPlus1z
|
||||
? DeduceTemplateArgumentsByTypeMatch(
|
||||
S, TemplateParams, NTTP->getType(), ValueType, Info, Deduced,
|
||||
TDF_ParamWithReferenceType | TDF_SkipNonDependent,
|
||||
/*PartialOrdering=*/false,
|
||||
/*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound())
|
||||
: Sema::TDK_Success;
|
||||
if (!S.getLangOpts().CPlusPlus1z)
|
||||
return Sema::TDK_Success;
|
||||
|
||||
// FIXME: It's not clear how deduction of a parameter of reference
|
||||
// type from an argument (of non-reference type) should be performed.
|
||||
// For now, we just remove reference types from both sides and let
|
||||
// the final check for matching types sort out the mess.
|
||||
return DeduceTemplateArgumentsByTypeMatch(
|
||||
S, TemplateParams, NTTP->getType().getNonReferenceType(),
|
||||
ValueType.getNonReferenceType(), Info, Deduced, TDF_SkipNonDependent,
|
||||
/*PartialOrdering=*/false,
|
||||
/*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound());
|
||||
}
|
||||
|
||||
/// \brief Deduce the value of the given non-type template parameter
|
||||
|
|
|
@ -374,3 +374,28 @@ namespace partial_order_different_types {
|
|||
template<typename T, typename U, U V> struct A<0, 0, T, U, V> {}; // expected-note {{matches}}
|
||||
A<0, 0, int, int, 0> a; // expected-error {{ambiguous partial specializations}}
|
||||
}
|
||||
|
||||
namespace partial_order_references {
|
||||
// FIXME: The standard does not appear to consider the second specialization
|
||||
// to be more more specialized than the first! The problem is that deducing
|
||||
// an 'int&' parameter from an argument 'R' results in a type mismatch,
|
||||
// because the parameter has a reference type and the argument is an
|
||||
// expression and thus does not have reference type. We resolve this by
|
||||
// matching the type of an expression corresponding to the parameter rather
|
||||
// than matching the parameter itself.
|
||||
template <int, int, int &> struct A {};
|
||||
template <int N, int &R> struct A<N, 0, R> {};
|
||||
template <int &R> struct A<0, 0, R> {};
|
||||
int N;
|
||||
A<0, 0, N> a;
|
||||
|
||||
// FIXME: These should both be rejected as they are not more specialized than
|
||||
// the primary template (they can never be used due to the type mismatch).
|
||||
template<int, int &R> struct B; // expected-note {{template}}
|
||||
template<const int &R> struct B<0, R> {};
|
||||
B<0, N> b; // expected-error {{undefined}}
|
||||
|
||||
template<int, const int &R> struct C; // expected-note {{template}}
|
||||
template<int &R> struct C<0, R> {};
|
||||
C<0, N> c; // expected-error {{undefined}}
|
||||
}
|
||||
|
|
|
@ -278,6 +278,12 @@ namespace Auto {
|
|||
|
||||
using R1 = fn_result_type<foo>::type;
|
||||
using R1 = double;
|
||||
|
||||
template<int, auto &f> struct fn_result_type_partial_order;
|
||||
template<auto &f> struct fn_result_type_partial_order<0, f>;
|
||||
template<class R, class... Args, R (& f)(Args...)>
|
||||
struct fn_result_type_partial_order<0, f> {};
|
||||
fn_result_type_partial_order<0, foo> frtpo;
|
||||
}
|
||||
|
||||
namespace Variadic {
|
||||
|
|
Loading…
Reference in New Issue