From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 201A43858D28 for ; Wed, 15 Dec 2021 22:53:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 201A43858D28 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-505-KynZWxvMP2CCwT7DBlmpeA-1; Wed, 15 Dec 2021 17:53:44 -0500 X-MC-Unique: KynZWxvMP2CCwT7DBlmpeA-1 Received: by mail-qt1-f198.google.com with SMTP id h8-20020a05622a170800b002acc8656e05so31552917qtk.7 for ; Wed, 15 Dec 2021 14:53:44 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:mime-version; bh=BkYh0P7+L1xqIhbhyWnQz9EsKMIcRYhQsoBKpmDmXd4=; b=fH9OzHoT2fkNgCdA7g0vi+JgMe8TDePt/B2mE/1uRKKCkJm8SgGQ74oa8/cLofm8PL IVFyRru5189R81b+7PbrHgJ65xV6ZGw2lIB8dhpb/ktoi4S5hVSk7ZX7NvxcBXMYzmd7 nb+/HbABRbc2R/LB8tmW4ZXBuPT+sdfd1jdLKbdFcKMUAJmiDHLqhWb7b2imQQO27zrK 1mm1M3Hc9DNCPFxXdGkpPzAeNot4SoMQn1jCbc1sQlDkDa8d4KiINeZcCByzcCescW6o OmFtaEdYOe3fb20fzs4FHi7O3Aw8FhYWohcVHRMb1ahM2fkZ8oN92gDL5cq4TBz+mPtv 0AxA== X-Gm-Message-State: AOAM533lhzGewJJGIXDL4zkMY14OvRLa0QFD36aIXt3y7GgXKgs4xjBe KFC5Z0yMAkt1NdEZmwLdpXZrlp6zaXdurQx8L8rb0XSt9o6nLh2re7LB7KaIUXpF+WUcJPtOs0V K7z5dEej3eBU686ECuQ== X-Received: by 2002:a05:6214:b62:: with SMTP id ey2mr3676585qvb.0.1639608822214; Wed, 15 Dec 2021 14:53:42 -0800 (PST) X-Google-Smtp-Source: ABdhPJxvU01XSLdBY5RkEi4uQaGvjkt0CdIJk18IbDHVsxdsdqOhtgwrygklUHNLp1x6SSSPmGtM9w== X-Received: by 2002:a05:6214:b62:: with SMTP id ey2mr3676484qvb.0.1639608820340; Wed, 15 Dec 2021 14:53:40 -0800 (PST) Received: from [192.168.1.130] (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id a20sm1776006qkh.63.2021.12.15.14.53.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Dec 2021 14:53:39 -0800 (PST) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Wed, 15 Dec 2021 17:53:38 -0500 (EST) To: Jason Merrill cc: Patrick Palka , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] c++: two-stage name lookup for overloaded operators [PR51577] In-Reply-To: <11c7cfa4-a2a3-d012-5638-687194ea8737@redhat.com> Message-ID: <318cb467-0e62-2694-d838-125d2f49b11a@idea> References: <20211210145333.2868378-1-ppalka@redhat.com> <11c7cfa4-a2a3-d012-5638-687194ea8737@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-16.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Dec 2021 22:54:01 -0000 On Wed, 15 Dec 2021, Jason Merrill wrote: > On 12/10/21 09:53, Patrick Palka wrote: > > 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 result 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, say a DEPENDENT_OPERATOR_EXPR with enough operands to store > > the lookup results along and everything else, but that'd require a lot > > of careful work to make sure we handle this new tree code properly > > across the frontend. > > > > However, currently type-dependent operator (and call) expressions are > > given an empty TREE_TYPE, so this space is effectively unused except to > > signal that the expression is type-dependent. It'd be convenient if we > > could use this space to store the lookup results 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, and since the frontend doesn't seem to care > > much about the particular 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_binary_op & friends 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. 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. > > > > Bootstrapped and regtested on x86-64-pc-linux-gnu, does this look OK for > > trunk? > > > > 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. > > (DEPENDENT_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 > > DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS to build_x_*. > > (tsubst_omp_for_iterator): Adjust call to build_x_modify_expr. > > (tsubst_expr) : Pass > > DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS to build_x_*. > > (tsubst_copy_and_build) : Likewise. > > : Likewise. > > : Likewise. > > : Likewise. > > : 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 parmaeter 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. > > --- > > gcc/cp/call.c | 33 +++-- > > gcc/cp/constraint.cc | 11 +- > > gcc/cp/coroutines.cc | 2 +- > > gcc/cp/cp-objcp-common.c | 1 + > > gcc/cp/cp-tree.def | 5 + > > gcc/cp/cp-tree.h | 45 +++++-- > > gcc/cp/cxx-pretty-print.c | 4 +- > > gcc/cp/decl.c | 2 - > > gcc/cp/decl2.c | 5 +- > > gcc/cp/method.c | 12 +- > > gcc/cp/module.cc | 2 + > > gcc/cp/name-lookup.c | 133 +------------------ > > gcc/cp/name-lookup.h | 3 - > > gcc/cp/parser.c | 40 +++--- > > gcc/cp/pt.c | 27 +++- > > gcc/cp/ptree.c | 6 + > > gcc/cp/semantics.c | 46 ++++--- > > gcc/cp/tree.c | 2 - > > gcc/cp/typeck.c | 112 +++++++++++++--- > > gcc/cp/typeck2.c | 2 +- > > gcc/testsuite/g++.dg/lookup/operator-3-ops.h | 53 ++++++++ > > gcc/testsuite/g++.dg/lookup/operator-3.C | 56 +------- > > gcc/testsuite/g++.dg/lookup/operator-3a.C | 61 +++++++++ > > gcc/testsuite/g++.dg/lookup/operator-4.C | 74 +++++++++++ > > gcc/testsuite/g++.dg/lookup/operator-4a.C | 76 +++++++++++ > > gcc/testsuite/g++.dg/lookup/operator-5.C | 74 +++++++++++ > > gcc/testsuite/g++.dg/lookup/operator-5a.C | 76 +++++++++++ > > gcc/testsuite/g++.dg/lookup/operator-6.C | 59 ++++++++ > > gcc/testsuite/g++.dg/lookup/operator-7.C | 27 ++++ > > gcc/testsuite/g++.dg/lookup/operator-8.C | 34 +++++ > > libcc1/libcp1plugin.cc | 4 +- > > 31 files changed, 787 insertions(+), 300 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-3-ops.h > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-3a.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-4.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-4a.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-5.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-5a.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-6.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-7.C > > create mode 100644 gcc/testsuite/g++.dg/lookup/operator-8.C > > > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c > > index 28bd8e0c260..53a391cbc6b 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 *arglist, > > + vec *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 contains 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; > > vec *arglist; > > @@ -6554,7 +6567,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; > > @@ -6610,7 +6623,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. */ > > @@ -6767,7 +6780,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 2896efdd7f2..c235a657a77 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 9017902e6fb..c00672eeb6e 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 38eae881f0c..36e04cdee5e 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 725139bb457..6fb838cc850 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 e4330fb1f8b..8b98c061eea 100644 > > --- a/gcc/cp/cp-tree.h > > +++ b/gcc/cp/cp-tree.h > > @@ -2183,7 +2183,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 > > @@ -3976,9 +3977,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) > > @@ -4033,6 +4038,20 @@ 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. */ > > +#define DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS(NODE) \ > > + TYPE_VALUES_RAW (DEPENDENT_OPERATOR_TYPE_CHECK (NODE)) > > + > > +/* Helper for the above accessor macro that takes a dependent operator > > + expression instead of the type thereof. */ > > +#define DEPENDENT_OPERATOR_SAVED_LOOKUPS(NODE) \ > > + (TREE_TYPE (NODE) && TREE_CODE (TREE_TYPE (NODE)) == > > DEPENDENT_OPERATOR_TYPE \ > > + ? DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (TREE_TYPE (NODE)) \ > > + : NULL_TREE) > > Let's make this one an inline function; I'd prefer in general to avoid adding > new macros with rvalue results, or that use their argument more than once. Sounds good. I also renamed it to the more apt TEMPLATED_OPERATOR_SAVED_LOOKUPS since we use it on dependent as well as non-dependent operator expressions. > > > /* Indicates whether a string literal has been parenthesized. Such > > usages are disallowed in certain circumstances. */ > > @@ -6462,14 +6481,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 **, > > tsubst_flags_t); > > @@ -7873,8 +7893,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, > > @@ -7892,20 +7913,20 @@ extern tree cp_build_function_call_vec > > (tree, vec **, > > 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); > > @@ -7920,7 +7941,7 @@ extern tree build_x_compound_expr_from_list (tree, > > expr_list_kind, > > extern tree build_x_compound_expr_from_vec (vec *, > > 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, > > @@ -7936,7 +7957,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 3ea357deb80..6af009c6890 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 56f80775ca0..0b8b33a097c 100644 > > --- a/gcc/cp/decl.c > > +++ b/gcc/cp/decl.c > > @@ -17098,8 +17098,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 99f5dc784b7..062c175430b 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 935946f5eef..44439bae4ec 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 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 71d0fab411f..28283264da6 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 080692899a8..5ae7d870cc0 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 f63c4f5b8bb..db705d20c68 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 6f273bfe21f..1baa90ef8fd 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 > > @@ -18914,7 +18914,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; > > @@ -41551,7 +41551,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. */ > > @@ -41628,11 +41628,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); > > @@ -41860,7 +41862,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; > > @@ -41982,7 +41984,7 @@ cp_convert_omp_range_for (tree &this_pre_body, > > vec *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)) > > @@ -42020,7 +42022,7 @@ cp_convert_omp_range_for (tree &this_pre_body, > > vec *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); > > @@ -42060,7 +42062,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 cbdb4b566aa..2340139b238 100644 > > --- a/gcc/cp/pt.c > > +++ b/gcc/cp/pt.c > > @@ -12657,23 +12657,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 = DEPENDENT_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); > > } > > } > > @@ -17908,7 +17911,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); > > @@ -19221,6 +19224,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)), > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > complain)); > > case ANNOTATE_EXPR: > > @@ -19872,6 +19876,7 @@ tsubst_copy_and_build (tree t, > > } > > else > > r = build_x_indirect_ref (input_location, r, RO_UNARY_STAR, > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > complain|decltype_flag); > > if (REF_PARENTHESIZED_P (t)) > > @@ -19982,6 +19987,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, > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > complain|decltype_flag)); > > case PREDECREMENT_EXPR: > > @@ -19995,6 +20001,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)), > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > complain|decltype_flag)); > > case FIX_TRUNC_EXPR: > > @@ -20013,6 +20020,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, > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > complain|decltype_flag)); > > case PLUS_EXPR: > > @@ -20077,6 +20085,7 @@ tsubst_copy_and_build (tree t, > > (warning_suppressed_p (TREE_OPERAND (t, 1)) > > ? ERROR_MARK > > : TREE_CODE (TREE_OPERAND (t, 1))), > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > /*overload=*/NULL, > > complain|decltype_flag); > > if (EXPR_P (r)) > > @@ -20229,8 +20238,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, > > + DEPENDENT_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 > > @@ -20331,6 +20342,7 @@ tsubst_copy_and_build (tree t, > > RETURN (build_x_compound_expr (EXPR_LOCATION (t), > > op0, > > RECUR (TREE_OPERAND (t, 1)), > > + DEPENDENT_OPERATOR_SAVED_LOOKUPS (t), > > complain|decltype_flag)); > > } > > @@ -27011,6 +27023,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 d514aa2cad2..f7ddae77679 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 cdf63c15e21..7078af03d3c 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); > > @@ -9881,7 +9882,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; > > } > > @@ -9895,9 +9896,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; > > @@ -9925,7 +9927,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 > > @@ -9951,6 +9953,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; > > @@ -9980,13 +9983,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; > > @@ -10097,7 +10100,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))) > > @@ -10106,23 +10109,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); > > @@ -10138,13 +10142,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); > > @@ -10162,7 +10166,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); > > @@ -10873,7 +10877,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; > > @@ -12125,6 +12129,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; > > } > > @@ -12151,6 +12158,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 f6f7927f293..f319dbf3526 100644 > > --- a/gcc/cp/tree.c > > +++ b/gcc/cp/tree.c > > @@ -5974,8 +5974,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 4e60db40c76..88dca343315 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,64 @@ 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 contains the result of phase 1 name lookup that we performed > > + earlier at template definition time, so just carry it over. */; > > If we're going to keep using the same set of lookups, can we also reuse the > same DEPENDENT_OPERATOR_TYPE? It seems like you could pass the type to > build_x_* instead of pulling the lookups out as early. That sounds like it'd work well. But what if we instead just make DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS point back to the corresponding DEPENDENT_OPERATOR_TYPE via TREE_TYPE? As in the below... v2: Rename DEPENDENT_OPERATOR_SAVED_LOOKUPS to TEMPLATED_OPERATOR_SAVED_LOOKUPS and turn into an inline function. Make build_dependent_operator_type set/inspect the TREE_TYPE of the lookup result in order to reuse the DEPENDENT_OPERATOR_TYPE during partial instantiations. Document this in the comment for DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS. Bootstrap and regtest in progress. -- >8 -- 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) : Pass TEMPLATED_OPERATOR_SAVED_LOOKUPS to build_x_*. (tsubst_copy_and_build) : Likewise. : Likewise. : Likewise. : Likewise. : 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 parmaeter 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. --- gcc/cp/call.c | 33 +++-- gcc/cp/constraint.cc | 11 +- gcc/cp/coroutines.cc | 2 +- gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.def | 5 + gcc/cp/cp-tree.h | 49 +++++-- gcc/cp/cxx-pretty-print.c | 4 +- gcc/cp/decl.c | 2 - gcc/cp/decl2.c | 5 +- gcc/cp/method.c | 12 +- gcc/cp/module.cc | 2 + gcc/cp/name-lookup.c | 133 +------------------ gcc/cp/name-lookup.h | 3 - gcc/cp/parser.c | 40 +++--- gcc/cp/pt.c | 27 +++- gcc/cp/ptree.c | 6 + gcc/cp/semantics.c | 46 ++++--- gcc/cp/tree.c | 2 - gcc/cp/typeck.c | 115 +++++++++++++--- gcc/cp/typeck2.c | 2 +- gcc/testsuite/g++.dg/lookup/operator-3-ops.h | 53 ++++++++ gcc/testsuite/g++.dg/lookup/operator-3.C | 56 +------- gcc/testsuite/g++.dg/lookup/operator-3a.C | 61 +++++++++ gcc/testsuite/g++.dg/lookup/operator-4.C | 74 +++++++++++ gcc/testsuite/g++.dg/lookup/operator-4a.C | 76 +++++++++++ gcc/testsuite/g++.dg/lookup/operator-5.C | 74 +++++++++++ gcc/testsuite/g++.dg/lookup/operator-5a.C | 76 +++++++++++ gcc/testsuite/g++.dg/lookup/operator-6.C | 59 ++++++++ gcc/testsuite/g++.dg/lookup/operator-7.C | 27 ++++ gcc/testsuite/g++.dg/lookup/operator-8.C | 34 +++++ libcc1/libcp1plugin.cc | 4 +- 31 files changed, 794 insertions(+), 300 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/operator-3-ops.h create mode 100644 gcc/testsuite/g++.dg/lookup/operator-3a.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-4.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-4a.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-5.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-5a.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-6.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-7.C create mode 100644 gcc/testsuite/g++.dg/lookup/operator-8.C diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 347df5da35d..31c2308dc28 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 *arglist, + vec *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 contains 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 566f4e38fac..8e25ae23670 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 9017902e6fb..c00672eeb6e 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 38eae881f0c..36e04cdee5e 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 725139bb457..6fb838cc850 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 7f32cf56383..57a0da4e0ef 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,24 @@ 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) +{ + return TREE_TYPE (EXPR_CHECK (t)) && TREE_CODE (TREE_TYPE (t)) == DEPENDENT_OPERATOR_TYPE + ? DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (TREE_TYPE (t)) + : NULL_TREE; +} + /* Indicates whether a string literal has been parenthesized. Such usages are disallowed in certain circumstances. */ @@ -6464,14 +6487,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 **, tsubst_flags_t); @@ -7875,8 +7899,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 +7919,20 @@ extern tree cp_build_function_call_vec (tree, vec **, 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 +7947,7 @@ extern tree build_x_compound_expr_from_list (tree, expr_list_kind, extern tree build_x_compound_expr_from_vec (vec *, 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 +7963,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 3ea357deb80..6af009c6890 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 7c2048c6acb..24dd6701663 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -17098,8 +17098,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 99f5dc784b7..062c175430b 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 935946f5eef..44439bae4ec 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 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 9266055cd92..f3e7af22699 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 6b5e4349595..3bd7b206abb 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 f63c4f5b8bb..db705d20c68 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 c2564e51e41..5d72201f87c 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 *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 *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 42133a30c97..60cc23ba987 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 d514aa2cad2..f7ddae77679 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 356fb83200c..6603066c620 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 284fb5f4b2a..29f3c171606 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 4e60db40c76..d73c7fb6e33 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 contains 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 **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 *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 *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 3fb651a02ba..724684c0457 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 00000000000..fbd242a4e66 --- /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 bc5eb3d6693..98011efd543 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 at block scope. template void f (T x) { +x; // { dg-error "no match" } @@ -50,59 +52,7 @@ template 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 00000000000..62ae5c36dc2 --- /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 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 00000000000..e0b80a1c3b3 --- /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 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 00000000000..b4a3f947b05 --- /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 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 00000000000..2bbb2c41618 --- /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 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 00000000000..6f9ecd65a50 --- /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 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 00000000000..b59c137226a --- /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 struct S { + static constexpr bool is_primary = true; +}; + +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; + +template struct S*T())> { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S> T())> { }; +template struct S { }; +template struct S { }; +template struct S { }; + +template struct S { }; +template struct S { }; +template struct S { }; +template struct S T())> { }; +template struct S { }; +template struct S= T())> { }; +#if __cplusplus > 201703L +template struct S T())> { }; +#endif + +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S { }; +template struct S>= T())> { }; + +namespace N { struct A { }; } + +#include "operator-3-ops.h" + +static_assert(S::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 00000000000..546fcb0a526 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/operator-7.C @@ -0,0 +1,27 @@ +// PR c++/100465 + +namespace N +{ + struct string + { + template + void operator+=(T); + }; + + struct A { + void operator+=(char); // #1 + + template + void f() { + string s; + s += T(); + } + + void g() { + f(); + } + }; +} // namespace N + +template +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 00000000000..01adff963dc --- /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 + +struct A { + bool operator==(int); + std::strong_ordering operator<=>(int); +}; + +template +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 functions shouldn't be considered +// during instantiation of f. +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(); diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index ea6ee553401..fccdce6ad47 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; } -- 2.34.1.182.ge773545c7f