diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1c19f67cb0fc2d9b10b76fc7695a4a6641d8057a..2920ede3b5eea3de477e0ab2e6a8e2fa993edfac 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -5123,18 +5123,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 518ec78e6f7d03a4cb935fa0911a04f8611e614a..00e03ef61eb07fe3a3ef526ba2fdd0e8d31f7249 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 0000000000000000000000000000000000000000..0a151de3902361ca9c7de168fe43d7cf839cc0e4 --- /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 27a0a03f84f462c9083c972de38d90401ba30bdf..5b72b8c6549a4ac1e4f5f811d1d985ee81f3d96f 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 aa517c32859937e2bec2e267ce06f562f7b6314c..703935dcd5c19bfa76e6634a02fa379b11c19462 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; }