Author: rsmith Date: Tue Dec 27 00:14:37 2016 New Revision: 290586 URL: http://llvm.org/viewvc/llvm-project?rev=290586&view=rev Log: 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.
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=290586&r1=290585&r2=290586&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 27 00:14:37 2016 @@ -5040,7 +5040,8 @@ ExprResult Sema::CheckTemplateArgument(N "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(N // // 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(); Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=290586&r1=290585&r2=290586&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Dec 27 00:14:37 2016 @@ -327,13 +327,18 @@ static Sema::TemplateDeductionResult Ded } 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 Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=290586&r1=290585&r2=290586&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Dec 27 00:14:37 2016 @@ -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}} +} Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp?rev=290586&r1=290585&r2=290586&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp Tue Dec 27 00:14:37 2016 @@ -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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits