r290586 - Work around a standard defect: template argument deduction for non-type

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 26 22:14:37 PST 2016


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 {




More information about the cfe-commits mailing list