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.
Expr *getAsExpr() const {
assert(getKind() == Expression && "Unexpected kind");
def note_ovl_candidate_inconsistent_deduction : Note<
"candidate template ignored: deduced conflicting %select{types|values|"
"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<
"candidate template ignored: invalid explicitly-specified argument "
"for template parameter %0">;
"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">;
+ "corresponding template parameter%diff{ ($ vs $)|}0,1">;
def err_non_type_template_arg_subobject : Error<
"non-type template argument refers to subobject '%0'">;
def err_non_type_template_arg_addr_label_diff : Error<
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,
const ASTContext &Context) const {
ID.AddInteger(getKind());
int which = 0;
if (isa<TemplateTypeParmDecl>(ParamD))
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;
- else {
+ } else {
which = 2;
}
if (Y.isNull())
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()) {
case TemplateArgument::Null:
llvm_unreachable("Non-deduced template arguments handled above");
Y.getKind() == TemplateArgument::Declaration ||
(Y.getKind() == TemplateArgument::Integral &&
hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
- return DeducedTemplateArgument(X,
- X.wasDeducedFromArrayBound() &&
- Y.wasDeducedFromArrayBound());
+ return X.wasDeducedFromArrayBound() ? Y : X;
// All other combinations are incompatible.
return DeducedTemplateArgument();
// All other combinations are incompatible.
return DeducedTemplateArgument();
- case TemplateArgument::Expression:
- // If we deduced a dependent expression in one case and either an integral
- // constant or a declaration in another case, keep the integral constant
- // 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
- llvm::FoldingSetNodeID ID1, ID2;
- X.getAsExpr()->Profile(ID1, Context, true);
- Y.getAsExpr()->Profile(ID2, Context, true);
- if (ID1 == ID2)
- return X;
- }
+ case TemplateArgument::Expression: {
+ if (Y.getKind() != TemplateArgument::Expression)
+ return checkDeducedTemplateArguments(Context, Y, X);
+
+ // Compare the expressions for equality
+ llvm::FoldingSetNodeID ID1, ID2;
+ X.getAsExpr()->Profile(ID1, Context, true);
+ Y.getAsExpr()->Profile(ID2, Context, true);
+ if (ID1 == ID2)
+ return X.wasDeducedFromArrayBound() ? Y : X;
- // All other combinations are incompatible.
+ // Differing dependent expressions are incompatible.
return DeducedTemplateArgument();
+ }
case TemplateArgument::Declaration:
+ assert(!X.wasDeducedFromArrayBound());
+
// If we deduced a declaration and a dependent expression, keep the
// declaration.
if (Y.getKind() == TemplateArgument::Expression)
return X;
// If we deduced a declaration and an integral constant, keep the
- // integral constant.
- if (Y.getKind() == TemplateArgument::Integral)
+ // integral constant and whichever type did not come from an array
+ // bound.
+ if (Y.getKind() == TemplateArgument::Integral) {
+ if (Y.wasDeducedFromArrayBound())
+ return TemplateArgument(Context, Y.getAsIntegral(),
+ X.getParamTypeForDecl());
return Y;
+ }
// If we deduced two declarations, make sure they they refer to the
// same declaration.
if (Y.getKind() == TemplateArgument::Integral)
return Y;
- // If we deduced two null pointers, make sure they have the same type.
- if (Y.getKind() == TemplateArgument::NullPtr &&
- Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType()))
+ // If we deduced two null pointers, they are the same.
+ if (Y.getKind() == TemplateArgument::NullPtr)
return X;
// All other combinations are incompatible.
"Cannot deduce non-type template argument with depth > 0");
D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
- TemplateArgument New(D, NTTP->getType());
+ TemplateArgument New(D, T);
DeducedTemplateArgument NewDeduced(New);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
ArgSize = VectorArg->getNumElements();
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
- S.Context.IntTy, false, Info, Deduced);
+ S.Context.IntTy, false, Info,
+ Deduced);
}
if (const DependentSizedExtVectorType *VectorArg
static const unsigned char ten = 10;
template<typename T, T Value, typename U>
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() {
- 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}}
}
}
// 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<typename T, template<T> class A>
} // 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 {
+ using nullptr_t = decltype(nullptr);
+
template<typename T, T v> struct X {};
template<typename T, T v> void f(X<T, 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;
}