aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/call.c
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-12-16 13:40:42 -0500
committerPatrick Palka <ppalka@redhat.com>2021-12-16 13:40:42 -0500
commitbb2a7f80a98de3febefbb32b1e4898062bdb6af8 (patch)
tree755d59d7edc782cd013dcc67e5d706e4a6a63af7 /gcc/cp/call.c
parent271e36d9d5b3a75e7f1a927e594477e6a5dd6fc0 (diff)
downloadgcc-bb2a7f80a98de3febefbb32b1e4898062bdb6af8.zip
gcc-bb2a7f80a98de3febefbb32b1e4898062bdb6af8.tar.gz
gcc-bb2a7f80a98de3febefbb32b1e4898062bdb6af8.tar.bz2
c++: two-stage name lookup for overloaded operators [PR51577]
In order to properly implement two-stage name lookup for dependent operator expressions, we need to remember the result of unqualified lookup of the operator at template definition time, and reuse that result rather than performing another unqualified lookup at instantiation time. Ideally we could just store the lookup in the expression directly, but as pointed out in r9-6405 this isn't really possible since we use the standard tree codes to represent most dependent operator expressions. We could perhaps create a new tree code to represent dependent operator expressions, with enough operands to store the lookup along with everything else, but that'd require a lot of careful work to make sure we handle this new tree code properly across the frontend. But currently type-dependent operator (and call) expressions are given an empty TREE_TYPE, which dependent_type_p treats as dependent, so this field is effectively unused except to signal that the expression is type-dependent. It'd be convenient if we could store the lookup there while preserving the dependent-ness of the expression. To that end, this patch creates a new kind of type, called DEPENDENT_OPERATOR_TYPE, which we give to dependent operator expressions and into which we can store the result of operator lookup at template definition time (DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS). Since this type is always dependent (by definition), and since the frontend doesn't seem to care much about the exact type of a type-dependent expression, using this type in place of a NULL_TREE type seems to "just work"; only dependent_type_p and WILDCARD_TYPE_P need to be adjusted to return true for this new type. The rest of the patch mostly consists of adding the necessary plumbing to pass DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS to add_operator_candidates, adjusting all callers of build_x_* appropriately, and removing the now unnecessary push_operator_bindings mechanism. In passing, this patch simplifies finish_constraint_binary_op to avoid using build_x_binary_op for building a binary constraint-expr; we don't need to consider operator overloads here, as the &&/|| inside a constraint effectively always has the built-in meaning (since atomic constraints must have bool type). This patch also makes FOLD_EXPR_OP yield a tree_code instead of a raw INTEGER_CST. Finally, this patch adds the XFAILed test operator-8.C which is about broken two-stage name lookup for rewritten non-dependent operator expressions, an existing bug that's otherwise only documented in build_new_op. PR c++/51577 PR c++/83035 PR c++/100465 gcc/cp/ChangeLog: * call.c (add_operator_candidates): Add lookups parameter. Use it to avoid performing a second unqualified lookup when instantiating a dependent operator expression. (build_new_op): Add lookups parameter and pass it appropriately. * constraint.cc (finish_constraint_binary_op): Use build_min_nt_loc instead of build_x_binary_op. * coroutines.cc (build_co_await): Adjust call to build_new_op. * cp-objcp-common.c (cp_common_init_ts): Mark DEPENDENT_OPERATOR_TYPE appropriately. * cp-tree.def (DEPENDENT_OPERATOR_TYPE): Define. * cp-tree.h (WILDCARD_TYPE_P): Accept DEPENDENT_OPERATOR_TYPE. (FOLD_EXPR_OP_RAW): New, renamed from ... (FOLD_EXPR_OP): ... this. Change this to return the tree_code directly. (DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS): Define. (templated_operator_saved_lookups): Define. (build_new_op): Add lookups parameter. (build_dependent_operator_type): Declare. (build_x_indirect_ref): Add lookups parameter. (build_x_binary_op): Likewise. (build_x_unary_op): Likewise. (build_x_compound_expr): Likewise. (build_x_modify_expr): Likewise. * cxx-pretty-print.c (get_fold_operator): Adjust after FOLD_EXPR_OP change. * decl.c (start_preparsed_function): Don't call push_operator_bindings. * decl2.c (grok_array_decl): Adjust calls to build_new_op. * method.c (do_one_comp): Likewise. (build_comparison_op): Likewise. * module.cc (trees_out::type_node): Handle DEPENDENT_OPERATOR_TYPE. (trees_in::tree_node): Likewise. * name-lookup.c (lookup_name): Revert r11-2876 change. (op_unqualified_lookup): Remove. (maybe_save_operator_binding): Remove. (discard_operator_bindings): Remove. (push_operator_bindings): Remove. * name-lookup.h (maybe_save_operator_binding): Remove. (push_operator_bindings): Remove. (discard_operator_bindings): Remove. * parser.c (cp_parser_unary_expression): Adjust calls to build_x_*. (cp_parser_binary_expression): Likewise. (cp_parser_assignment_expression): Likewise. (cp_parser_expression): Likewise. (do_range_for_auto_deduction): Likewise. (cp_convert_range_for): Likewise. (cp_parser_perform_range_for_lookup): Likewise. (cp_parser_template_argument): Likewise. (cp_parser_omp_for_cond): Likewise. (cp_parser_omp_for_incr): Likewise. (cp_parser_omp_for_loop_init): Likewise. (cp_convert_omp_range_for): Likewise. (cp_finish_omp_range_for): Likewise. * pt.c (fold_expression): Adjust after FOLD_EXPR_OP change. Pass templated_operator_saved_lookups to build_x_*. (tsubst_omp_for_iterator): Adjust call to build_x_modify_expr. (tsubst_expr) <case COMPOUND_EXPR>: Pass templated_operator_saved_lookups to build_x_*. (tsubst_copy_and_build) <case INDIRECT_REF>: Likewise. <case tcc_unary>: Likewise. <case tcc_binary>: Likewise. <case MODOP_EXPR>: Likewise. <case COMPOUND_EXPR>: Likewise. (dependent_type_p_r): Return true for DEPENDENT_OPERATOR_TYPE. * ptree.c (cxx_print_type): Handle DEPENDENT_OPERATOR_TYPE. * semantics.c (finish_increment_expr): Adjust call to build_x_unary_op. (finish_unary_op_expr): Likewise. (handle_omp_for_class_iterator): Adjust calls to build_x_*. (finish_omp_cancel): Likewise. (finish_unary_fold_expr): Use build_dependent_operator_type. (finish_binary_fold_expr): Likewise. * tree.c (cp_free_lang_data): Don't call discard_operator_bindings. * typeck.c (rationalize_conditional_expr): Adjust call to build_x_binary_op. (op_unqualified_lookup): Define. (build_dependent_operator_type): Define. (build_x_indirect_ref): Add lookups parameter and use build_dependent_operator_type. (build_x_binary_op): Likewise. (build_x_array_ref): Likewise. (build_x_unary_op): Likewise. (build_x_compound_expr_from_list): Adjust call to build_x_compound_expr. (build_x_compound_expr_from_vec): Likewise. (build_x_compound_expr): Add lookups parameter and use build_dependent_operator_type. (cp_build_modify_expr): Adjust call to build_new_op. (build_x_modify_expr): Add lookups parameter and use build_dependent_operator_type. * typeck2.c (build_x_arrow): Adjust call to build_new_op. libcc1/ChangeLog: * libcp1plugin.cc (plugin_build_unary_expr): Adjust call to build_x_unary_op. (plugin_build_binary_expr): Adjust call to build_x_binary_op. gcc/testsuite/ChangeLog: * g++.dg/lookup/operator-3.C: Split out operator overload declarations into ... * g++.dg/lookup/operator-3-ops.h: ... here. * g++.dg/lookup/operator-3a.C: New test. * g++.dg/lookup/operator-4.C: New test. * g++.dg/lookup/operator-4a.C: New test. * g++.dg/lookup/operator-5.C: New test. * g++.dg/lookup/operator-5a.C: New test. * g++.dg/lookup/operator-6.C: New test. * g++.dg/lookup/operator-7.C: New test. * g++.dg/lookup/operator-8.C: New test.
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r--gcc/cp/call.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 347df5d..495dcdd 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6285,12 +6285,17 @@ op_is_ordered (tree_code code)
/* Subroutine of build_new_op: Add to CANDIDATES all candidates for the
operator indicated by CODE/CODE2. This function calls itself recursively to
- handle C++20 rewritten comparison operator candidates. */
+ handle C++20 rewritten comparison operator candidates.
+
+ LOOKUPS, if non-NULL, is the set of pertinent namespace-scope operator
+ overloads to consider. This parameter is used when instantiating a
+ dependent operator expression and has the same structure as
+ DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS. */
static tree
add_operator_candidates (z_candidate **candidates,
tree_code code, tree_code code2,
- vec<tree, va_gc> *arglist,
+ vec<tree, va_gc> *arglist, tree lookups,
int flags, tsubst_flags_t complain)
{
z_candidate *start_candidates = *candidates;
@@ -6326,7 +6331,15 @@ add_operator_candidates (z_candidate **candidates,
consider. */
if (!memonly)
{
- tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE);
+ tree fns;
+ if (!lookups)
+ fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE);
+ /* If LOOKUPS is non-NULL, then we're instantiating a dependent operator
+ expression, and LOOKUPS is the result of stage 1 name lookup. */
+ else if (tree found = purpose_member (fnname, lookups))
+ fns = TREE_VALUE (found);
+ else
+ fns = NULL_TREE;
fns = lookup_arg_dependent (fnname, fns, arglist);
add_candidates (fns, NULL_TREE, arglist, NULL_TREE,
NULL_TREE, false, NULL_TREE, NULL_TREE,
@@ -6429,7 +6442,7 @@ add_operator_candidates (z_candidate **candidates,
if (rewrite_code != code)
/* Add rewritten candidates in same order. */
add_operator_candidates (candidates, rewrite_code, ERROR_MARK,
- arglist, flags, complain);
+ arglist, lookups, flags, complain);
z_candidate *save_cand = *candidates;
@@ -6439,7 +6452,7 @@ add_operator_candidates (z_candidate **candidates,
revlist->quick_push ((*arglist)[1]);
revlist->quick_push ((*arglist)[0]);
add_operator_candidates (candidates, rewrite_code, ERROR_MARK,
- revlist, flags, complain);
+ revlist, lookups, flags, complain);
/* Release the vec if we didn't add a candidate that uses it. */
for (z_candidate *c = *candidates; c != save_cand; c = c->next)
@@ -6457,8 +6470,8 @@ add_operator_candidates (z_candidate **candidates,
tree
build_new_op (const op_location_t &loc, enum tree_code code, int flags,
- tree arg1, tree arg2, tree arg3, tree *overload,
- tsubst_flags_t complain)
+ tree arg1, tree arg2, tree arg3, tree lookups,
+ tree *overload, tsubst_flags_t complain)
{
struct z_candidate *candidates = 0, *cand;
releasing_vec arglist;
@@ -6552,7 +6565,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
p = conversion_obstack_alloc (0);
result = add_operator_candidates (&candidates, code, code2, arglist,
- flags, complain);
+ lookups, flags, complain);
if (result == error_mark_node)
goto user_defined_result_ready;
@@ -6608,7 +6621,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
else
code = PREDECREMENT_EXPR;
result = build_new_op (loc, code, flags, arg1, NULL_TREE,
- NULL_TREE, overload, complain);
+ NULL_TREE, lookups, overload, complain);
break;
/* The caller will deal with these. */
@@ -6765,7 +6778,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
warning_sentinel ws (warn_zero_as_null_pointer_constant);
result = build_new_op (loc, code,
LOOKUP_NORMAL|LOOKUP_REWRITTEN,
- lhs, rhs, NULL_TREE,
+ lhs, rhs, NULL_TREE, lookups,
NULL, complain);
}
break;