summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaTemplate.cpp28
-rw-r--r--test/SemaTemplate/class-template-spec.cpp12
-rw-r--r--test/SemaTemplate/partial-order.cpp14
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp16
-rw-r--r--test/SemaTemplate/temp_arg_template_cxx1z.cpp8
5 files changed, 48 insertions, 30 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 8ad5b5951e..ad1e89a0ca 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -5127,18 +5127,22 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CTAK == CTAK_Deduced &&
!Context.hasSameType(ParamType.getNonLValueExprType(Context),
Arg->getType())) {
- // 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
- // by the enclosing simple-template-id, deduction fails.
- //
- // 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.
+ // FIXME: If either type is dependent, we skip the check. This isn't
+ // correct, since during deduction we're supposed to have replaced each
+ // template parameter with some unique (non-dependent) placeholder.
+ // FIXME: If the argument type contains 'auto', we carry on and fail the
+ // type check in order to force specific types to be more specialized than
+ // 'auto'. It's not clear how partial ordering with 'auto' is supposed to
+ // work.
+ if ((ParamType->isDependentType() || Arg->isTypeDependent()) &&
+ !Arg->getType()->getContainedAutoType()) {
+ Converted = TemplateArgument(Arg);
+ return Arg;
+ }
+ // FIXME: This attempts to implement C++ [temp.deduct.type]p17. Per DR1770,
+ // we should actually be checking the type of the template argument in P,
+ // not the type of the template argument deduced from A, against the
+ // template parameter type.
Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
<< Arg->getType()
<< ParamType.getUnqualifiedType();
diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp
index 518ec78e6f..00e03ef61e 100644
--- a/test/SemaTemplate/class-template-spec.cpp
+++ b/test/SemaTemplate/class-template-spec.cpp
@@ -207,19 +207,19 @@ namespace NTTPTypeVsPartialOrder {
struct X { typedef int value_type; };
template<typename T> struct Y { typedef T value_type; };
- template<typename T, typename T::value_type N> struct A; // expected-note {{template}}
+ template<typename T, typename T::value_type N> struct A;
template<int N> struct A<X, N> {};
- template<typename T, T N> struct A<Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}}
+ template<typename T, T N> struct A<Y<T>, N> {};
A<X, 0> ax;
A<Y<int>, 0> ay;
- template<int, typename T, typename T::value_type> struct B; // expected-note {{template}}
- template<typename T, typename T::value_type N> struct B<0, T, N>; // expected-note {{matches}}
+ template<int, typename T, typename T::value_type> struct B;
+ template<typename T, typename T::value_type N> struct B<0, T, N>;
template<int N> struct B<0, X, N> {};
- template<typename T, T N> struct B<0, Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}} expected-note {{matches}}
+ template<typename T, T N> struct B<0, Y<T>, N> {};
B<0, X, 0> bx;
- B<0, Y<int>, 0> by; // expected-error {{ambiguous}}
+ B<0, Y<int>, 0> by;
}
namespace DefaultArgVsPartialSpec {
diff --git a/test/SemaTemplate/partial-order.cpp b/test/SemaTemplate/partial-order.cpp
new file mode 100644
index 0000000000..0a151de390
--- /dev/null
+++ b/test/SemaTemplate/partial-order.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++1z %s -verify
+
+// expected-no-diagnostics
+
+namespace hana_enable_if_idiom {
+ template<bool> struct A {};
+ template<typename, typename = A<true>> struct B;
+ template<typename T, bool N> struct B<T, A<N>> {};
+ template<typename T> struct B<T, A<T::value>> {};
+ struct C {
+ static const bool value = true;
+ };
+ B<C> b;
+}
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 27a0a03f84..5b72b8c654 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -370,13 +370,13 @@ namespace PR17696 {
}
namespace partial_order_different_types {
- // These are unordered because the type of the final argument doesn't match.
- template<int, int, typename T, typename, T> struct A; // expected-note {{here}}
- template<int N, typename T, typename U, T V> struct A<0, N, T, U, V> {}; // expected-note {{matches}}
- template<typename T, typename U, U V> struct A<0, 0, T, U, V> {}; // expected-note {{matches}}
- // expected-error@-1 {{not more specialized than the primary}}
- // expected-note@-2 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('U' vs 'type-parameter-0-0')}}
- A<0, 0, int, int, 0> a; // expected-error {{ambiguous partial specializations}}
+ template<int, int, typename T, typename, T> struct A;
+ template<int N, typename T, typename U, T V> struct A<0, N, T, U, V>; // expected-note {{matches}}
+ // FIXME: It appears that this partial specialization should be ill-formed as
+ // it is not more specialized than the primary template. V is not deducible
+ // because it does not have the same type as the corresponding parameter.
+ template<int N, typename T, typename U, U V> struct A<0, N, T, U, V> {}; // expected-note {{matches}}
+ A<0, 0, int, int, 0> a; // expected-error {{ambiguous}}
}
namespace partial_order_references {
@@ -434,7 +434,7 @@ namespace dependent_nested_partial_specialization {
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}}
+ template<typename W, T V> struct F<W, V> {}; // expected-error {{not more specialized than the primary}}
};
E<int>::F<int, 0> e1; // expected-note {{instantiation of}}
}
diff --git a/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/test/SemaTemplate/temp_arg_template_cxx1z.cpp
index aa517c3285..703935dcd5 100644
--- a/test/SemaTemplate/temp_arg_template_cxx1z.cpp
+++ b/test/SemaTemplate/temp_arg_template_cxx1z.cpp
@@ -79,13 +79,13 @@ namespace Auto {
TInt<Auto> ia;
TInt<AutoPtr> iap; // expected-error {{different template parameters}}
- TInt<DecltypeAuto> ida; // FIXME expected-error {{different template parameters}}
+ TInt<DecltypeAuto> ida;
TInt<Int> ii;
TInt<IntPtr> iip; // expected-error {{different template parameters}}
TIntPtr<Auto> ipa;
TIntPtr<AutoPtr> ipap;
- TIntPtr<DecltypeAuto> ipda; // FIXME expected-error {{different template parameters}}
+ TIntPtr<DecltypeAuto> ipda;
TIntPtr<Int> ipi; // expected-error {{different template parameters}}
TIntPtr<IntPtr> ipip;
@@ -114,6 +114,6 @@ namespace Auto {
int n;
template<auto A, decltype(A) B = &n> struct SubstFailure;
- TInt<SubstFailure> isf; // expected-error {{different template parameters}}
- TIntPtr<SubstFailure> ipsf; // expected-error {{different template parameters}}
+ TInt<SubstFailure> isf; // FIXME: this should be ill-formed
+ TIntPtr<SubstFailure> ipsf;
}