diff mbox series

[v1] c++: Eagerly substitute auto constraint args in tsubst [PR115030]

Message ID CAPJwJpcGu4iKOiUhbiR3e-2j1-wCT==vCmsmrNFdghzTdRQZmw@mail.gmail.com
State New
Headers show
Series [v1] c++: Eagerly substitute auto constraint args in tsubst [PR115030] | expand

Commit Message

Seyed Sajad Kahani July 9, 2024, 1:43 p.m. UTC
This patch addresses a bug in constrained auto deduction (C++/PR115030) by
modifying tsubst to eagerly substitute the constraint args of an auto node.
This change avoids the complexity of finding outer_targs during
do_auto_deduction.

Note that outer_targs cannot be completely removed but will be set to TREE_NULL
in all calls except the one for

template <typename T, C<T> auto V>
struct S { };

Substituting constraint arguments earlier will slightly alter error messages,
changing the errors from constraint satisfaction to template substitution /
deduction errors.

PR c++/115030

gcc/cp/ChangeLog:

* constraint.cc (type_deducible_p): Remove outer_targs from do_auto_deduction
call.
* cp-tree.h (do_auto_deduction): Remove tmpl from the signature.
* decl.cc (cp_finish_decl): Remove outer_targs from do_auto_deduction call
and the corresponding code to set it from DECL_TI_ARGS.
* pt.cc (convert_template_argument): Remove tmpl from do_auto_deduction call.
(tsubst): Strengthen the check for using the cache from
TEMPLATE_TYPE_DESCENDANTS. Substitute the constraint args and the auto node
itself, while retaining all other parameters as is.
(unify): Remove tmpl and outer_targs from do_auto_deduction call.
(do_auto_deduction): Remove the tmpl argument and its related code, remove
the part that sets outer_targs from current_function_decl and change the hack
to use TEMPLATE_TYPE_LEVEL.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-placeholder14.C: New test.
---
gcc/cp/constraint.cc | 3 +-
gcc/cp/cp-tree.h | 3 +-
gcc/cp/decl.cc | 11 +--
gcc/cp/pt.cc | 73 ++++++++++---------
.../g++.dg/cpp2a/concepts-placeholder14.C | 20 +++++
5 files changed, 60 insertions(+), 50 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
diff mbox series

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index ebf4255e5..6ea791812 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2088,8 +2088,7 @@  type_deducible_p (tree expr, tree type, tree
placeholder, tree args,
expr = force_paren_expr_uneval (expr);
tree deduced_type = do_auto_deduction (type, expr, placeholder,
- info.complain, adc_requirement,
- /*outer_targs=*/args);
+ info.complain, adc_requirement);
return deduced_type != error_mark_node;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4bb3e9c49..961537f9f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7521,8 +7521,7 @@  extern tree do_auto_deduction (tree, tree, tree,
auto_deduction_context
= adc_unspecified,
tree = NULL_TREE,
- int = LOOKUP_NORMAL,
- tree = NULL_TREE);
+ int = LOOKUP_NORMAL);
extern tree type_uses_auto (tree);
extern tree type_uses_auto_or_concept (tree);
extern void append_type_to_template_for_access_check (tree, tree, tree,
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 29616100c..773370b48 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8567,18 +8567,9 @@  cp_finish_decl (tree decl, tree init, bool
init_const_expr_p,
enum auto_deduction_context adc = adc_variable_type;
if (DECL_DECOMPOSITION_P (decl))
adc = adc_decomp_type;
- tree outer_targs = NULL_TREE;
- if (PLACEHOLDER_TYPE_CONSTRAINTS_INFO (auto_node)
- && DECL_LANG_SPECIFIC (decl)
- && DECL_TEMPLATE_INFO (decl)
- && !DECL_FUNCTION_SCOPE_P (decl))
- /* The outer template arguments might be needed for satisfaction.
- (For function scope variables, do_auto_deduction will obtain the
- outer template arguments from current_function_decl.) */
- outer_targs = DECL_TI_ARGS (decl);
type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
tf_warning_or_error, adc,
- outer_targs, flags);
+ NULL_TREE, flags);
if (type == error_mark_node)
return;
if (TREE_CODE (type) == FUNCTION_TYPE)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d1316483e..fdd641e5c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8781,7 +8781,7 @@  convert_template_argument (tree parm,
else if (tree a = type_uses_auto (t))
{
t = do_auto_deduction (t, arg, a, complain, adc_unify, args,
- LOOKUP_IMPLICIT, /*tmpl=*/in_decl);
+ LOOKUP_IMPLICIT);
if (t == error_mark_node)
return error_mark_node;
}
@@ -16506,8 +16506,8 @@  tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
if (tree d = TEMPLATE_TYPE_DESCENDANTS (t))
if (TEMPLATE_PARM_LEVEL (d) == TEMPLATE_TYPE_LEVEL (t) - levels
- && (code == TEMPLATE_TYPE_PARM
- || TEMPLATE_TEMPLATE_PARM_SIMPLE_P (t)))
+ && ((code == TEMPLATE_TYPE_PARM && !PLACEHOLDER_TYPE_CONSTRAINTS_INFO(t))
+ || (code == TEMPLATE_TEMPLATE_PARM && TEMPLATE_TEMPLATE_PARM_SIMPLE_P (t))))
/* Cache lowering a type parameter or a simple template
template parameter. */
r = TREE_TYPE (d);
@@ -16515,6 +16515,32 @@  tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
if (!r)
{
r = copy_type (t);
+
+ if (code == TEMPLATE_TYPE_PARM)
+ if (tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t))
+ {
+ tree cparms = TREE_PURPOSE (ci);
+
+ tree auto_vec = make_tree_vec (1);
+ TREE_VEC_ELT (auto_vec, 0) = r;
+ tree extra = template_parms_to_args (cparms);
+ extra = add_outermost_template_args (extra, auto_vec);
+ extra = get_innermost_template_args(extra, level - levels);
+ tree full_args = add_to_template_args (args, extra);
+
+ tree cexpr
+ = tsubst_constraint (TREE_VALUE (ci), full_args, complain, in_decl);
+
+ if (cexpr == error_mark_node)
+ return error_mark_node;
+
+ PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r)
+ = build_tree_list(cparms, cexpr);
+
+ /* reduce_template_parm_level needs proper canonical type */
+ TYPE_CANONICAL (r) = canonical_type_parameter (r);
+ }
+
TEMPLATE_TYPE_PARM_INDEX (r)
= reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
r, levels, args, complain);
@@ -16523,12 +16549,6 @@  tsubst (tree t, tree args, tsubst_flags_t
complain, tree in_decl)
TYPE_POINTER_TO (r) = NULL_TREE;
TYPE_REFERENCE_TO (r) = NULL_TREE;
- if (code == TEMPLATE_TYPE_PARM)
- if (tree ci = PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t))
- /* Propagate constraints on placeholders since they are
- only instantiated during satisfaction. */
- PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci;
-
if (TYPE_STRUCTURAL_EQUALITY_P (t))
SET_TYPE_STRUCTURAL_EQUALITY (r);
else
@@ -24915,9 +24935,8 @@  unify (tree tparms, tree targs, tree parm,
tree arg, int strict,
if (tree a = type_uses_auto (tparm))
{
tparm = do_auto_deduction (tparm, arg, a,
- complain, adc_unify, targs,
- LOOKUP_NORMAL,
- TPARMS_PRIMARY_TEMPLATE (tparms));
+ complain, adc_unify, NULL_TREE,
+ LOOKUP_NORMAL);
if (tparm == error_mark_node)
return 1;
}
@@ -31116,8 +31135,7 @@  do_auto_deduction (tree type, tree init, tree auto_node,
tsubst_flags_t complain /* = tf_warning_or_error */,
auto_deduction_context context /* = adc_unspecified */,
tree outer_targs /* = NULL_TREE */,
- int flags /* = LOOKUP_NORMAL */,
- tree tmpl /* = NULL_TREE */)
+ int flags /* = LOOKUP_NORMAL */)
{
if (type == error_mark_node || init == error_mark_node)
return error_mark_node;
@@ -31287,28 +31305,7 @@  do_auto_deduction (tree type, tree init, tree
auto_node,
return type;
}
- if (context == adc_return_type
- || context == adc_variable_type
- || context == adc_decomp_type)
- if (tree fn = current_function_decl)
- if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
- {
- outer_targs = DECL_TEMPLATE_INFO (fn)
- ? DECL_TI_ARGS (fn) : NULL_TREE;
- if (LAMBDA_FUNCTION_P (fn))
- {
- /* As in satisfy_declaration_constraints. */
- tree regen_args = lambda_regenerating_args (fn);
- if (outer_targs)
- outer_targs = add_to_template_args (regen_args, outer_targs);
- else
- outer_targs = regen_args;
- }
- }
-
tree full_targs = outer_targs;
- if (context == adc_unify && tmpl)
- full_targs = add_outermost_template_args (tmpl, full_targs);
full_targs = add_to_template_args (full_targs, targs);
/* HACK: Compensate for callers not always communicating all levels of
@@ -31318,9 +31315,13 @@  do_auto_deduction (tree type, tree init, tree
auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
+ if (int missing_levels = (TEMPLATE_TYPE_LEVEL (auto_node)
- TMPL_ARGS_DEPTH (full_targs)))
{
+ /* For example the case that
+ template <typename T> is_same<bool> auto x = true;
+ will end up here, because it will be deduced before instantiation */
+ gcc_assert (missing_levels > 0);
tree dummy_levels = make_tree_vec (missing_levels);
for (int i = 0; i < missing_levels; ++i)
TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..a8bd48e39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,20 @@ 
+// PR c++/115030
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template <typename T>
+struct s {
+};
+
+template <typename T>
+char v = 'a';
+
+template<typename T>
+C<T> auto v<s<T>> = 'c';
+
+int main() {
+ v<s<char>> = 'b';
+ return 0;
+}