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