forked from OSchip/llvm-project
When merging two deduced non-type template arguments for the same parameter,
fail the merge if the arguments have different types (except if one of them was deduced from an array bound, in which case take the type from the other). This is correct because (except in the array bound case) the type of the template argument in each deduction must match the type of the parameter, so at least one of the two deduced arguments must have a mismatched type. This is necessary because we would otherwise lose the type information for the discarded template argument in the merge, and fail to diagnose the mismatch. In order to power this, we now properly retain the type of a deduced non-type template argument deduced from a declaration, rather than giving it the type of the template parameter; we'll convert it to the template parameter type when checking the deduced arguments. llvm-svn: 290399
This commit is contained in:
parent
fcd33149b4
commit
593d6a168f
|
@ -301,6 +301,10 @@ public:
|
||||||
Integer.Type = T.getAsOpaquePtr();
|
Integer.Type = T.getAsOpaquePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief If this is a non-type template argument, get its type. Otherwise,
|
||||||
|
/// returns a null QualType.
|
||||||
|
QualType getNonTypeTemplateArgumentType() const;
|
||||||
|
|
||||||
/// \brief Retrieve the template argument as an expression.
|
/// \brief Retrieve the template argument as an expression.
|
||||||
Expr *getAsExpr() const {
|
Expr *getAsExpr() const {
|
||||||
assert(getKind() == Expression && "Unexpected kind");
|
assert(getKind() == Expression && "Unexpected kind");
|
||||||
|
|
|
@ -3343,6 +3343,10 @@ def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored:
|
||||||
def note_ovl_candidate_inconsistent_deduction : Note<
|
def note_ovl_candidate_inconsistent_deduction : Note<
|
||||||
"candidate template ignored: deduced conflicting %select{types|values|"
|
"candidate template ignored: deduced conflicting %select{types|values|"
|
||||||
"templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">;
|
"templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">;
|
||||||
|
def note_ovl_candidate_inconsistent_deduction_types : Note<
|
||||||
|
"candidate template ignored: deduced values %diff{"
|
||||||
|
"of conflicting types for parameter %0 (%1 of type $ vs. %3 of type $)|"
|
||||||
|
"%1 and %3 of conflicting types for parameter %0|}2,4">;
|
||||||
def note_ovl_candidate_explicit_arg_mismatch_named : Note<
|
def note_ovl_candidate_explicit_arg_mismatch_named : Note<
|
||||||
"candidate template ignored: invalid explicitly-specified argument "
|
"candidate template ignored: invalid explicitly-specified argument "
|
||||||
"for template parameter %0">;
|
"for template parameter %0">;
|
||||||
|
@ -3840,7 +3844,7 @@ def err_non_type_template_parm_type_deduction_failure : Error<
|
||||||
"non-type template parameter %0 with type %1 has incompatible initializer of type %2">;
|
"non-type template parameter %0 with type %1 has incompatible initializer of type %2">;
|
||||||
def err_deduced_non_type_template_arg_type_mismatch : Error<
|
def err_deduced_non_type_template_arg_type_mismatch : Error<
|
||||||
"deduced non-type template argument does not have the same type as the "
|
"deduced non-type template argument does not have the same type as the "
|
||||||
"its corresponding template parameter%diff{ ($ vs $)|}0,1">;
|
"corresponding template parameter%diff{ ($ vs $)|}0,1">;
|
||||||
def err_non_type_template_arg_subobject : Error<
|
def err_non_type_template_arg_subobject : Error<
|
||||||
"non-type template argument refers to subobject '%0'">;
|
"non-type template argument refers to subobject '%0'">;
|
||||||
def err_non_type_template_arg_addr_label_diff : Error<
|
def err_non_type_template_arg_addr_label_diff : Error<
|
||||||
|
|
|
@ -243,6 +243,31 @@ Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
|
||||||
|
switch (getKind()) {
|
||||||
|
case TemplateArgument::Null:
|
||||||
|
case TemplateArgument::Type:
|
||||||
|
case TemplateArgument::Template:
|
||||||
|
case TemplateArgument::TemplateExpansion:
|
||||||
|
case TemplateArgument::Pack:
|
||||||
|
return QualType();
|
||||||
|
|
||||||
|
case TemplateArgument::Integral:
|
||||||
|
return getIntegralType();
|
||||||
|
|
||||||
|
case TemplateArgument::Expression:
|
||||||
|
return getAsExpr()->getType();
|
||||||
|
|
||||||
|
case TemplateArgument::Declaration:
|
||||||
|
return getParamTypeForDecl();
|
||||||
|
|
||||||
|
case TemplateArgument::NullPtr:
|
||||||
|
return getNullPtrType();
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("Invalid TemplateArgument Kind!");
|
||||||
|
}
|
||||||
|
|
||||||
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
|
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
|
||||||
const ASTContext &Context) const {
|
const ASTContext &Context) const {
|
||||||
ID.AddInteger(getKind());
|
ID.AddInteger(getKind());
|
||||||
|
|
|
@ -9593,9 +9593,25 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
|
||||||
int which = 0;
|
int which = 0;
|
||||||
if (isa<TemplateTypeParmDecl>(ParamD))
|
if (isa<TemplateTypeParmDecl>(ParamD))
|
||||||
which = 0;
|
which = 0;
|
||||||
else if (isa<NonTypeTemplateParmDecl>(ParamD))
|
else if (isa<NonTypeTemplateParmDecl>(ParamD)) {
|
||||||
|
// Deduction might have failed because we deduced arguments of two
|
||||||
|
// different types for a non-type template parameter.
|
||||||
|
// FIXME: Use a different TDK value for this.
|
||||||
|
QualType T1 =
|
||||||
|
DeductionFailure.getFirstArg()->getNonTypeTemplateArgumentType();
|
||||||
|
QualType T2 =
|
||||||
|
DeductionFailure.getSecondArg()->getNonTypeTemplateArgumentType();
|
||||||
|
if (!S.Context.hasSameType(T1, T2)) {
|
||||||
|
S.Diag(Templated->getLocation(),
|
||||||
|
diag::note_ovl_candidate_inconsistent_deduction_types)
|
||||||
|
<< ParamD->getDeclName() << *DeductionFailure.getFirstArg() << T1
|
||||||
|
<< *DeductionFailure.getSecondArg() << T2;
|
||||||
|
MaybeEmitInheritedConstructorNote(S, Found);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
which = 1;
|
which = 1;
|
||||||
else {
|
} else {
|
||||||
which = 2;
|
which = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,20 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
||||||
if (Y.isNull())
|
if (Y.isNull())
|
||||||
return X;
|
return X;
|
||||||
|
|
||||||
|
// If we have two non-type template argument values deduced for the same
|
||||||
|
// parameter, they must both match the type of the parameter, and thus must
|
||||||
|
// match each other's type. As we're only keeping one of them, we must check
|
||||||
|
// for that now. The exception is that if either was deduced from an array
|
||||||
|
// bound, the type is permitted to differ.
|
||||||
|
if (!X.wasDeducedFromArrayBound() && !Y.wasDeducedFromArrayBound()) {
|
||||||
|
QualType XType = X.getNonTypeTemplateArgumentType();
|
||||||
|
if (!XType.isNull()) {
|
||||||
|
QualType YType = Y.getNonTypeTemplateArgumentType();
|
||||||
|
if (YType.isNull() || !Context.hasSameType(XType, YType))
|
||||||
|
return DeducedTemplateArgument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (X.getKind()) {
|
switch (X.getKind()) {
|
||||||
case TemplateArgument::Null:
|
case TemplateArgument::Null:
|
||||||
llvm_unreachable("Non-deduced template arguments handled above");
|
llvm_unreachable("Non-deduced template arguments handled above");
|
||||||
|
@ -184,9 +198,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
||||||
Y.getKind() == TemplateArgument::Declaration ||
|
Y.getKind() == TemplateArgument::Declaration ||
|
||||||
(Y.getKind() == TemplateArgument::Integral &&
|
(Y.getKind() == TemplateArgument::Integral &&
|
||||||
hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
|
hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
|
||||||
return DeducedTemplateArgument(X,
|
return X.wasDeducedFromArrayBound() ? Y : X;
|
||||||
X.wasDeducedFromArrayBound() &&
|
|
||||||
Y.wasDeducedFromArrayBound());
|
|
||||||
|
|
||||||
// All other combinations are incompatible.
|
// All other combinations are incompatible.
|
||||||
return DeducedTemplateArgument();
|
return DeducedTemplateArgument();
|
||||||
|
@ -208,37 +220,38 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
||||||
// All other combinations are incompatible.
|
// All other combinations are incompatible.
|
||||||
return DeducedTemplateArgument();
|
return DeducedTemplateArgument();
|
||||||
|
|
||||||
case TemplateArgument::Expression:
|
case TemplateArgument::Expression: {
|
||||||
// If we deduced a dependent expression in one case and either an integral
|
if (Y.getKind() != TemplateArgument::Expression)
|
||||||
// constant or a declaration in another case, keep the integral constant
|
return checkDeducedTemplateArguments(Context, Y, X);
|
||||||
// or declaration.
|
|
||||||
if (Y.getKind() == TemplateArgument::Integral ||
|
|
||||||
Y.getKind() == TemplateArgument::Declaration)
|
|
||||||
return DeducedTemplateArgument(Y, X.wasDeducedFromArrayBound() &&
|
|
||||||
Y.wasDeducedFromArrayBound());
|
|
||||||
|
|
||||||
if (Y.getKind() == TemplateArgument::Expression) {
|
// Compare the expressions for equality
|
||||||
// Compare the expressions for equality
|
llvm::FoldingSetNodeID ID1, ID2;
|
||||||
llvm::FoldingSetNodeID ID1, ID2;
|
X.getAsExpr()->Profile(ID1, Context, true);
|
||||||
X.getAsExpr()->Profile(ID1, Context, true);
|
Y.getAsExpr()->Profile(ID2, Context, true);
|
||||||
Y.getAsExpr()->Profile(ID2, Context, true);
|
if (ID1 == ID2)
|
||||||
if (ID1 == ID2)
|
return X.wasDeducedFromArrayBound() ? Y : X;
|
||||||
return X;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All other combinations are incompatible.
|
// Differing dependent expressions are incompatible.
|
||||||
return DeducedTemplateArgument();
|
return DeducedTemplateArgument();
|
||||||
|
}
|
||||||
|
|
||||||
case TemplateArgument::Declaration:
|
case TemplateArgument::Declaration:
|
||||||
|
assert(!X.wasDeducedFromArrayBound());
|
||||||
|
|
||||||
// If we deduced a declaration and a dependent expression, keep the
|
// If we deduced a declaration and a dependent expression, keep the
|
||||||
// declaration.
|
// declaration.
|
||||||
if (Y.getKind() == TemplateArgument::Expression)
|
if (Y.getKind() == TemplateArgument::Expression)
|
||||||
return X;
|
return X;
|
||||||
|
|
||||||
// If we deduced a declaration and an integral constant, keep the
|
// If we deduced a declaration and an integral constant, keep the
|
||||||
// integral constant.
|
// integral constant and whichever type did not come from an array
|
||||||
if (Y.getKind() == TemplateArgument::Integral)
|
// bound.
|
||||||
|
if (Y.getKind() == TemplateArgument::Integral) {
|
||||||
|
if (Y.wasDeducedFromArrayBound())
|
||||||
|
return TemplateArgument(Context, Y.getAsIntegral(),
|
||||||
|
X.getParamTypeForDecl());
|
||||||
return Y;
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
// If we deduced two declarations, make sure they they refer to the
|
// If we deduced two declarations, make sure they they refer to the
|
||||||
// same declaration.
|
// same declaration.
|
||||||
|
@ -260,9 +273,8 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
||||||
if (Y.getKind() == TemplateArgument::Integral)
|
if (Y.getKind() == TemplateArgument::Integral)
|
||||||
return Y;
|
return Y;
|
||||||
|
|
||||||
// If we deduced two null pointers, make sure they have the same type.
|
// If we deduced two null pointers, they are the same.
|
||||||
if (Y.getKind() == TemplateArgument::NullPtr &&
|
if (Y.getKind() == TemplateArgument::NullPtr)
|
||||||
Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType()))
|
|
||||||
return X;
|
return X;
|
||||||
|
|
||||||
// All other combinations are incompatible.
|
// All other combinations are incompatible.
|
||||||
|
@ -405,7 +417,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
|
||||||
"Cannot deduce non-type template argument with depth > 0");
|
"Cannot deduce non-type template argument with depth > 0");
|
||||||
|
|
||||||
D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
|
D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
|
||||||
TemplateArgument New(D, NTTP->getType());
|
TemplateArgument New(D, T);
|
||||||
DeducedTemplateArgument NewDeduced(New);
|
DeducedTemplateArgument NewDeduced(New);
|
||||||
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
|
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
|
||||||
Deduced[NTTP->getIndex()],
|
Deduced[NTTP->getIndex()],
|
||||||
|
@ -1685,7 +1697,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
|
||||||
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
|
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
|
||||||
ArgSize = VectorArg->getNumElements();
|
ArgSize = VectorArg->getNumElements();
|
||||||
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
|
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
|
||||||
S.Context.IntTy, false, Info, Deduced);
|
S.Context.IntTy, false, Info,
|
||||||
|
Deduced);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const DependentSizedExtVectorType *VectorArg
|
if (const DependentSizedExtVectorType *VectorArg
|
||||||
|
|
|
@ -32,8 +32,11 @@ namespace PR6707 {
|
||||||
static const unsigned char ten = 10;
|
static const unsigned char ten = 10;
|
||||||
template<typename T, T Value, typename U>
|
template<typename T, T Value, typename U>
|
||||||
void f2(X<T, Value>, X<U, Value>);
|
void f2(X<T, Value>, X<U, Value>);
|
||||||
|
// expected-note@-1 {{candidate template ignored: deduced values of conflicting types for parameter 'Value' (10 of type 'int' vs. 10 of type 'char')}}
|
||||||
|
// expected-note@-2 {{candidate template ignored: deduced values of conflicting types for parameter 'Value' (10 of type 'char' vs. 10 of type 'int')}}
|
||||||
|
|
||||||
void g2() {
|
void g2() {
|
||||||
f2(X<int, 10>(), X<char, ten>());
|
f2(X<int, 10>(), X<char, ten>()); // expected-error {{no matching}}
|
||||||
|
f2(X<char, 10>(), X<int, ten>()); // expected-error {{no matching}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
|
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z
|
||||||
|
|
||||||
// Template argument deduction with template template parameters.
|
// Template argument deduction with template template parameters.
|
||||||
template<typename T, template<T> class A>
|
template<typename T, template<T> class A>
|
||||||
|
@ -266,10 +267,72 @@ int main() {
|
||||||
} // end ns2
|
} // end ns2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace multiple_deduction_different_type {
|
||||||
|
template<typename T, T v> struct X {};
|
||||||
|
template<template<typename T, T> class X, typename T, typename U, int N>
|
||||||
|
void f(X<T, N>, X<U, N>) {} // expected-note 2{{values of conflicting types}}
|
||||||
|
template<template<typename T, T> class X, typename T, typename U, const int *N>
|
||||||
|
void g(X<T, N>, X<U, N>) {} // expected-note 0-2{{values of conflicting types}}
|
||||||
|
int n;
|
||||||
|
void h() {
|
||||||
|
f(X<int, 1+1>(), X<unsigned int, 3-1>()); // expected-error {{no matching function}}
|
||||||
|
f(X<unsigned int, 1+1>(), X<int, 3-1>()); // expected-error {{no matching function}}
|
||||||
|
#if __cplusplus > 201402L
|
||||||
|
g(X<const int*, &n>(), X<int*, &n + 1 - 1>()); // expected-error {{no matching function}}
|
||||||
|
g(X<int*, &n>(), X<const int*, &n + 1 - 1>()); // expected-error {{no matching function}}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<typename T, T> class X, typename T, typename U, T N>
|
||||||
|
void x(X<T, N>, int(*)[N], X<U, N>) {} // expected-note 1+{{candidate}}
|
||||||
|
template<template<typename T, T> class X, typename T, typename U, T N>
|
||||||
|
void x(int(*)[N], X<T, N>, X<U, N>) {} // expected-note 1+{{candidate}}
|
||||||
|
int arr[3];
|
||||||
|
void y() {
|
||||||
|
x(X<int, 3>(), &arr, X<int, 3>());
|
||||||
|
x(&arr, X<int, 3>(), X<int, 3>());
|
||||||
|
|
||||||
|
x(X<int, 3>(), &arr, X<char, 3>()); // expected-error {{no matching function}}
|
||||||
|
x(&arr, X<int, 3>(), X<char, 3>()); // expected-error {{no matching function}}
|
||||||
|
|
||||||
|
x(X<char, 3>(), &arr, X<char, 3>());
|
||||||
|
x(&arr, X<char, 3>(), X<char, 3>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace nullptr_deduction {
|
namespace nullptr_deduction {
|
||||||
|
using nullptr_t = decltype(nullptr);
|
||||||
|
|
||||||
template<typename T, T v> struct X {};
|
template<typename T, T v> struct X {};
|
||||||
template<typename T, T v> void f(X<T, v>) {
|
template<typename T, T v> void f(X<T, v>) {
|
||||||
static_assert(!v, "");
|
static_assert(!v, "");
|
||||||
}
|
}
|
||||||
void g() { f(X<int*, nullptr>()); }
|
void g() {
|
||||||
|
f(X<int*, nullptr>());
|
||||||
|
f(X<nullptr_t, nullptr>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<typename T, T> class X, typename T, typename U, int *P>
|
||||||
|
void f1(X<T, P>, X<U, P>) {} // expected-note 2{{values of conflicting types}}
|
||||||
|
void h() {
|
||||||
|
f1(X<int*, nullptr>(), X<nullptr_t, nullptr>()); // expected-error {{no matching function}}
|
||||||
|
f1(X<nullptr_t, nullptr>(), X<int*, nullptr>()); // expected-error {{no matching function}}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<template<typename T, T> class X, typename T, typename U, nullptr_t P>
|
||||||
|
void f2(X<T, P>, X<U, P>) {} // expected-note 2{{values of conflicting types}}
|
||||||
|
void i() {
|
||||||
|
f2(X<int*, nullptr>(), X<nullptr_t, nullptr>()); // expected-error {{no matching function}}
|
||||||
|
f2(X<nullptr_t, nullptr>(), X<int*, nullptr>()); // expected-error {{no matching function}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace member_pointer {
|
||||||
|
struct A { void f(int); };
|
||||||
|
template<typename T, void (A::*F)(T)> struct B;
|
||||||
|
template<typename T> struct C;
|
||||||
|
template<typename T, void (A::*F)(T)> struct C<B<T, F>> {
|
||||||
|
C() { A a; T t; (a.*F)(t); }
|
||||||
|
};
|
||||||
|
C<B<int, &A::f>> c;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue