diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 347df5da35d16e299effcadbfa1a6b199e612ffa..495dcdd77b3b8cfa89406c88c38655bfd2dfec95 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; diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 566f4e38fac9a1e8664da1c6f0bd7799709fa343..8e25ae2367028b95c05c8ea6857aef0cb6cca0e6 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -202,15 +202,8 @@ finish_constraint_binary_op (location_t loc, return error_mark_node; if (!check_constraint_operands (loc, lhs, rhs)) return error_mark_node; - tree overload; - cp_expr expr = build_x_binary_op (loc, code, - lhs, TREE_CODE (lhs), - rhs, TREE_CODE (rhs), - &overload, tf_none); - /* When either operand is dependent, the overload set may be non-empty. */ - if (expr == error_mark_node) - return error_mark_node; - expr.set_location (loc); + cp_expr expr + = build_min_nt_loc (loc, code, lhs.get_value (), rhs.get_value ()); expr.set_range (lhs.get_start (), rhs.get_finish ()); return expr; } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 9017902e6fb6f5ea3a5b15ec77bd8d61ee4b5588..c00672eeb6e73b87fe63657d2dfca241e62c771a 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -912,7 +912,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) if (MAYBE_CLASS_TYPE_P (TREE_TYPE (a))) { o = build_new_op (loc, CO_AWAIT_EXPR, LOOKUP_NORMAL, a, NULL_TREE, - NULL_TREE, NULL, tf_warning_or_error); + NULL_TREE, NULL_TREE, NULL, tf_warning_or_error); /* If no viable functions are found, o is a. */ if (!o || o == error_mark_node) o = a; diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 38eae881f0c11322efbb235f7d9f86a856916e08..36e04cdee5eaa28168146583ee862b77d7966897 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -484,6 +484,7 @@ cp_common_init_ts (void) /* New Types. */ MARK_TS_TYPE_COMMON (UNBOUND_CLASS_TEMPLATE); MARK_TS_TYPE_COMMON (TYPE_ARGUMENT_PACK); + MARK_TS_TYPE_COMMON (DEPENDENT_OPERATOR_TYPE); MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE); MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE); diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 725139bb457ce07f7eb722c01756118a1b7a1fee..6fb838cc850eb03c6a70f0fa75ef26eb36622e14 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -476,6 +476,11 @@ DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0) BASES_TYPE is the type in question. */ DEFTREECODE (BASES, "bases", tcc_type, 0) +/* Dependent operator expressions are given this type rather than a NULL_TREE + type so that we have somewhere to stash the result of phase 1 name lookup + (namely into DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS). */ +DEFTREECODE (DEPENDENT_OPERATOR_TYPE, "dependent_operator_type", tcc_type, 0) + /* Used to represent the template information stored by template specializations. The accessors are: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7f32cf56383cf4131eee704122f0df86ef53f4c2..9eff4349181d78d4305a7db196b862191dbee8e7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2185,7 +2185,8 @@ enum languages { lang_c, lang_cplusplus }; || TREE_CODE (T) == TYPENAME_TYPE \ || TREE_CODE (T) == TYPEOF_TYPE \ || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \ - || TREE_CODE (T) == DECLTYPE_TYPE) + || TREE_CODE (T) == DECLTYPE_TYPE \ + || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE) /* Nonzero if T is a class (or struct or union) type. Also nonzero for template type parameters, typename types, and instantiated @@ -3978,9 +3979,13 @@ struct GTY(()) lang_decl { TREE_LANG_FLAG_0 (FOLD_EXPR_CHECK (NODE)) /* An INTEGER_CST containing the tree code of the folded operator. */ -#define FOLD_EXPR_OP(NODE) \ +#define FOLD_EXPR_OP_RAW(NODE) \ TREE_OPERAND (FOLD_EXPR_CHECK (NODE), 0) +/* The tree code of the folded operator. */ +#define FOLD_EXPR_OP(NODE) \ + ((enum tree_code) TREE_INT_CST_LOW (FOLD_EXPR_OP_RAW (NODE))) + /* The expression containing an unexpanded parameter pack. */ #define FOLD_EXPR_PACK(NODE) \ TREE_OPERAND (FOLD_EXPR_CHECK (NODE), 1) @@ -4035,6 +4040,26 @@ struct GTY(()) lang_decl { #define CALL_EXPR_OPERATOR_SYNTAX(NODE) \ TREE_LANG_FLAG_6 (CALL_OR_AGGR_INIT_CHECK (NODE)) +/* A TREE_LIST containing the result of phase 1 name lookup of the operator + overloads that are pertinent to the dependent operator expression whose + type is NODE. Each TREE_PURPOSE is an IDENTIFIER_NODE and TREE_VALUE is + the corresponding (possibly empty) lookup result. The TREE_TYPE of the + first TREE_LIST node points back to NODE. */ +#define DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS(NODE) \ + TYPE_VALUES_RAW (DEPENDENT_OPERATOR_TYPE_CHECK (NODE)) + +/* Guarded helper for the above accessor macro that takes a (templated) + operator expression instead of the type thereof. */ +inline tree +templated_operator_saved_lookups (tree t) +{ + tree type = TREE_TYPE (EXPR_CHECK (t)); + if (type && TREE_CODE (type) == DEPENDENT_OPERATOR_TYPE) + return DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (type); + else + return NULL_TREE; +} + /* Indicates whether a string literal has been parenthesized. Such usages are disallowed in certain circumstances. */ @@ -6464,14 +6489,15 @@ extern tree build_special_member_call (tree, tree, tree, int, tsubst_flags_t); extern tree build_new_op (const op_location_t &, enum tree_code, - int, tree, tree, tree, tree *, - tsubst_flags_t); + int, tree, tree, tree, tree, + tree *, tsubst_flags_t); /* Wrapper that leaves out the usually-null op3 and overload parms. */ inline tree build_new_op (const op_location_t &loc, enum tree_code code, int flags, tree arg1, tree arg2, tsubst_flags_t complain) { - return build_new_op (loc, code, flags, arg1, arg2, NULL_TREE, NULL, complain); + return build_new_op (loc, code, flags, arg1, arg2, NULL_TREE, NULL_TREE, + NULL, complain); } extern tree build_op_call (tree, vec<tree, va_gc> **, tsubst_flags_t); @@ -7875,8 +7901,9 @@ extern tree build_class_member_access_expr (cp_expr, tree, tree, bool, extern tree finish_class_member_access_expr (cp_expr, tree, bool, tsubst_flags_t); extern tree lookup_destructor (tree, tree, tree, tsubst_flags_t); +extern tree build_dependent_operator_type (tree, enum tree_code, bool); extern tree build_x_indirect_ref (location_t, tree, - ref_operator, + ref_operator, tree, tsubst_flags_t); extern tree cp_build_indirect_ref (location_t, tree, ref_operator, @@ -7894,20 +7921,20 @@ extern tree cp_build_function_call_vec (tree, vec<tree, va_gc> **, extern tree build_x_binary_op (const op_location_t &, enum tree_code, tree, enum tree_code, tree, - enum tree_code, tree *, - tsubst_flags_t); + enum tree_code, tree, + tree *, tsubst_flags_t); inline tree build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1, tree arg2, tsubst_flags_t complain) { return build_x_binary_op (loc, code, arg1, TREE_CODE (arg1), arg2, - TREE_CODE (arg2), NULL, complain); + TREE_CODE (arg2), NULL_TREE, NULL, complain); } extern tree build_x_array_ref (location_t, tree, tree, tsubst_flags_t); extern tree build_x_unary_op (location_t, enum tree_code, cp_expr, - tsubst_flags_t); + tree, tsubst_flags_t); extern tree cp_build_addressof (location_t, tree, tsubst_flags_t); extern tree cp_build_addr_expr (tree, tsubst_flags_t); @@ -7922,7 +7949,7 @@ extern tree build_x_compound_expr_from_list (tree, expr_list_kind, extern tree build_x_compound_expr_from_vec (vec<tree, va_gc> *, const char *, tsubst_flags_t); extern tree build_x_compound_expr (location_t, tree, tree, - tsubst_flags_t); + tree, tsubst_flags_t); extern tree build_compound_expr (location_t, tree, tree); extern tree cp_build_compound_expr (tree, tree, tsubst_flags_t); extern tree build_static_cast (location_t, tree, tree, @@ -7938,7 +7965,7 @@ extern tree cp_build_c_cast (location_t, tree, tree, tsubst_flags_t); extern cp_expr build_x_modify_expr (location_t, tree, enum tree_code, tree, - tsubst_flags_t); + tree, tsubst_flags_t); extern tree cp_build_modify_expr (location_t, tree, enum tree_code, tree, tsubst_flags_t); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 3ea357deb80cb0a3f51df5cfcd1e9328f5ad1463..6af009c68907a6132b780d94de2c614274902b6a 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2541,8 +2541,8 @@ pp_cxx_addressof_expression (cxx_pretty_printer *pp, tree t) static char const* get_fold_operator (tree t) { - int op = int_cst_value (FOLD_EXPR_OP (t)); - ovl_op_info_t *info = OVL_OP_INFO (FOLD_EXPR_MODIFY_P (t), op); + ovl_op_info_t *info = OVL_OP_INFO (FOLD_EXPR_MODIFY_P (t), + FOLD_EXPR_OP (t)); return info->name; } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 2e0339858c33c35bfbb18f1f04b033cb55413aec..7ca8770bd025a58dc7d1bf309129c91594aab3b0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -17118,8 +17118,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags) store_parm_decls (current_function_parms); - push_operator_bindings (); - if (!processing_template_decl && (flag_lifetime_dse > 1) && DECL_CONSTRUCTOR_P (decl1) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 99f5dc784b7b57a0924dca0700ccc5929eda5cfb..062c175430bf85522a033431cff5a7c309fdc87b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -417,7 +417,8 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, { if (index_exp) expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, - index_exp, NULL_TREE, &overload, complain); + index_exp, NULL_TREE, NULL_TREE, + &overload, complain); else if ((*index_exp_list)->is_empty ()) expr = build_op_subscript (loc, array_expr, index_exp_list, &overload, complain); @@ -431,7 +432,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, tf_none); if (idx != error_mark_node) expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, - idx, NULL_TREE, &overload, + idx, NULL_TREE, NULL_TREE, &overload, complain & tf_decltype); if (expr == error_mark_node) { diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 935946f5eefb25a1353e9fc63fe868565aa471d5..44439bae4ec7e6153e7bb6d8d74a5f7c7a8e8bd2 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1372,7 +1372,7 @@ do_one_comp (location_t loc, const comp_info &info, tree sub, tree lhs, tree rhs to </=, so don't give an error yet if <=> lookup fails. */ bool tentative = retcat != cc_last; tree comp = build_new_op (loc, code, flags, lhs, rhs, - NULL_TREE, &overload, + NULL_TREE, NULL_TREE, &overload, tentative ? tf_none : complain); if (code != SPACESHIP_EXPR) @@ -1684,8 +1684,8 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain) comp = retval = var; } eq = build_new_op (info.loc, EQ_EXPR, flags, comp, - integer_zero_node, NULL_TREE, NULL, - complain); + integer_zero_node, NULL_TREE, NULL_TREE, + NULL, complain); } tree ceq = contextual_conv_bool (eq, complain); info.check (ceq); @@ -1720,7 +1720,7 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain) else if (code == NE_EXPR) { tree comp = build_new_op (info.loc, EQ_EXPR, flags, lhs, rhs, - NULL_TREE, NULL, complain); + NULL_TREE, NULL_TREE, NULL, complain); comp = contextual_conv_bool (comp, complain); info.check (comp); if (defining) @@ -1732,9 +1732,9 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain) else { tree comp = build_new_op (info.loc, SPACESHIP_EXPR, flags, lhs, rhs, - NULL_TREE, NULL, complain); + NULL_TREE, NULL_TREE, NULL, complain); tree comp2 = build_new_op (info.loc, code, flags, comp, integer_zero_node, - NULL_TREE, NULL, complain); + NULL_TREE, NULL_TREE, NULL, complain); info.check (comp2); if (defining) finish_return_stmt (comp2); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 9266055cd92472734cfaaddfb86eed4b73723fe1..f3e7af22699ce64152fbf46304c5e75a2a491005 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8789,6 +8789,7 @@ trees_out::type_node (tree type) case DECLTYPE_TYPE: case TYPEOF_TYPE: case UNDERLYING_TYPE: + case DEPENDENT_OPERATOR_TYPE: tree_node (TYPE_VALUES_RAW (type)); if (TREE_CODE (type) == DECLTYPE_TYPE) /* We stash a whole bunch of things into decltype's @@ -9311,6 +9312,7 @@ trees_in::tree_node (bool is_use) case DECLTYPE_TYPE: case TYPEOF_TYPE: case UNDERLYING_TYPE: + case DEPENDENT_OPERATOR_TYPE: { tree expr = tree_node (); if (!get_overrun ()) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 6b5e434959587abfff4e8e6bfb0aa55841e68923..3bd7b206abb51b996ab0256b61a79da00d5428dc 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -7725,20 +7725,14 @@ lookup_name (tree name, LOOK_where where, LOOK_want want) if (binding) { - /* The saved lookups for an operator record 'nothing - found' as error_mark_node. We need to stop the search - here, but not return the error mark node. */ - if (binding == error_mark_node) - binding = NULL_TREE; - val = binding; - goto found; + break; } } } /* Now lookup in namespace scopes. */ - if (bool (where & LOOK_where::NAMESPACE)) + if (!val && bool (where & LOOK_where::NAMESPACE)) { name_lookup lookup (name, want); if (lookup.search_unqualified @@ -7746,8 +7740,6 @@ lookup_name (tree name, LOOK_where where, LOOK_want want) val = lookup.value; } - found:; - /* If we have a known type overload, pull it out. This can happen for both using decls and unhidden functions. */ if (val && TREE_CODE (val) == OVERLOAD && TREE_TYPE (val) != unknown_type_node) @@ -8949,125 +8941,4 @@ cp_emit_debug_info_for_using (tree t, tree context) } } -/* Return the result of unqualified lookup for the overloaded operator - designated by CODE, if we are in a template and the binding we find is - not. */ - -static tree -op_unqualified_lookup (tree fnname) -{ - if (cxx_binding *binding = IDENTIFIER_BINDING (fnname)) - { - cp_binding_level *l = binding->scope; - while (l && !l->this_entity) - l = l->level_chain; - - if (l && uses_template_parms (l->this_entity)) - /* Don't preserve decls from an uninstantiated template, - wait until that template is instantiated. */ - return NULL_TREE; - } - - tree fns = lookup_name (fnname); - if (!fns) - /* Remember we found nothing! */ - return error_mark_node; - - tree d = fns; - if (TREE_CODE (d) == TREE_LIST) - d = TREE_VALUE (d); - if (is_overloaded_fn (d)) - d = get_first_fn (d); - if (DECL_CLASS_SCOPE_P (d)) - /* We don't need to remember class-scope functions or declarations, - normal unqualified lookup will find them again. */ - return NULL_TREE; - - return fns; -} - -/* E is an expression representing an operation with dependent type, so we - don't know yet whether it will use the built-in meaning of the operator or a - function. Remember declarations of that operator in scope. - - We then inject a fake binding of that lookup into the - instantiation's parameter scope. This approach fails if the user - has different using declarations or directives in different local - binding of the current function from whence we need to do lookups - (we'll cache what we see on the first lookup). */ - -static const char *const op_bind_attrname = "operator bindings"; - -void -maybe_save_operator_binding (tree e) -{ - /* This is only useful in a template. */ - if (!processing_template_decl) - return; - - tree cfn = current_function_decl; - if (!cfn) - return; - - tree fnname; - if(TREE_CODE (e) == MODOP_EXPR) - fnname = ovl_op_identifier (true, TREE_CODE (TREE_OPERAND (e, 1))); - else - fnname = ovl_op_identifier (false, TREE_CODE (e)); - if (!fnname || fnname == assign_op_identifier) - return; - - tree attributes = DECL_ATTRIBUTES (cfn); - tree op_attr = lookup_attribute (op_bind_attrname, attributes); - if (!op_attr) - { - tree *ap = &DECL_ATTRIBUTES (cfn); - while (*ap && ATTR_IS_DEPENDENT (*ap)) - ap = &TREE_CHAIN (*ap); - op_attr = tree_cons (get_identifier (op_bind_attrname), - NULL_TREE, *ap); - *ap = op_attr; - } - - tree op_bind = purpose_member (fnname, TREE_VALUE (op_attr)); - if (!op_bind) - { - tree fns = op_unqualified_lookup (fnname); - - /* Always record, so we don't keep looking for this - operator. */ - TREE_VALUE (op_attr) = tree_cons (fnname, fns, TREE_VALUE (op_attr)); - } -} - -/* Called from cp_free_lang_data so we don't put this into LTO. */ - -void -discard_operator_bindings (tree decl) -{ - DECL_ATTRIBUTES (decl) = remove_attribute (op_bind_attrname, - DECL_ATTRIBUTES (decl)); -} - -/* Subroutine of start_preparsed_function: push the bindings we saved away in - maybe_save_op_lookup into the function parameter binding level. */ - -void -push_operator_bindings () -{ - tree decl1 = current_function_decl; - if (tree attr = lookup_attribute (op_bind_attrname, - DECL_ATTRIBUTES (decl1))) - for (tree binds = TREE_VALUE (attr); binds; binds = TREE_CHAIN (binds)) - if (tree val = TREE_VALUE (binds)) - { - tree name = TREE_PURPOSE (binds); - if (TREE_CODE (val) == TREE_LIST) - for (tree v = val; v; v = TREE_CHAIN (v)) - push_local_binding (name, TREE_VALUE (v), /*using*/true); - else - push_local_binding (name, val, /*using*/true); - } -} - #include "gt-cp-name-lookup.h" diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index f63c4f5b8bb885464b66286d9a2de012c506bd8a..db705d20c68b85cc40faf4ecb709f165b8d66d79 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -465,10 +465,7 @@ extern void push_nested_namespace (tree); extern void pop_nested_namespace (tree); extern void push_to_top_level (void); extern void pop_from_top_level (void); -extern void maybe_save_operator_binding (tree); -extern void push_operator_bindings (void); extern void push_using_decl_bindings (tree, tree); -extern void discard_operator_bindings (tree); /* Lower level interface for modules. */ extern tree *mergeable_namespace_slots (tree ns, tree name, bool is_global, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c2564e51e41682391a2150ef029a831ce7606501..5d72201f87c7eea0af4acb85998916e3e6d67548 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8731,7 +8731,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, return build_x_unary_op (token->location, (keyword == RID_REALPART ? REALPART_EXPR : IMAGPART_EXPR), - expression, + expression, NULL_TREE, tf_warning_or_error); } break; @@ -8908,7 +8908,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, case INDIRECT_REF: non_constant_p = NIC_STAR; expression = build_x_indirect_ref (loc, cast_expression, - RO_UNARY_STAR, + RO_UNARY_STAR, NULL_TREE, complain); /* TODO: build_x_indirect_ref does not always honor the location, so ensure it is set. */ @@ -8921,7 +8921,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, case BIT_NOT_EXPR: expression = build_x_unary_op (loc, unary_operator, cast_expression, - complain); + NULL_TREE, complain); /* TODO: build_x_unary_op does not always honor the location, so ensure it is set. */ expression.set_location (loc); @@ -10149,7 +10149,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, op_location_t op_loc (current.loc, combined_loc); current.lhs = build_x_binary_op (op_loc, current.tree_type, current.lhs, current.lhs_type, - rhs, rhs_type, &overload, + rhs, rhs_type, NULL_TREE, &overload, complain_flags (decltype_p)); /* TODO: build_x_binary_op doesn't always honor the location. */ current.lhs.set_location (combined_loc); @@ -10328,7 +10328,7 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk, rhs.get_finish ()); expr = build_x_modify_expr (loc, expr, assignment_operator, - rhs, + rhs, NULL_TREE, complain_flags (decltype_p)); /* TODO: build_x_modify_expr doesn't honor the location, so we must set it here. */ @@ -10480,7 +10480,7 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk, expression.get_start (), assignment_expression.get_finish ()); expression = build_x_compound_expr (loc, expression, - assignment_expression, + assignment_expression, NULL_TREE, complain_flags (decltype_p)); expression.set_location (loc); } @@ -13617,7 +13617,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr) iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE, iter_type); iter_decl = build_x_indirect_ref (input_location, iter_decl, - RO_UNARY_STAR, + RO_UNARY_STAR, NULL_TREE, tf_warning_or_error); TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl), iter_decl, auto_node, @@ -13804,7 +13804,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, condition = build_x_binary_op (input_location, NE_EXPR, begin, ERROR_MARK, end, ERROR_MARK, - NULL, tf_warning_or_error); + NULL_TREE, NULL, tf_warning_or_error); finish_for_cond (condition, statement, ivdep, unroll); /* The new increment expression. */ @@ -13818,7 +13818,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, /* The declaration is initialized with *__begin inside the loop body. */ tree deref_begin = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); cp_finish_decl (range_decl, deref_begin, /*is_constant_init*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); @@ -13924,7 +13924,7 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end) && (build_x_binary_op (input_location, NE_EXPR, *begin, ERROR_MARK, *end, ERROR_MARK, - NULL, tf_none) + NULL_TREE, NULL, tf_none) != error_mark_node)) /* P0184R0 allows __begin and __end to have different types, but make sure they are comparable so we can give a better @@ -18924,7 +18924,7 @@ cp_parser_template_argument (cp_parser* parser) { if (address_p) argument = build_x_unary_op (loc, ADDR_EXPR, argument, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); else argument = convert_from_reference (argument); return argument; @@ -41564,7 +41564,7 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code) TREE_CODE (cond), TREE_OPERAND (cond, 0), ERROR_MARK, TREE_OPERAND (cond, 1), ERROR_MARK, - /*overload=*/NULL, tf_warning_or_error); + NULL_TREE, /*overload=*/NULL, tf_warning_or_error); } /* Helper function, to parse omp for increment expression. */ @@ -41641,11 +41641,13 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl) lhs = rhs; else lhs = build_x_unary_op (input_location, NEGATE_EXPR, rhs, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); } else - lhs = build_x_binary_op (input_location, op, lhs, ERROR_MARK, rhs, - ERROR_MARK, NULL, tf_warning_or_error); + lhs = build_x_binary_op (input_location, op, + lhs, ERROR_MARK, + rhs, ERROR_MARK, + NULL_TREE, NULL, tf_warning_or_error); } } while (token->type == CPP_PLUS || token->type == CPP_MINUS); @@ -41873,7 +41875,7 @@ cp_parser_omp_for_loop_init (cp_parser *parser, orig_init = rhs; finish_expr_stmt (build_x_modify_expr (EXPR_LOCATION (rhs), decl, NOP_EXPR, - rhs, + rhs, NULL_TREE, tf_warning_or_error)); if (!add_private_clause) add_private_clause = decl; @@ -41995,7 +41997,7 @@ cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block, cond = build_x_binary_op (input_location, NE_EXPR, begin, ERROR_MARK, end, ERROR_MARK, - NULL, tf_warning_or_error); + NULL_TREE, NULL, tf_warning_or_error); /* The new increment expression. */ if (CLASS_TYPE_P (iter_type)) @@ -42033,7 +42035,7 @@ cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block, if (auto_node) { tree t = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, - tf_none); + NULL_TREE, tf_none); if (!error_operand_p (t)) TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl), t, auto_node); @@ -42073,7 +42075,7 @@ cp_finish_omp_range_for (tree orig, tree begin) /* The declaration is initialized with *__begin inside the loop body. */ cp_finish_decl (decl, build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, - tf_warning_or_error), + NULL_TREE, tf_warning_or_error), /*is_constant_init*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 62a058d583f877ef9ba909114129907b3bdefb47..18c6f118ae6c2a14c85406bc0d998475e9dc6d53 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12640,23 +12640,26 @@ expand_empty_fold (tree t, tsubst_flags_t complain) static tree fold_expression (tree t, tree left, tree right, tsubst_flags_t complain) { - tree op = FOLD_EXPR_OP (t); - tree_code code = (tree_code)TREE_INT_CST_LOW (op); + tree_code code = FOLD_EXPR_OP (t); + + tree lookups = templated_operator_saved_lookups (t); // Handle compound assignment operators. if (FOLD_EXPR_MODIFY_P (t)) - return build_x_modify_expr (input_location, left, code, right, complain); + return build_x_modify_expr (input_location, left, code, right, + lookups, complain); warning_sentinel s(warn_parentheses); switch (code) { case COMPOUND_EXPR: - return build_x_compound_expr (input_location, left, right, complain); + return build_x_compound_expr (input_location, left, right, + lookups, complain); default: return build_x_binary_op (input_location, code, left, TREE_CODE (left), right, TREE_CODE (right), - /*overload=*/NULL, + lookups, /*overload=*/NULL, complain); } } @@ -17891,7 +17894,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, tree lhs = RECUR (TREE_OPERAND (incr, 0)); tree rhs = RECUR (TREE_OPERAND (incr, 1)); incr = build_x_modify_expr (EXPR_LOCATION (incr), lhs, - NOP_EXPR, rhs, complain); + NOP_EXPR, rhs, NULL_TREE, complain); } else incr = RECUR (incr); @@ -19204,6 +19207,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, RETURN (RECUR (TREE_OPERAND (t, 1))); RETURN (build_x_compound_expr (EXPR_LOCATION (t), tmp, RECUR (TREE_OPERAND (t, 1)), + templated_operator_saved_lookups (t), complain)); case ANNOTATE_EXPR: @@ -19855,6 +19859,7 @@ tsubst_copy_and_build (tree t, } else r = build_x_indirect_ref (input_location, r, RO_UNARY_STAR, + templated_operator_saved_lookups (t), complain|decltype_flag); if (REF_PARENTHESIZED_P (t)) @@ -19965,6 +19970,7 @@ tsubst_copy_and_build (tree t, op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0), args, complain, in_decl); RETURN (build_x_unary_op (input_location, TREE_CODE (t), op1, + templated_operator_saved_lookups (t), complain|decltype_flag)); case PREDECREMENT_EXPR: @@ -19978,6 +19984,7 @@ tsubst_copy_and_build (tree t, case IMAGPART_EXPR: RETURN (build_x_unary_op (input_location, TREE_CODE (t), RECUR (TREE_OPERAND (t, 0)), + templated_operator_saved_lookups (t), complain|decltype_flag)); case FIX_TRUNC_EXPR: @@ -19996,6 +20003,7 @@ tsubst_copy_and_build (tree t, op1 = tsubst_non_call_postfix_expression (op1, args, complain, in_decl); RETURN (build_x_unary_op (input_location, ADDR_EXPR, op1, + templated_operator_saved_lookups (t), complain|decltype_flag)); case PLUS_EXPR: @@ -20060,6 +20068,7 @@ tsubst_copy_and_build (tree t, (warning_suppressed_p (TREE_OPERAND (t, 1)) ? ERROR_MARK : TREE_CODE (TREE_OPERAND (t, 1))), + templated_operator_saved_lookups (t), /*overload=*/NULL, complain|decltype_flag); if (EXPR_P (r)) @@ -20212,8 +20221,10 @@ tsubst_copy_and_build (tree t, warning_sentinel s(warn_div_by_zero); tree lhs = RECUR (TREE_OPERAND (t, 0)); tree rhs = RECUR (TREE_OPERAND (t, 2)); + tree r = build_x_modify_expr (EXPR_LOCATION (t), lhs, TREE_CODE (TREE_OPERAND (t, 1)), rhs, + templated_operator_saved_lookups (t), complain|decltype_flag); /* TREE_NO_WARNING must be set if either the expression was parenthesized or it uses an operator such as >>= rather @@ -20314,6 +20325,7 @@ tsubst_copy_and_build (tree t, RETURN (build_x_compound_expr (EXPR_LOCATION (t), op0, RECUR (TREE_OPERAND (t, 1)), + templated_operator_saved_lookups (t), complain|decltype_flag)); } @@ -26994,6 +27006,9 @@ dependent_type_p_r (tree type) if (TREE_CODE (type) == TYPE_PACK_EXPANSION) return true; + if (TREE_CODE (type) == DEPENDENT_OPERATOR_TYPE) + return true; + if (any_dependent_type_attributes_p (TYPE_ATTRIBUTES (type))) return true; diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index d514aa2cad2765d9eb7762a494cb2ac2490ea45e..f7ddae77679c878576982a1e0dfb73e24d7094a8 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -151,6 +151,12 @@ cxx_print_type (FILE *file, tree node, int indent) print_node (file, "expr", DECLTYPE_TYPE_EXPR (node), indent + 4); return; + case DEPENDENT_OPERATOR_TYPE: + print_node (file, "saved_lookups", + DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (node), + indent + 4); + return; + case TYPENAME_TYPE: print_node (file, "fullname", TYPENAME_TYPE_FULLNAME (node), indent + 4); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 356fb83200cc238263a77937ff1bd6234f49bb9d..6603066c6207b226a0130f69b2f366c797f78745 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2920,7 +2920,7 @@ finish_increment_expr (cp_expr expr, enum tree_code code) expr.get_start (), get_finish (input_location)); cp_expr result = build_x_unary_op (combined_loc, code, expr, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); /* TODO: build_x_unary_op doesn't honor the location, so set it here. */ result.set_location (combined_loc); return result; @@ -3031,7 +3031,8 @@ finish_unary_op_expr (location_t op_loc, enum tree_code code, cp_expr expr, of the operator token to the end of EXPR. */ location_t combined_loc = make_location (op_loc, op_loc, expr.get_finish ()); - cp_expr result = build_x_unary_op (combined_loc, code, expr, complain); + cp_expr result = build_x_unary_op (combined_loc, code, expr, + NULL_TREE, complain); /* TODO: build_x_unary_op doesn't always honor the location. */ result.set_location (combined_loc); @@ -9884,7 +9885,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, TREE_CODE (cond), iter, ERROR_MARK, TREE_OPERAND (cond, 1), ERROR_MARK, - NULL, tf_warning_or_error); + NULL_TREE, NULL, tf_warning_or_error); if (error_operand_p (tem)) return true; } @@ -9898,9 +9899,10 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, error_at (elocus, "invalid controlling predicate"); return true; } - diff = build_x_binary_op (elocus, MINUS_EXPR, TREE_OPERAND (cond, 1), - ERROR_MARK, iter, ERROR_MARK, NULL, - tf_warning_or_error); + diff = build_x_binary_op (elocus, MINUS_EXPR, + TREE_OPERAND (cond, 1), ERROR_MARK, + iter, ERROR_MARK, + NULL_TREE, NULL, tf_warning_or_error); diff = cp_fully_fold (diff); if (error_operand_p (diff)) return true; @@ -9928,7 +9930,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, } iter_incr = build_x_unary_op (EXPR_LOCATION (incr), TREE_CODE (incr), iter, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); if (error_operand_p (iter_incr)) return true; else if (TREE_CODE (incr) == PREINCREMENT_EXPR @@ -9954,6 +9956,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs), iter, TREE_CODE (rhs), TREE_OPERAND (rhs, 1), + NULL_TREE, tf_warning_or_error); if (error_operand_p (iter_incr)) return true; @@ -9983,13 +9986,13 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, PLUS_EXPR, TREE_OPERAND (rhs, 0), ERROR_MARK, iter, - ERROR_MARK, NULL, + ERROR_MARK, NULL_TREE, NULL, tf_warning_or_error); if (error_operand_p (iter_incr)) return true; iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs), iter, NOP_EXPR, - iter_incr, + iter_incr, NULL_TREE, tf_warning_or_error); if (error_operand_p (iter_incr)) return true; @@ -10100,7 +10103,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, if (init != NULL) finish_expr_stmt (build_x_modify_expr (elocus, iter, NOP_EXPR, init, - tf_warning_or_error)); + NULL_TREE, tf_warning_or_error)); init = build_int_cst (TREE_TYPE (diff), 0); if (c && iter_incr == NULL && (!ordered || (i < collapse && collapse > 1))) @@ -10109,23 +10112,24 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, { finish_expr_stmt (build_x_modify_expr (elocus, incr_var, NOP_EXPR, - incr, tf_warning_or_error)); + incr, NULL_TREE, + tf_warning_or_error)); incr = incr_var; } iter_incr = build_x_modify_expr (elocus, iter, PLUS_EXPR, incr, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); } if (c && ordered && i < collapse && collapse > 1) iter_incr = incr; finish_expr_stmt (build_x_modify_expr (elocus, last, NOP_EXPR, init, - tf_warning_or_error)); + NULL_TREE, tf_warning_or_error)); if (diffvar) { finish_expr_stmt (build_x_modify_expr (elocus, diffvar, NOP_EXPR, - diff, tf_warning_or_error)); + diff, NULL_TREE, tf_warning_or_error)); diff = diffvar; } *pre_body = pop_stmt_list (*pre_body); @@ -10141,13 +10145,13 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), decl, last); iter_init = build_x_modify_expr (elocus, iter, PLUS_EXPR, iter_init, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); if (iter_init != error_mark_node) iter_init = build1 (NOP_EXPR, void_type_node, iter_init); finish_expr_stmt (iter_init); finish_expr_stmt (build_x_modify_expr (elocus, last, NOP_EXPR, decl, - tf_warning_or_error)); + NULL_TREE, tf_warning_or_error)); add_stmt (orig_body); *body = pop_stmt_list (*body); @@ -10165,7 +10169,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), iter_init, last); iter_init = build_x_modify_expr (elocus, iter, PLUS_EXPR, iter_init, - tf_warning_or_error); + NULL_TREE, tf_warning_or_error); if (iter_init != error_mark_node) iter_init = build1 (NOP_EXPR, void_type_node, iter_init); finish_expr_stmt (iter_init); @@ -10876,7 +10880,7 @@ finish_omp_cancel (tree clauses) ifc = build_x_binary_op (OMP_CLAUSE_LOCATION (ifc), NE_EXPR, OMP_CLAUSE_IF_EXPR (ifc), ERROR_MARK, integer_zero_node, ERROR_MARK, - NULL, tf_warning_or_error); + NULL_TREE, NULL, tf_warning_or_error); } else ifc = boolean_true_node; @@ -12128,6 +12132,9 @@ finish_unary_fold_expr (tree expr, int op, tree_code dir) tree code = build_int_cstu (integer_type_node, abs (op)); tree fold = build_min_nt_loc (UNKNOWN_LOCATION, dir, code, pack); FOLD_EXPR_MODIFY_P (fold) = (op < 0); + TREE_TYPE (fold) = build_dependent_operator_type (NULL_TREE, + FOLD_EXPR_OP (fold), + FOLD_EXPR_MODIFY_P (fold)); return fold; } @@ -12154,6 +12161,9 @@ finish_binary_fold_expr (tree pack, tree init, int op, tree_code dir) tree code = build_int_cstu (integer_type_node, abs (op)); tree fold = build_min_nt_loc (UNKNOWN_LOCATION, dir, code, pack, init); FOLD_EXPR_MODIFY_P (fold) = (op < 0); + TREE_TYPE (fold) = build_dependent_operator_type (NULL_TREE, + FOLD_EXPR_OP (fold), + FOLD_EXPR_MODIFY_P (fold)); return fold; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 284fb5f4b2a83570c8b7aed68cecf0e489a75db7..29f3c171606a927b90a7bae2077afb070e401c21 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5975,8 +5975,6 @@ cp_free_lang_data (tree t) DECL_EXTERNAL (t) = 1; TREE_STATIC (t) = 0; } - if (TREE_CODE (t) == FUNCTION_DECL) - discard_operator_bindings (t); if (TREE_CODE (t) == NAMESPACE_DECL) /* We do not need the leftover chaining of namespaces from the binding level. */ diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 4e60db40c767cbe8f997ce429df9ce4147f3f2da..5184b02d3e4ee8bd71826a746e28f188e4e4f084 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2602,6 +2602,7 @@ rationalize_conditional_expr (enum tree_code code, tree t, ? LE_EXPR : GE_EXPR), op0, TREE_CODE (op0), op1, TREE_CODE (op1), + NULL_TREE, /*overload=*/NULL, complain), cp_build_unary_op (code, op0, false, complain), @@ -3487,6 +3488,67 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name) return build_simple_component_ref (ptrmem, member); } +/* Return a TREE_LIST of namespace-scope overloads for the given operator, + and for any other relevant operator. */ + +static tree +op_unqualified_lookup (tree_code code, bool is_assign) +{ + tree lookups = NULL_TREE; + + if (cxx_dialect >= cxx20 && !is_assign) + { + if (code == NE_EXPR) + { + /* != can get rewritten in terms of ==. */ + tree fnname = ovl_op_identifier (false, EQ_EXPR); + if (tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE)) + lookups = tree_cons (fnname, fns, lookups); + } + else if (code == GT_EXPR || code == LE_EXPR + || code == LT_EXPR || code == GE_EXPR) + { + /* These can get rewritten in terms of <=>. */ + tree fnname = ovl_op_identifier (false, SPACESHIP_EXPR); + if (tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE)) + lookups = tree_cons (fnname, fns, lookups); + } + } + + tree fnname = ovl_op_identifier (is_assign, code); + if (tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE)) + lookups = tree_cons (fnname, fns, lookups); + + if (lookups) + return lookups; + else + return build_tree_list (NULL_TREE, NULL_TREE); +} + +/* Create a DEPENDENT_OPERATOR_TYPE for a dependent operator expression of + the given operator. LOOKUPS, if non-NULL, is the result of phase 1 + name lookup for the given operator. */ + +tree +build_dependent_operator_type (tree lookups, tree_code code, bool is_assign) +{ + if (lookups) + /* We're partially instantiating a dependent operator expression, and + LOOKUPS is the result of phase 1 name lookup that we performed + earlier at template definition time, so just reuse the corresponding + DEPENDENT_OPERATOR_TYPE. */ + return TREE_TYPE (lookups); + + /* Otherwise we're processing a dependent operator expression at template + definition time, so perform phase 1 name lookup now. */ + lookups = op_unqualified_lookup (code, is_assign); + + tree type = cxx_make_type (DEPENDENT_OPERATOR_TYPE); + DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (type) = lookups; + TREE_TYPE (lookups) = type; + return type; +} + /* Given an expression PTR for a pointer, return an expression for the value pointed to. ERRORSTRING is the name of the operator to appear in error messages. @@ -3496,7 +3558,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name) tree build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, - tsubst_flags_t complain) + tree lookups, tsubst_flags_t complain) { tree orig_expr = expr; tree rval; @@ -3516,12 +3578,18 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, return build_min (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr); } if (type_dependent_expression_p (expr)) - return build_min_nt_loc (loc, INDIRECT_REF, expr); + { + expr = build_min_nt_loc (loc, INDIRECT_REF, expr); + TREE_TYPE (expr) + = build_dependent_operator_type (lookups, INDIRECT_REF, false); + return expr; + } expr = build_non_dependent_expr (expr); } rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr, - NULL_TREE, NULL_TREE, &overload, complain); + NULL_TREE, NULL_TREE, lookups, + &overload, complain); if (!rval) rval = cp_build_indirect_ref (loc, expr, errorstring, complain); @@ -4458,8 +4526,8 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl, tree build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1, enum tree_code arg1_code, tree arg2, - enum tree_code arg2_code, tree *overload_p, - tsubst_flags_t complain) + enum tree_code arg2_code, tree lookups, + tree *overload_p, tsubst_flags_t complain) { tree orig_arg1; tree orig_arg2; @@ -4475,7 +4543,8 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1, || type_dependent_expression_p (arg2)) { expr = build_min_nt_loc (loc, code, arg1, arg2); - maybe_save_operator_binding (expr); + TREE_TYPE (expr) + = build_dependent_operator_type (lookups, code, false); return expr; } arg1 = build_non_dependent_expr (arg1); @@ -4486,7 +4555,7 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1, expr = build_m_component_ref (arg1, arg2, complain); else expr = build_new_op (loc, code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE, - &overload, complain); + lookups, &overload, complain); if (overload_p != NULL) *overload_p = overload; @@ -4538,7 +4607,7 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2, } expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, arg1, arg2, - NULL_TREE, &overload, complain); + NULL_TREE, NULL_TREE, &overload, complain); if (processing_template_decl && expr != error_mark_node) { @@ -6402,7 +6471,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype, tree build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, - tsubst_flags_t complain) + tree lookups, tsubst_flags_t complain) { tree orig_expr = xarg; tree exp; @@ -6414,7 +6483,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, if (type_dependent_expression_p (xarg)) { tree e = build_min_nt_loc (loc, code, xarg.get_value (), NULL_TREE); - maybe_save_operator_binding (e); + TREE_TYPE (e) = build_dependent_operator_type (lookups, code, false); return e; } @@ -6439,7 +6508,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, /* Don't look for a function. */; else exp = build_new_op (loc, code, LOOKUP_NORMAL, xarg, NULL_TREE, - NULL_TREE, &overload, complain); + NULL_TREE, lookups, &overload, complain); if (!exp && code == ADDR_EXPR) { @@ -7508,7 +7577,8 @@ build_x_compound_expr_from_list (tree list, expr_list_kind exp, for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list)) expr = build_x_compound_expr (EXPR_LOCATION (TREE_VALUE (list)), - expr, TREE_VALUE (list), complain); + expr, TREE_VALUE (list), NULL_TREE, + complain); } return expr; @@ -7543,7 +7613,7 @@ build_x_compound_expr_from_vec (vec<tree, va_gc> *vec, const char *msg, expr = (*vec)[0]; for (ix = 1; vec->iterate (ix, &t); ++ix) expr = build_x_compound_expr (EXPR_LOCATION (t), expr, - t, complain); + t, NULL_TREE, complain); return expr; } @@ -7553,7 +7623,7 @@ build_x_compound_expr_from_vec (vec<tree, va_gc> *vec, const char *msg, tree build_x_compound_expr (location_t loc, tree op1, tree op2, - tsubst_flags_t complain) + tree lookups, tsubst_flags_t complain) { tree result; tree orig_op1 = op1; @@ -7566,7 +7636,8 @@ build_x_compound_expr (location_t loc, tree op1, tree op2, || type_dependent_expression_p (op2)) { result = build_min_nt_loc (loc, COMPOUND_EXPR, op1, op2); - maybe_save_operator_binding (result); + TREE_TYPE (result) + = build_dependent_operator_type (lookups, COMPOUND_EXPR, false); return result; } op1 = build_non_dependent_expr (op1); @@ -7574,7 +7645,7 @@ build_x_compound_expr (location_t loc, tree op1, tree op2, } result = build_new_op (loc, COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, - NULL_TREE, &overload, complain); + NULL_TREE, lookups, &overload, complain); if (!result) result = cp_build_compound_expr (op1, op2, complain); @@ -9017,8 +9088,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { result = build_new_op (input_location, MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, - make_node (NOP_EXPR), /*overload=*/NULL, - complain); + make_node (NOP_EXPR), NULL_TREE, + /*overload=*/NULL, complain); if (result == NULL_TREE) return error_mark_node; goto ret; @@ -9233,7 +9304,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, cp_expr build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, - tree rhs, tsubst_flags_t complain) + tree rhs, tree lookups, tsubst_flags_t complain) { tree orig_lhs = lhs; tree orig_rhs = rhs; @@ -9250,7 +9321,9 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { tree op = build_min_nt_loc (loc, modifycode, NULL_TREE, NULL_TREE); tree rval = build_min_nt_loc (loc, MODOP_EXPR, lhs, op, rhs); - maybe_save_operator_binding (rval); + if (modifycode != NOP_EXPR) + TREE_TYPE (rval) + = build_dependent_operator_type (lookups, modifycode, true); return rval; } @@ -9262,7 +9335,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, - lhs, rhs, op, &overload, complain); + lhs, rhs, op, lookups, &overload, complain); if (rval) { if (rval == error_mark_node) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 3fb651a02ba1e2eb2b46b8cddc3331ed40d5c28d..724684c0457d8cd9c1e4e4929e647410e6ac8370 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1956,7 +1956,7 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain) while ((expr = build_new_op (loc, COMPONENT_REF, LOOKUP_NORMAL, expr, NULL_TREE, NULL_TREE, - &fn, complain))) + NULL_TREE, &fn, complain))) { if (expr == error_mark_node) return error_mark_node; diff --git a/gcc/testsuite/g++.dg/lookup/operator-3-ops.h b/gcc/testsuite/g++.dg/lookup/operator-3-ops.h new file mode 100644 index 0000000000000000000000000000000000000000..fbd242a4e66b599df7728510d34b45e6e17c1ea4 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-3-ops.h @@ -0,0 +1,53 @@ +void operator+(N::A); +void operator-(N::A); +void operator*(N::A); +void operator~(N::A); +#if __cplusplus >= 201103L +void operator&(N::A) = delete; +#else +void operator&(N::A); +#endif +void operator!(N::A); +void operator++(N::A); +void operator--(N::A); +void operator++(N::A, int); +void operator--(N::A, int); + +void operator->*(N::A, N::A); +void operator/(N::A, N::A); +void operator*(N::A, N::A); +void operator+(N::A, N::A); +void operator-(N::A, N::A); +void operator%(N::A, N::A); +void operator&(N::A, N::A); +void operator|(N::A, N::A); +void operator^(N::A, N::A); +void operator<<(N::A, N::A); +void operator>>(N::A, N::A); +void operator&&(N::A, N::A); +void operator||(N::A, N::A); +#if __cplusplus >= 201103L +void operator,(N::A, N::A) = delete; +#else +void operator,(N::A, N::A); +#endif + +void operator==(N::A, N::A); +void operator!=(N::A, N::A); +void operator<(N::A, N::A); +void operator>(N::A, N::A); +void operator<=(N::A, N::A); +void operator>=(N::A, N::A); +#if __cplusplus > 201703L +void operator<=>(N::A, N::A); +#endif + +void operator+=(N::A, N::A); +void operator-=(N::A, N::A); +void operator*=(N::A, N::A); +void operator/=(N::A, N::A); +void operator%=(N::A, N::A); +void operator|=(N::A, N::A); +void operator^=(N::A, N::A); +void operator<<=(N::A, N::A); +void operator>>=(N::A, N::A); diff --git a/gcc/testsuite/g++.dg/lookup/operator-3.C b/gcc/testsuite/g++.dg/lookup/operator-3.C index bc5eb3d6693ebc48a367f0e8e2b851083807722c..ab0257a66aaf60e9806464f4471c6c3f79eaed7d 100644 --- a/gcc/testsuite/g++.dg/lookup/operator-3.C +++ b/gcc/testsuite/g++.dg/lookup/operator-3.C @@ -1,4 +1,6 @@ // PR c++/51577 +// Verify we don't consider later-declared namespace-scope operator overloads +// when instantiating a dependent operator expression that occurs at block scope. template <class T> void f (T x) { +x; // { dg-error "no match" } @@ -50,59 +52,7 @@ template <class T> void f (T x) { namespace N { struct A { }; } -void operator+(N::A); -void operator-(N::A); -void operator*(N::A); -void operator~(N::A); -#if __cplusplus >= 201103L -void operator&(N::A) = delete; -#else -void operator&(N::A); -#endif -void operator!(N::A); -void operator++(N::A); -void operator--(N::A); -void operator++(N::A, int); -void operator--(N::A, int); - -void operator->*(N::A, N::A); -void operator/(N::A, N::A); -void operator*(N::A, N::A); -void operator+(N::A, N::A); -void operator-(N::A, N::A); -void operator%(N::A, N::A); -void operator&(N::A, N::A); -void operator|(N::A, N::A); -void operator^(N::A, N::A); -void operator<<(N::A, N::A); -void operator>>(N::A, N::A); -void operator&&(N::A, N::A); -void operator||(N::A, N::A); -#if __cplusplus >= 201103L -void operator,(N::A, N::A) = delete; -#else -void operator,(N::A, N::A); -#endif - -void operator==(N::A, N::A); -void operator!=(N::A, N::A); -void operator<(N::A, N::A); -void operator>(N::A, N::A); -void operator<=(N::A, N::A); -void operator>=(N::A, N::A); -#if __cplusplus > 201703L -void operator<=>(N::A, N::A); -#endif - -void operator+=(N::A, N::A); -void operator-=(N::A, N::A); -void operator*=(N::A, N::A); -void operator/=(N::A, N::A); -void operator%=(N::A, N::A); -void operator|=(N::A, N::A); -void operator^=(N::A, N::A); -void operator<<=(N::A, N::A); -void operator>>=(N::A, N::A); +#include "operator-3-ops.h" int main() { f(N::A()); diff --git a/gcc/testsuite/g++.dg/lookup/operator-3a.C b/gcc/testsuite/g++.dg/lookup/operator-3a.C new file mode 100644 index 0000000000000000000000000000000000000000..62ae5c36dc2fc541a8ad1c10dcc3af735a76f53c --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-3a.C @@ -0,0 +1,61 @@ +// PR c++/51577 +// { dg-do compile { target c++14 } } +// Like operator-3.C but also containing a partial instantiation step. + +template <class...> auto f () { + return [] (auto x) { + +x; // { dg-error "no match" } + -x; // { dg-error "no match" } + *x; // { dg-error "no match" } + ~x; // { dg-error "no match" } + &x; + !x; // { dg-error "no match" } + ++x; // { dg-error "no match" } + --x; // { dg-error "no match" } + x++; // { dg-error "declared for postfix" } + x--; // { dg-error "declared for postfix" } + + x->*x; // { dg-error "no match" } + x / x; // { dg-error "no match" } + x * x; // { dg-error "no match" } + x + x; // { dg-error "no match" } + x - x; // { dg-error "no match" } + x % x; // { dg-error "no match" } + x & x; // { dg-error "no match" } + x | x; // { dg-error "no match" } + x ^ x; // { dg-error "no match" } + x << x; // { dg-error "no match" } + x >> x; // { dg-error "no match" } + x && x; // { dg-error "no match" } + x || x; // { dg-error "no match" } + x, x; + + x == x; // { dg-error "no match" } + x != x; // { dg-error "no match" } + x < x; // { dg-error "no match" } + x > x; // { dg-error "no match" } + x <= x; // { dg-error "no match" } + x >= x; // { dg-error "no match" } +#if __cplusplus > 201703L + x <=> x; // { dg-error "no match" "" { target c++20 } } +#endif + + x += x; // { dg-error "no match" } + x -= x; // { dg-error "no match" } + x *= x; // { dg-error "no match" } + x /= x; // { dg-error "no match" } + x %= x; // { dg-error "no match" } + x |= x; // { dg-error "no match" } + x ^= x; // { dg-error "no match" } + x <<= x; // { dg-error "no match" } + x >>= x; // { dg-error "no match" } + }; +} + +namespace N { struct A { }; } + +#include "operator-3-ops.h" + +int main() { + f()(N::A()); +} diff --git a/gcc/testsuite/g++.dg/lookup/operator-4.C b/gcc/testsuite/g++.dg/lookup/operator-4.C new file mode 100644 index 0000000000000000000000000000000000000000..e0b80a1c3b39329fb5d9ddc85e4ae51a837b6652 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-4.C @@ -0,0 +1,74 @@ +// PR c++/51577 +// { dg-do compile { target c++17 } } +// Like operator-3.C but for unary fold expressions. + +template <class... Ts> void f (Ts... xs) { + (xs->*...); // { dg-error "no match" } + (...->*xs); // { dg-error "no match" } + (xs / ...); // { dg-error "no match" } + (... / xs); // { dg-error "no match" } + (xs * ...); // { dg-error "no match" } + (... * xs); // { dg-error "no match" } + (xs + ...); // { dg-error "no match" } + (... + xs); // { dg-error "no match" } + (xs - ...); // { dg-error "no match" } + (... - xs); // { dg-error "no match" } + (xs % ...); // { dg-error "no match" } + (... % xs); // { dg-error "no match" } + (xs & ...); // { dg-error "no match" } + (... & xs); // { dg-error "no match" } + (xs | ...); // { dg-error "no match" } + (... | xs); // { dg-error "no match" } + (xs ^ ...); // { dg-error "no match" } + (... ^ xs); // { dg-error "no match" } + (xs << ...); // { dg-error "no match" } + (... << xs); // { dg-error "no match" } + (xs >> ...); // { dg-error "no match" } + (... >> xs); // { dg-error "no match" } + (xs && ...); // { dg-error "no match" } + (... && xs); // { dg-error "no match" } + (xs || ...); // { dg-error "no match" } + (... || xs); // { dg-error "no match" } + (xs, ...); + (..., xs); + + (xs == ...); // { dg-error "no match" } + (... == xs); // { dg-error "no match" } + (xs != ...); // { dg-error "no match" } + (... != xs); // { dg-error "no match" } + (xs < ...); // { dg-error "no match" } + (... < xs); // { dg-error "no match" } + (xs > ...); // { dg-error "no match" } + (... > xs); // { dg-error "no match" } + (xs <= ...); // { dg-error "no match" } + (... <= xs); // { dg-error "no match" } + (xs >= ...); // { dg-error "no match" } + (... >= xs); // { dg-error "no match" } + + (xs += ...); // { dg-error "no match" } + (... += xs); // { dg-error "no match" } + (xs -= ...); // { dg-error "no match" } + (... -= xs); // { dg-error "no match" } + (xs *= ...); // { dg-error "no match" } + (... *= xs); // { dg-error "no match" } + (xs /= ...); // { dg-error "no match" } + (... /= xs); // { dg-error "no match" } + (xs %= ...); // { dg-error "no match" } + (... %= xs); // { dg-error "no match" } + (xs |= ...); // { dg-error "no match" } + (... |= xs); // { dg-error "no match" } + (xs ^= ...); // { dg-error "no match" } + (... ^= xs); // { dg-error "no match" } + (xs <<= ...); // { dg-error "no match" } + (... <<= xs); // { dg-error "no match" } + (xs >>= ...); // { dg-error "no match" } + (... >>= xs); // { dg-error "no match" } +} + +namespace N { struct A { }; } + +#include "operator-3-ops.h" + +int main() { + f(N::A(), N::A()); +} diff --git a/gcc/testsuite/g++.dg/lookup/operator-4a.C b/gcc/testsuite/g++.dg/lookup/operator-4a.C new file mode 100644 index 0000000000000000000000000000000000000000..b4a3f947b05246f36dfd67c3e90e5161afe97125 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-4a.C @@ -0,0 +1,76 @@ +// PR c++/51577 +// { dg-do compile { target c++17 } } +// Like operator-4.C but also containing a partial instantiation step. + +template <class...> auto f () { + return [] (auto... xs) { + (xs->*...); // { dg-error "no match" } + (...->*xs); // { dg-error "no match" } + (xs / ...); // { dg-error "no match" } + (... / xs); // { dg-error "no match" } + (xs * ...); // { dg-error "no match" } + (... * xs); // { dg-error "no match" } + (xs + ...); // { dg-error "no match" } + (... + xs); // { dg-error "no match" } + (xs - ...); // { dg-error "no match" } + (... - xs); // { dg-error "no match" } + (xs % ...); // { dg-error "no match" } + (... % xs); // { dg-error "no match" } + (xs & ...); // { dg-error "no match" } + (... & xs); // { dg-error "no match" } + (xs | ...); // { dg-error "no match" } + (... | xs); // { dg-error "no match" } + (xs ^ ...); // { dg-error "no match" } + (... ^ xs); // { dg-error "no match" } + (xs << ...); // { dg-error "no match" } + (... << xs); // { dg-error "no match" } + (xs >> ...); // { dg-error "no match" } + (... >> xs); // { dg-error "no match" } + (xs && ...); // { dg-error "no match" } + (... && xs); // { dg-error "no match" } + (xs || ...); // { dg-error "no match" } + (... || xs); // { dg-error "no match" } + (xs, ...); + (..., xs); + + (xs == ...); // { dg-error "no match" } + (... == xs); // { dg-error "no match" } + (xs != ...); // { dg-error "no match" } + (... != xs); // { dg-error "no match" } + (xs < ...); // { dg-error "no match" } + (... < xs); // { dg-error "no match" } + (xs > ...); // { dg-error "no match" } + (... > xs); // { dg-error "no match" } + (xs <= ...); // { dg-error "no match" } + (... <= xs); // { dg-error "no match" } + (xs >= ...); // { dg-error "no match" } + (... >= xs); // { dg-error "no match" } + + (xs += ...); // { dg-error "no match" } + (... += xs); // { dg-error "no match" } + (xs -= ...); // { dg-error "no match" } + (... -= xs); // { dg-error "no match" } + (xs *= ...); // { dg-error "no match" } + (... *= xs); // { dg-error "no match" } + (xs /= ...); // { dg-error "no match" } + (... /= xs); // { dg-error "no match" } + (xs %= ...); // { dg-error "no match" } + (... %= xs); // { dg-error "no match" } + (xs |= ...); // { dg-error "no match" } + (... |= xs); // { dg-error "no match" } + (xs ^= ...); // { dg-error "no match" } + (... ^= xs); // { dg-error "no match" } + (xs <<= ...); // { dg-error "no match" } + (... <<= xs); // { dg-error "no match" } + (xs >>= ...); // { dg-error "no match" } + (... >>= xs); // { dg-error "no match" } + }; +} + +namespace N { struct A { }; } + +#include "operator-3-ops.h" + +int main() { + f()(N::A(), N::A()); +} diff --git a/gcc/testsuite/g++.dg/lookup/operator-5.C b/gcc/testsuite/g++.dg/lookup/operator-5.C new file mode 100644 index 0000000000000000000000000000000000000000..2bbb2c41618c0ccfe674a90e19c6887566d20d78 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-5.C @@ -0,0 +1,74 @@ +// PR c++/51577 +// { dg-do compile { target c++17 } } +// Like operator-4.C but for binary fold expressions. + +namespace N { struct A { }; } + +template <class... Ts> void f (Ts... xs) { + (xs->*...->*N::A{}); // { dg-error "no match" } + (N::A{}->*...->*xs); // { dg-error "no match" } + (xs / ... / N::A{}); // { dg-error "no match" } + (N::A{} / ... / xs); // { dg-error "no match" } + (xs * ... * N::A{}); // { dg-error "no match" } + (N::A{} * ... * xs); // { dg-error "no match" } + (xs + ... + N::A{}); // { dg-error "no match" } + (N::A{} + ... + xs); // { dg-error "no match" } + (xs - ... - N::A{}); // { dg-error "no match" } + (N::A{} - ... - xs); // { dg-error "no match" } + (xs % ... % N::A{}); // { dg-error "no match" } + (N::A{} % ... % xs); // { dg-error "no match" } + (xs & ... & N::A{}); // { dg-error "no match" } + (N::A{} & ... & xs); // { dg-error "no match" } + (xs | ... | N::A{}); // { dg-error "no match" } + (N::A{} | ... | xs); // { dg-error "no match" } + (xs ^ ... ^ N::A{}); // { dg-error "no match" } + (N::A{} ^ ... ^ xs); // { dg-error "no match" } + (xs << ... << N::A{}); // { dg-error "no match" } + (N::A{} << ... << xs); // { dg-error "no match" } + (xs >> ... >> N::A{}); // { dg-error "no match" } + (N::A{} >> ... >> xs); // { dg-error "no match" } + (xs && ... && N::A{}); // { dg-error "no match" } + (N::A{} && ... && xs); // { dg-error "no match" } + (xs || ... || N::A{}); // { dg-error "no match" } + (N::A{} || ... || xs); // { dg-error "no match" } + (xs , ... , N::A{}); + (N::A{} , ... , xs); + + (xs == ... == N::A{}); // { dg-error "no match" } + (N::A{} == ... == xs); // { dg-error "no match" } + (xs != ... != N::A{}); // { dg-error "no match" } + (N::A{} != ... != xs); // { dg-error "no match" } + (xs < ... < N::A{}); // { dg-error "no match" } + (N::A{} < ... < xs); // { dg-error "no match" } + (xs > ... > N::A{}); // { dg-error "no match" } + (N::A{} > ... > xs); // { dg-error "no match" } + (xs <= ... <= N::A{}); // { dg-error "no match" } + (N::A{} <= ... <= xs); // { dg-error "no match" } + (xs >= ... >= N::A{}); // { dg-error "no match" } + (N::A{} >= ... >= xs); // { dg-error "no match" } + + (xs += ... += N::A{}); // { dg-error "no match" } + (N::A{} += ... += xs); // { dg-error "no match" } + (xs -= ... -= N::A{}); // { dg-error "no match" } + (N::A{} -= ... -= xs); // { dg-error "no match" } + (xs *= ... *= N::A{}); // { dg-error "no match" } + (N::A{} *= ... *= xs); // { dg-error "no match" } + (xs /= ... /= N::A{}); // { dg-error "no match" } + (N::A{} /= ... /= xs); // { dg-error "no match" } + (xs %= ... %= N::A{}); // { dg-error "no match" } + (N::A{} %= ... %= xs); // { dg-error "no match" } + (xs |= ... |= N::A{}); // { dg-error "no match" } + (N::A{} |= ... |= xs); // { dg-error "no match" } + (xs ^= ... ^= N::A{}); // { dg-error "no match" } + (N::A{} ^= ... ^= xs); // { dg-error "no match" } + (xs <<= ... <<= N::A{}); // { dg-error "no match" } + (N::A{} <<= ... <<= xs); // { dg-error "no match" } + (xs >>= ... >>= N::A{}); // { dg-error "no match" } + (N::A{} >>= ... >>= xs); // { dg-error "no match" } +} + +#include "operator-3-ops.h" + +int main() { + f(N::A()); +} diff --git a/gcc/testsuite/g++.dg/lookup/operator-5a.C b/gcc/testsuite/g++.dg/lookup/operator-5a.C new file mode 100644 index 0000000000000000000000000000000000000000..6f9ecd65a50b66a61b40f2384907e0d3ca0a5777 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-5a.C @@ -0,0 +1,76 @@ +// PR c++/51577 +// { dg-do compile { target c++17 } } +// Like operator-5.C but also containing a partial instantiation step. + +namespace N { struct A { }; } + +template <class...> auto f () { + return [] (auto... xs) { + (xs->*...->*N::A{}); // { dg-error "no match" } + (N::A{}->*...->*xs); // { dg-error "no match" } + (xs / ... / N::A{}); // { dg-error "no match" } + (N::A{} / ... / xs); // { dg-error "no match" } + (xs * ... * N::A{}); // { dg-error "no match" } + (N::A{} * ... * xs); // { dg-error "no match" } + (xs + ... + N::A{}); // { dg-error "no match" } + (N::A{} + ... + xs); // { dg-error "no match" } + (xs - ... - N::A{}); // { dg-error "no match" } + (N::A{} - ... - xs); // { dg-error "no match" } + (xs % ... % N::A{}); // { dg-error "no match" } + (N::A{} % ... % xs); // { dg-error "no match" } + (xs & ... & N::A{}); // { dg-error "no match" } + (N::A{} & ... & xs); // { dg-error "no match" } + (xs | ... | N::A{}); // { dg-error "no match" } + (N::A{} | ... | xs); // { dg-error "no match" } + (xs ^ ... ^ N::A{}); // { dg-error "no match" } + (N::A{} ^ ... ^ xs); // { dg-error "no match" } + (xs << ... << N::A{}); // { dg-error "no match" } + (N::A{} << ... << xs); // { dg-error "no match" } + (xs >> ... >> N::A{}); // { dg-error "no match" } + (N::A{} >> ... >> xs); // { dg-error "no match" } + (xs && ... && N::A{}); // { dg-error "no match" } + (N::A{} && ... && xs); // { dg-error "no match" } + (xs || ... || N::A{}); // { dg-error "no match" } + (N::A{} || ... || xs); // { dg-error "no match" } + (xs , ... , N::A{}); + (N::A{} , ... , xs); + + (xs == ... == N::A{}); // { dg-error "no match" } + (N::A{} == ... == xs); // { dg-error "no match" } + (xs != ... != N::A{}); // { dg-error "no match" } + (N::A{} != ... != xs); // { dg-error "no match" } + (xs < ... < N::A{}); // { dg-error "no match" } + (N::A{} < ... < xs); // { dg-error "no match" } + (xs > ... > N::A{}); // { dg-error "no match" } + (N::A{} > ... > xs); // { dg-error "no match" } + (xs <= ... <= N::A{}); // { dg-error "no match" } + (N::A{} <= ... <= xs); // { dg-error "no match" } + (xs >= ... >= N::A{}); // { dg-error "no match" } + (N::A{} >= ... >= xs); // { dg-error "no match" } + + (xs += ... += N::A{}); // { dg-error "no match" } + (N::A{} += ... += xs); // { dg-error "no match" } + (xs -= ... -= N::A{}); // { dg-error "no match" } + (N::A{} -= ... -= xs); // { dg-error "no match" } + (xs *= ... *= N::A{}); // { dg-error "no match" } + (N::A{} *= ... *= xs); // { dg-error "no match" } + (xs /= ... /= N::A{}); // { dg-error "no match" } + (N::A{} /= ... /= xs); // { dg-error "no match" } + (xs %= ... %= N::A{}); // { dg-error "no match" } + (N::A{} %= ... %= xs); // { dg-error "no match" } + (xs |= ... |= N::A{}); // { dg-error "no match" } + (N::A{} |= ... |= xs); // { dg-error "no match" } + (xs ^= ... ^= N::A{}); // { dg-error "no match" } + (N::A{} ^= ... ^= xs); // { dg-error "no match" } + (xs <<= ... <<= N::A{}); // { dg-error "no match" } + (N::A{} <<= ... <<= xs); // { dg-error "no match" } + (xs >>= ... >>= N::A{}); // { dg-error "no match" } + (N::A{} >>= ... >>= xs); // { dg-error "no match" } + }; +} + +#include "operator-3-ops.h" + +int main() { + f()(N::A()); +} diff --git a/gcc/testsuite/g++.dg/lookup/operator-6.C b/gcc/testsuite/g++.dg/lookup/operator-6.C new file mode 100644 index 0000000000000000000000000000000000000000..b59c137226ae67a85e7b0af3c9fe70f4b286a136 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-6.C @@ -0,0 +1,59 @@ +// PR c++/83035 +// { dg-do compile { target c++11 } } +// Like operator-3.C but where the lookup occurs at non-block scope. + +template<class T, class = void> struct S { + static constexpr bool is_primary = true; +}; + +template<class T> struct S<T, decltype(+T())> { }; +template<class T> struct S<T, decltype(-T())> { }; +template<class T> struct S<T, decltype(*T())> { }; +template<class T> struct S<T, decltype(~T())> { }; +template<class T> struct S<T, decltype(&T())> { }; +template<class T> struct S<T, decltype(!T())> { }; +template<class T> struct S<T, decltype(++T())> { }; +template<class T> struct S<T, decltype(--T())> { }; +template<class T> struct S<T, decltype(T()++)> { }; +template<class T> struct S<T, decltype(T()--)> { }; + +template<class T> struct S<T, decltype(T()->*T())> { }; +template<class T> struct S<T, decltype(T() / T())> { }; +template<class T> struct S<T, decltype(T() * T())> { }; +template<class T> struct S<T, decltype(T() + T())> { }; +template<class T> struct S<T, decltype(T() - T())> { }; +template<class T> struct S<T, decltype(T() % T())> { }; +template<class T> struct S<T, decltype(T() & T())> { }; +template<class T> struct S<T, decltype(T() | T())> { }; +template<class T> struct S<T, decltype(T() ^ T())> { }; +template<class T> struct S<T, decltype(T() << T())> { }; +template<class T> struct S<T, decltype(T() >> T())> { }; +template<class T> struct S<T, decltype(T() && T())> { }; +template<class T> struct S<T, decltype(T() || T())> { }; +template<class T> struct S<T, decltype(T(), T())> { }; + +template<class T> struct S<T, decltype(T() == T())> { }; +template<class T> struct S<T, decltype(T() != T())> { }; +template<class T> struct S<T, decltype(T() < T())> { }; +template<class T> struct S<T, decltype(T() > T())> { }; +template<class T> struct S<T, decltype(T() <= T())> { }; +template<class T> struct S<T, decltype(T() >= T())> { }; +#if __cplusplus > 201703L +template<class T> struct S<T, decltype(T() <=> T())> { }; +#endif + +template<class T> struct S<T, decltype(T() += T())> { }; +template<class T> struct S<T, decltype(T() -= T())> { }; +template<class T> struct S<T, decltype(T() *= T())> { }; +template<class T> struct S<T, decltype(T() /= T())> { }; +template<class T> struct S<T, decltype(T() %= T())> { }; +template<class T> struct S<T, decltype(T() |= T())> { }; +template<class T> struct S<T, decltype(T() ^= T())> { }; +template<class T> struct S<T, decltype(T() <<= T())> { }; +template<class T> struct S<T, decltype(T() >>= T())> { }; + +namespace N { struct A { }; } + +#include "operator-3-ops.h" + +static_assert(S<N::A>::is_primary, ""); diff --git a/gcc/testsuite/g++.dg/lookup/operator-7.C b/gcc/testsuite/g++.dg/lookup/operator-7.C new file mode 100644 index 0000000000000000000000000000000000000000..546fcb0a52684c21923963043029826f3649a26f --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-7.C @@ -0,0 +1,27 @@ +// PR c++/100465 + +namespace N +{ + struct string + { + template<typename T> + void operator+=(T); + }; + + struct A { + void operator+=(char); // #1 + + template<typename T> + void f() { + string s; + s += T(); + } + + void g() { + f<char>(); + } + }; +} // namespace N + +template<typename T> +void operator+=(N::string, T); diff --git a/gcc/testsuite/g++.dg/lookup/operator-8.C b/gcc/testsuite/g++.dg/lookup/operator-8.C new file mode 100644 index 0000000000000000000000000000000000000000..64d8a97cdd005e81cda1a8754719adf01eb96871 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-8.C @@ -0,0 +1,34 @@ +// Verify phase 1 lookup works properly for rewritten non-dependent conditional +// operator expressions. + +// This test currently fails due to build_min_non_dep_op_overload not knowing +// how to handle rewritten operator expressions; see the FIXME in build_new_op. + +// { dg-do compile { target c++20 } } + +#include <compare> + +struct A { + bool operator==(int); + std::strong_ordering operator<=>(int); +}; + +template<class T> +void f() { + A a; + (void)(a != 0, 0 != a); // { dg-bogus "deleted" "" { xfail *-*-* } } + (void)(a < 0, 0 < a); // { dg-bogus "deleted" "" { xfail *-*-* } } + (void)(a <= 0, 0 <= a); // { dg-bogus "deleted" "" { xfail *-*-* } } + (void)(a > 0, 0 > a); // { dg-bogus "deleted" "" { xfail *-*-* } } + (void)(a >= 0, 0 >= a); // { dg-bogus "deleted" "" { xfail *-*-* } } +} + +// These later-declared namespace-scope overloads shouldn't be considered +// when instantiating f<int>. +bool operator!=(A, int) = delete; +bool operator<(A, int) = delete; +bool operator<=(A, int) = delete; +bool operator>(A, int) = delete; +bool operator>=(A, int) = delete; + +template void f<int>(); diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index ea6ee55340159cb1f394244905140a722e0726f8..fccdce6ad47d2687286dc769a580f65d05fdbb18 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -2669,7 +2669,7 @@ plugin_build_unary_expr (cc1_plugin::connection *self, break; default: - result = build_x_unary_op (/*loc=*/0, opcode, op0, tf_error); + result = build_x_unary_op (/*loc=*/0, opcode, op0, NULL_TREE, tf_error); break; } @@ -2794,7 +2794,7 @@ plugin_build_binary_expr (cc1_plugin::connection *self, default: result = build_x_binary_op (/*loc=*/0, opcode, op0, ERROR_MARK, - op1, ERROR_MARK, NULL, tf_error); + op1, ERROR_MARK, NULL_TREE, NULL, tf_error); break; }