C++ PATCH for c++/79092, auto template args of different type and same value

Jason Merrill jason@redhat.com
Thu Nov 16 21:31:00 GMT 2017


For an auto template parameter, the type of the argument matters, so
we can't treat 0 and 0u as equivalent.

But if we adjust cp_tree_equal to consider the type of a constant, we
need to be more careful about actually converting template arguments
to the type of the (non-auto) parameter, so that comparison of
template arguments works properly.  Specifically, in
g++.dg/cpp0x/temp_default7.C, unify needs to compare A<T,dummy> to
A<int,dummy>; in A<int,dummy>, dummy is implicitly converted to int,
so if we leave dummy unconverted in A<T,dummy>, we compare a constant
enumerator to a constant integer, and fail because they have different
types.  If we explicitly convert dummy in A<T,dummy> to the dependent
type of the parameter, we avoid this problem, because we can see that
the result is dependent and needs substitution before comparison.

I'm representing this conversion with a magic-ish IMPLICIT_CONV_EXPR,
marked for this situation.  We only add it in cases that are not
value-dependent, and therefore would only be used for comparison
rather than deduction.  In tsubst_copy_and_build we just drop these
once they become non-dependent, as the result will go back through
convert_template_argument.

Checking at this point for value-dependence required implementation of
a recent core DR that clarifies that all type-dependent expressions
are also value-dependent; previously I have felt that we shouldn't
even ask whether a type-dependent expression is value-dependent, but
now I see that this simplifies things.

I'm a bit unsure about treating DEFERRED_NOEXCEPT as non-dependent,
but it seems necessary, since non-template functions can have
DEFERRED_NOEXCEPT, and those certainly won't be dependent.

Tested x86_64-pc-linux-gnu, applying to trunk.
-------------- next part --------------
commit 5cf3f26db8e0d89e207453bbd9fd4c1a8cf79631
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 25 15:42:54 2017 -0400

            PR c++/79092 - non-type args of different types are different
    
            * tree.c (cp_tree_equal): Check the type of constants.
            * pt.c (unify) [TEMPLATE_PARM_INDEX]: Handle UNIFY_ALLOW_INTEGER
            when comparing to previously deduced argument.
            (maybe_convert_nontype_argument): New.
            (convert_nontype_argument): Call it.
            (tsubst_copy_and_build): Handle partial instantiation of
            IMPLICIT_CONV_EXPR.
            (unify): Ignore type when deducing from array bound.
            (dependent_type_p_r): Handle DEFERRED_NOEXCEPT.
            (value_dependent_expression_p): Any type-dependent expression is
            value-dependent.  Handle IMPLICIT_CONV_EXPR.
            * cp-tree.h (IMPLICIT_CONV_EXPR_NONTYPE_ARG): New.
            * mangle.c (write_template_arg): Strip IMPLICIT_CONV_EXPR.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c6554162078..1c19c3d31f8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -382,6 +382,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       TINFO_USED_TEMPLATE_ID (in TEMPLATE_INFO)
       PACK_EXPANSION_SIZEOF_P (in *_PACK_EXPANSION)
       OVL_USING_P (in OVERLOAD)
+      IMPLICIT_CONV_EXPR_NONTYPE_ARG (in IMPLICIT_CONV_EXPR)
    2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -4126,6 +4127,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \
   (TREE_LANG_FLAG_0 (IMPLICIT_CONV_EXPR_CHECK (NODE)))
 
+/* True if NODE represents a dependent conversion of a non-type template
+   argument.  Set by maybe_convert_nontype_argument.  */
+#define IMPLICIT_CONV_EXPR_NONTYPE_ARG(NODE) \
+  (TREE_LANG_FLAG_1 (IMPLICIT_CONV_EXPR_CHECK (NODE)))
+
 /* Nonzero means that an object of this type can not be initialized using
    an initializer list.  */
 #define CLASSTYPE_NON_AGGREGATE(NODE) \
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 050055bd26c..6d4e59101ee 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2836,7 +2836,7 @@ write_expression (tree expr)
   while (CONVERT_EXPR_CODE_P (code)
 	 /* Parentheses aren't mangled.  */
 	 || code == PAREN_EXPR
-	 || TREE_CODE (expr) == NON_LVALUE_EXPR)
+	 || code == NON_LVALUE_EXPR)
     {
       expr = TREE_OPERAND (expr, 0);
       code = TREE_CODE (expr);
@@ -3407,6 +3407,9 @@ write_template_arg (tree node)
 	}
     }
 
+  /* Strip a conversion added by convert_nontype_argument.  */
+  if (TREE_CODE (node) == IMPLICIT_CONV_EXPR)
+    node = TREE_OPERAND (node, 0);
   if (REFERENCE_REF_P (node))
     node = TREE_OPERAND (node, 0);
   if (TREE_CODE (node) == NOP_EXPR
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 562b9272596..2b70969999e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7519,6 +7519,31 @@ convert_wildcard_argument (tree parm, tree arg)
   return arg;
 }
 
+/* We can't fully resolve ARG given as a non-type template argument to TYPE,
+   because one of them is dependent.  But we need to represent the
+   conversion for the benefit of cp_tree_equal.  */
+
+static tree
+maybe_convert_nontype_argument (tree type, tree arg)
+{
+  /* Auto parms get no conversion.  */
+  if (type_uses_auto (type))
+    return arg;
+  /* We don't need or want to add this conversion now if we're going to use the
+     argument for deduction.  */
+  if (value_dependent_expression_p (arg))
+    return arg;
+
+  type = cv_unqualified (type);
+  tree argtype = TREE_TYPE (arg);
+  if (same_type_p (type, argtype))
+    return arg;
+
+  arg = build1 (IMPLICIT_CONV_EXPR, type, arg);
+  IMPLICIT_CONV_EXPR_NONTYPE_ARG (arg) = true;
+  return arg;
+}
+
 /* Convert the indicated template ARG as necessary to match the
    indicated template PARM.  Returns the converted ARG, or
    error_mark_node if the conversion was unsuccessful.  Error and
@@ -7774,7 +7799,11 @@ convert_template_argument (tree parm,
 	   argument specification is valid.  */
 	val = convert_nontype_argument (t, orig_arg, complain);
       else
-	val = canonicalize_expr_argument (orig_arg, complain);
+	{
+	  val = canonicalize_expr_argument (orig_arg, complain);
+	  val = maybe_convert_nontype_argument (t, val);
+	}
+
 
       if (val == NULL_TREE)
 	val = error_mark_node;
@@ -17097,6 +17126,17 @@ tsubst_copy_and_build (tree t,
       {
 	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	tree expr = RECUR (TREE_OPERAND (t, 0));
+	if (dependent_type_p (type) || type_dependent_expression_p (expr))
+	  {
+	    retval = copy_node (t);
+	    TREE_TYPE (retval) = type;
+	    TREE_OPERAND (retval, 0) = expr;
+	    RETURN (retval);
+	  }
+	if (IMPLICIT_CONV_EXPR_NONTYPE_ARG (t))
+	  /* We'll pass this to convert_nontype_argument again, we don't need
+	     to actually perform any conversion here.  */
+	  RETURN (expr);
 	int flags = LOOKUP_IMPLICIT;
 	if (IMPLICIT_CONV_EXPR_DIRECT_INIT (t))
 	  flags = LOOKUP_NORMAL;
@@ -20886,6 +20926,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 
       if (targ)
 	{
+	  if ((strict & UNIFY_ALLOW_INTEGER)
+	      && TREE_TYPE (targ) && TREE_TYPE (arg)
+	      && CP_INTEGRAL_TYPE_P (TREE_TYPE (targ)))
+	    /* We're deducing from an array bound, the type doesn't matter.  */
+	    arg = fold_convert (TREE_TYPE (targ), arg);
 	  int x = !cp_tree_equal (targ, arg);
 	  if (x)
 	    unify_inconsistency (explain_p, parm, targ, arg);
@@ -23704,13 +23749,15 @@ dependent_type_p_r (tree type)
 	if (dependent_type_p (TREE_VALUE (arg_type)))
 	  return true;
       if (cxx_dialect >= cxx17)
-	{
-	  /* A value-dependent noexcept-specifier makes the type dependent.  */
-	  tree spec = TYPE_RAISES_EXCEPTIONS (type);
-	  if (spec && TREE_PURPOSE (spec)
-	      && value_dependent_expression_p (TREE_PURPOSE (spec)))
-	    return true;
-	}
+	/* A value-dependent noexcept-specifier makes the type dependent.  */
+	if (tree spec = TYPE_RAISES_EXCEPTIONS (type))
+	  if (tree noex = TREE_PURPOSE (spec))
+	    /* Treat DEFERRED_NOEXCEPT as non-dependent, since it doesn't
+	       affect overload resolution and treating it as dependent breaks
+	       things.  */
+	    if (TREE_CODE (noex) != DEFERRED_NOEXCEPT
+		&& value_dependent_expression_p (noex))
+	      return true;
       return false;
     }
   /* -- an array type constructed from any dependent type or whose
@@ -23875,8 +23922,8 @@ value_dependent_expression_p (tree expression)
   if (!processing_template_decl || expression == NULL_TREE)
     return false;
 
-  /* A name declared with a dependent type.  */
-  if (DECL_P (expression) && type_dependent_expression_p (expression))
+  /* A type-dependent expression is also value-dependent.  */
+  if (type_dependent_expression_p (expression))
     return true;
 
   switch (TREE_CODE (expression))
@@ -23918,13 +23965,12 @@ value_dependent_expression_p (tree expression)
 	  && (TREE_CODE (DECL_INITIAL (expression)) == TREE_LIST
 	      /* cp_finish_decl doesn't fold reference initializers.  */
 	      || TREE_CODE (TREE_TYPE (expression)) == REFERENCE_TYPE
-	      || type_dependent_expression_p (DECL_INITIAL (expression))
 	      || value_dependent_expression_p (DECL_INITIAL (expression))))
 	return true;
       if (DECL_HAS_VALUE_EXPR_P (expression))
 	{
 	  tree value_expr = DECL_VALUE_EXPR (expression);
-	  if (type_dependent_expression_p (value_expr))
+	  if (value_dependent_expression_p (value_expr))
 	    return true;
 	}
       return false;
@@ -23934,6 +23980,7 @@ value_dependent_expression_p (tree expression)
     case CONST_CAST_EXPR:
     case REINTERPRET_CAST_EXPR:
     case CAST_EXPR:
+    case IMPLICIT_CONV_EXPR:
       /* These expressions are value-dependent if the type to which
 	 the cast occurs is dependent or the expression being casted
 	 is value-dependent.  */
@@ -24078,10 +24125,7 @@ value_dependent_expression_p (tree expression)
       }
 
     case TEMPLATE_ID_EXPR:
-      /* If a TEMPLATE_ID_EXPR involves a dependent name, it will be
-	 type-dependent.  */
-      return type_dependent_expression_p (expression)
-	|| variable_concept_p (TREE_OPERAND (expression, 0));
+      return variable_concept_p (TREE_OPERAND (expression, 0));
 
     case CONSTRUCTOR:
       {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c60d54ab01f..245657866df 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3494,6 +3494,10 @@ cp_tree_equal (tree t1, tree t2)
   if (code1 != code2)
     return false;
 
+  if (CONSTANT_CLASS_P (t1)
+      && !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return false;
+
   switch (code1)
     {
     case VOID_CST:
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype-auto12.C b/gcc/testsuite/g++.dg/cpp1z/nontype-auto12.C
new file mode 100644
index 00000000000..7bff75c3484
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype-auto12.C
@@ -0,0 +1,6 @@
+// PR c++/79092
+// { dg-options -std=c++17 }
+
+template<auto V> struct val {};
+
+struct type : val<0>, val<0u> {};


More information about the Gcc-patches mailing list