aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/call.c33
-rw-r--r--gcc/cp/constraint.cc11
-rw-r--r--gcc/cp/coroutines.cc2
-rw-r--r--gcc/cp/cp-objcp-common.c1
-rw-r--r--gcc/cp/cp-tree.def5
-rw-r--r--gcc/cp/cp-tree.h51
-rw-r--r--gcc/cp/cxx-pretty-print.c4
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/decl2.c5
-rw-r--r--gcc/cp/method.c12
-rw-r--r--gcc/cp/module.cc2
-rw-r--r--gcc/cp/name-lookup.c133
-rw-r--r--gcc/cp/name-lookup.h3
-rw-r--r--gcc/cp/parser.c40
-rw-r--r--gcc/cp/pt.c27
-rw-r--r--gcc/cp/ptree.c6
-rw-r--r--gcc/cp/semantics.c46
-rw-r--r--gcc/cp/tree.c2
-rw-r--r--gcc/cp/typeck.c115
-rw-r--r--gcc/cp/typeck2.c2
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-3-ops.h53
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-3.C56
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-3a.C61
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-4.C74
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-4a.C76
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-5.C74
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-5a.C76
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-6.C59
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-7.C27
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-8.C34
-rw-r--r--libcc1/libcp1plugin.cc4
31 files changed, 796 insertions, 300 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 347df5d..495dcdd 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6285,12 +6285,17 @@ op_is_ordered (tree_code code)
/* Subroutine of build_new_op: Add to CANDIDATES all candidates for the
operator indicated by CODE/CODE2. This function calls itself recursively to
- handle C++20 rewritten comparison operator candidates. */
+ handle C++20 rewritten comparison operator candidates.
+
+ LOOKUPS, if non-NULL, is the set of pertinent namespace-scope operator
+ overloads to consider. This parameter is used when instantiating a
+ dependent operator expression and has the same structure as
+ DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS. */
static tree
add_operator_candidates (z_candidate **candidates,
tree_code code, tree_code code2,
- vec<tree, va_gc> *arglist,
+ vec<tree, va_gc> *arglist, tree lookups,
int flags, tsubst_flags_t complain)
{
z_candidate *start_candidates = *candidates;
@@ -6326,7 +6331,15 @@ add_operator_candidates (z_candidate **candidates,
consider. */
if (!memonly)
{
- tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE);
+ tree fns;
+ if (!lookups)
+ fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE);
+ /* If LOOKUPS is non-NULL, then we're instantiating a dependent operator
+ expression, and LOOKUPS is the result of stage 1 name lookup. */
+ else if (tree found = purpose_member (fnname, lookups))
+ fns = TREE_VALUE (found);
+ else
+ fns = NULL_TREE;
fns = lookup_arg_dependent (fnname, fns, arglist);
add_candidates (fns, NULL_TREE, arglist, NULL_TREE,
NULL_TREE, false, NULL_TREE, NULL_TREE,
@@ -6429,7 +6442,7 @@ add_operator_candidates (z_candidate **candidates,
if (rewrite_code != code)
/* Add rewritten candidates in same order. */
add_operator_candidates (candidates, rewrite_code, ERROR_MARK,
- arglist, flags, complain);
+ arglist, lookups, flags, complain);
z_candidate *save_cand = *candidates;
@@ -6439,7 +6452,7 @@ add_operator_candidates (z_candidate **candidates,
revlist->quick_push ((*arglist)[1]);
revlist->quick_push ((*arglist)[0]);
add_operator_candidates (candidates, rewrite_code, ERROR_MARK,
- revlist, flags, complain);
+ revlist, lookups, flags, complain);
/* Release the vec if we didn't add a candidate that uses it. */
for (z_candidate *c = *candidates; c != save_cand; c = c->next)
@@ -6457,8 +6470,8 @@ add_operator_candidates (z_candidate **candidates,
tree
build_new_op (const op_location_t &loc, enum tree_code code, int flags,
- tree arg1, tree arg2, tree arg3, tree *overload,
- tsubst_flags_t complain)
+ tree arg1, tree arg2, tree arg3, tree lookups,
+ tree *overload, tsubst_flags_t complain)
{
struct z_candidate *candidates = 0, *cand;
releasing_vec arglist;
@@ -6552,7 +6565,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
p = conversion_obstack_alloc (0);
result = add_operator_candidates (&candidates, code, code2, arglist,
- flags, complain);
+ lookups, flags, complain);
if (result == error_mark_node)
goto user_defined_result_ready;
@@ -6608,7 +6621,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
else
code = PREDECREMENT_EXPR;
result = build_new_op (loc, code, flags, arg1, NULL_TREE,
- NULL_TREE, overload, complain);
+ NULL_TREE, lookups, overload, complain);
break;
/* The caller will deal with these. */
@@ -6765,7 +6778,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
warning_sentinel ws (warn_zero_as_null_pointer_constant);
result = build_new_op (loc, code,
LOOKUP_NORMAL|LOOKUP_REWRITTEN,
- lhs, rhs, NULL_TREE,
+ lhs, rhs, NULL_TREE, lookups,
NULL, complain);
}
break;
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 566f4e3..8e25ae2 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 9017902..c00672e 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 38eae88..36e04cd 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 725139b..6fb838c 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 7f32cf5..9eff434 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2185,7 +2185,8 @@ enum languages { lang_c, lang_cplusplus };
|| TREE_CODE (T) == TYPENAME_TYPE \
|| TREE_CODE (T) == TYPEOF_TYPE \
|| TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \
- || TREE_CODE (T) == DECLTYPE_TYPE)
+ || TREE_CODE (T) == DECLTYPE_TYPE \
+ || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
/* Nonzero if T is a class (or struct or union) type. Also nonzero
for template type parameters, typename types, and instantiated
@@ -3978,9 +3979,13 @@ struct GTY(()) lang_decl {
TREE_LANG_FLAG_0 (FOLD_EXPR_CHECK (NODE))
/* An INTEGER_CST containing the tree code of the folded operator. */
-#define FOLD_EXPR_OP(NODE) \
+#define FOLD_EXPR_OP_RAW(NODE) \
TREE_OPERAND (FOLD_EXPR_CHECK (NODE), 0)
+/* The tree code of the folded operator. */
+#define FOLD_EXPR_OP(NODE) \
+ ((enum tree_code) TREE_INT_CST_LOW (FOLD_EXPR_OP_RAW (NODE)))
+
/* The expression containing an unexpanded parameter pack. */
#define FOLD_EXPR_PACK(NODE) \
TREE_OPERAND (FOLD_EXPR_CHECK (NODE), 1)
@@ -4035,6 +4040,26 @@ struct GTY(()) lang_decl {
#define CALL_EXPR_OPERATOR_SYNTAX(NODE) \
TREE_LANG_FLAG_6 (CALL_OR_AGGR_INIT_CHECK (NODE))
+/* A TREE_LIST containing the result of phase 1 name lookup of the operator
+ overloads that are pertinent to the dependent operator expression whose
+ type is NODE. Each TREE_PURPOSE is an IDENTIFIER_NODE and TREE_VALUE is
+ the corresponding (possibly empty) lookup result. The TREE_TYPE of the
+ first TREE_LIST node points back to NODE. */
+#define DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS(NODE) \
+ TYPE_VALUES_RAW (DEPENDENT_OPERATOR_TYPE_CHECK (NODE))
+
+/* Guarded helper for the above accessor macro that takes a (templated)
+ operator expression instead of the type thereof. */
+inline tree
+templated_operator_saved_lookups (tree t)
+{
+ tree type = TREE_TYPE (EXPR_CHECK (t));
+ if (type && TREE_CODE (type) == DEPENDENT_OPERATOR_TYPE)
+ return DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (type);
+ else
+ return NULL_TREE;
+}
+
/* Indicates whether a string literal has been parenthesized. Such
usages are disallowed in certain circumstances. */
@@ -6464,14 +6489,15 @@ extern tree build_special_member_call (tree, tree,
tree, int, tsubst_flags_t);
extern tree build_new_op (const op_location_t &,
enum tree_code,
- int, tree, tree, tree, tree *,
- tsubst_flags_t);
+ int, tree, tree, tree, tree,
+ tree *, tsubst_flags_t);
/* Wrapper that leaves out the usually-null op3 and overload parms. */
inline tree build_new_op (const op_location_t &loc, enum tree_code code,
int flags, tree arg1, tree arg2,
tsubst_flags_t complain)
{
- return build_new_op (loc, code, flags, arg1, arg2, NULL_TREE, NULL, complain);
+ return build_new_op (loc, code, flags, arg1, arg2, NULL_TREE, NULL_TREE,
+ NULL, complain);
}
extern tree build_op_call (tree, vec<tree, va_gc> **,
tsubst_flags_t);
@@ -7875,8 +7901,9 @@ extern tree build_class_member_access_expr (cp_expr, tree, tree, bool,
extern tree finish_class_member_access_expr (cp_expr, tree, bool,
tsubst_flags_t);
extern tree lookup_destructor (tree, tree, tree, tsubst_flags_t);
+extern tree build_dependent_operator_type (tree, enum tree_code, bool);
extern tree build_x_indirect_ref (location_t, tree,
- ref_operator,
+ ref_operator, tree,
tsubst_flags_t);
extern tree cp_build_indirect_ref (location_t, tree,
ref_operator,
@@ -7894,20 +7921,20 @@ extern tree cp_build_function_call_vec (tree, vec<tree, va_gc> **,
extern tree build_x_binary_op (const op_location_t &,
enum tree_code, tree,
enum tree_code, tree,
- enum tree_code, tree *,
- tsubst_flags_t);
+ enum tree_code, tree,
+ tree *, tsubst_flags_t);
inline tree build_x_binary_op (const op_location_t &loc,
enum tree_code code, tree arg1, tree arg2,
tsubst_flags_t complain)
{
return build_x_binary_op (loc, code, arg1, TREE_CODE (arg1), arg2,
- TREE_CODE (arg2), NULL, complain);
+ TREE_CODE (arg2), NULL_TREE, NULL, complain);
}
extern tree build_x_array_ref (location_t, tree, tree,
tsubst_flags_t);
extern tree build_x_unary_op (location_t,
enum tree_code, cp_expr,
- tsubst_flags_t);
+ tree, tsubst_flags_t);
extern tree cp_build_addressof (location_t, tree,
tsubst_flags_t);
extern tree cp_build_addr_expr (tree, tsubst_flags_t);
@@ -7922,7 +7949,7 @@ extern tree build_x_compound_expr_from_list (tree, expr_list_kind,
extern tree build_x_compound_expr_from_vec (vec<tree, va_gc> *,
const char *, tsubst_flags_t);
extern tree build_x_compound_expr (location_t, tree, tree,
- tsubst_flags_t);
+ tree, tsubst_flags_t);
extern tree build_compound_expr (location_t, tree, tree);
extern tree cp_build_compound_expr (tree, tree, tsubst_flags_t);
extern tree build_static_cast (location_t, tree, tree,
@@ -7938,7 +7965,7 @@ extern tree cp_build_c_cast (location_t, tree, tree,
tsubst_flags_t);
extern cp_expr build_x_modify_expr (location_t, tree,
enum tree_code, tree,
- tsubst_flags_t);
+ tree, tsubst_flags_t);
extern tree cp_build_modify_expr (location_t, tree,
enum tree_code, tree,
tsubst_flags_t);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 3ea357d..6af009c 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 2e03398..7ca8770 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -17118,8 +17118,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
store_parm_decls (current_function_parms);
- push_operator_bindings ();
-
if (!processing_template_decl
&& (flag_lifetime_dse > 1)
&& DECL_CONSTRUCTOR_P (decl1)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 99f5dc7..062c175 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 935946f..44439ba 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1372,7 +1372,7 @@ do_one_comp (location_t loc, const comp_info &info, tree sub, tree lhs, tree rhs
to </=, so don't give an error yet if <=> lookup fails. */
bool tentative = retcat != cc_last;
tree comp = build_new_op (loc, code, flags, lhs, rhs,
- NULL_TREE, &overload,
+ NULL_TREE, NULL_TREE, &overload,
tentative ? tf_none : complain);
if (code != SPACESHIP_EXPR)
@@ -1684,8 +1684,8 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain)
comp = retval = var;
}
eq = build_new_op (info.loc, EQ_EXPR, flags, comp,
- integer_zero_node, NULL_TREE, NULL,
- complain);
+ integer_zero_node, NULL_TREE, NULL_TREE,
+ NULL, complain);
}
tree ceq = contextual_conv_bool (eq, complain);
info.check (ceq);
@@ -1720,7 +1720,7 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain)
else if (code == NE_EXPR)
{
tree comp = build_new_op (info.loc, EQ_EXPR, flags, lhs, rhs,
- NULL_TREE, NULL, complain);
+ NULL_TREE, NULL_TREE, NULL, complain);
comp = contextual_conv_bool (comp, complain);
info.check (comp);
if (defining)
@@ -1732,9 +1732,9 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain)
else
{
tree comp = build_new_op (info.loc, SPACESHIP_EXPR, flags, lhs, rhs,
- NULL_TREE, NULL, complain);
+ NULL_TREE, NULL_TREE, NULL, complain);
tree comp2 = build_new_op (info.loc, code, flags, comp, integer_zero_node,
- NULL_TREE, NULL, complain);
+ NULL_TREE, NULL_TREE, NULL, complain);
info.check (comp2);
if (defining)
finish_return_stmt (comp2);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 9266055..f3e7af2 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 6b5e434..3bd7b20 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 f63c4f5..db705d2 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 c2564e5..5d72201 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8731,7 +8731,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
return build_x_unary_op (token->location,
(keyword == RID_REALPART
? REALPART_EXPR : IMAGPART_EXPR),
- expression,
+ expression, NULL_TREE,
tf_warning_or_error);
}
break;
@@ -8908,7 +8908,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
case INDIRECT_REF:
non_constant_p = NIC_STAR;
expression = build_x_indirect_ref (loc, cast_expression,
- RO_UNARY_STAR,
+ RO_UNARY_STAR, NULL_TREE,
complain);
/* TODO: build_x_indirect_ref does not always honor the
location, so ensure it is set. */
@@ -8921,7 +8921,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
case BIT_NOT_EXPR:
expression = build_x_unary_op (loc, unary_operator,
cast_expression,
- complain);
+ NULL_TREE, complain);
/* TODO: build_x_unary_op does not always honor the location,
so ensure it is set. */
expression.set_location (loc);
@@ -10149,7 +10149,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
op_location_t op_loc (current.loc, combined_loc);
current.lhs = build_x_binary_op (op_loc, current.tree_type,
current.lhs, current.lhs_type,
- rhs, rhs_type, &overload,
+ rhs, rhs_type, NULL_TREE, &overload,
complain_flags (decltype_p));
/* TODO: build_x_binary_op doesn't always honor the location. */
current.lhs.set_location (combined_loc);
@@ -10328,7 +10328,7 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
rhs.get_finish ());
expr = build_x_modify_expr (loc, expr,
assignment_operator,
- rhs,
+ rhs, NULL_TREE,
complain_flags (decltype_p));
/* TODO: build_x_modify_expr doesn't honor the location,
so we must set it here. */
@@ -10480,7 +10480,7 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
expression.get_start (),
assignment_expression.get_finish ());
expression = build_x_compound_expr (loc, expression,
- assignment_expression,
+ assignment_expression, NULL_TREE,
complain_flags (decltype_p));
expression.set_location (loc);
}
@@ -13617,7 +13617,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr)
iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE,
iter_type);
iter_decl = build_x_indirect_ref (input_location, iter_decl,
- RO_UNARY_STAR,
+ RO_UNARY_STAR, NULL_TREE,
tf_warning_or_error);
TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl),
iter_decl, auto_node,
@@ -13804,7 +13804,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
condition = build_x_binary_op (input_location, NE_EXPR,
begin, ERROR_MARK,
end, ERROR_MARK,
- NULL, tf_warning_or_error);
+ NULL_TREE, NULL, tf_warning_or_error);
finish_for_cond (condition, statement, ivdep, unroll);
/* The new increment expression. */
@@ -13818,7 +13818,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
/* The declaration is initialized with *__begin inside the loop body. */
tree deref_begin = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
- tf_warning_or_error);
+ NULL_TREE, tf_warning_or_error);
cp_finish_decl (range_decl, deref_begin,
/*is_constant_init*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING);
@@ -13924,7 +13924,7 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
&& (build_x_binary_op (input_location, NE_EXPR,
*begin, ERROR_MARK,
*end, ERROR_MARK,
- NULL, tf_none)
+ NULL_TREE, NULL, tf_none)
!= error_mark_node))
/* P0184R0 allows __begin and __end to have different types,
but make sure they are comparable so we can give a better
@@ -18924,7 +18924,7 @@ cp_parser_template_argument (cp_parser* parser)
{
if (address_p)
argument = build_x_unary_op (loc, ADDR_EXPR, argument,
- tf_warning_or_error);
+ NULL_TREE, tf_warning_or_error);
else
argument = convert_from_reference (argument);
return argument;
@@ -41564,7 +41564,7 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code)
TREE_CODE (cond),
TREE_OPERAND (cond, 0), ERROR_MARK,
TREE_OPERAND (cond, 1), ERROR_MARK,
- /*overload=*/NULL, tf_warning_or_error);
+ NULL_TREE, /*overload=*/NULL, tf_warning_or_error);
}
/* Helper function, to parse omp for increment expression. */
@@ -41641,11 +41641,13 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl)
lhs = rhs;
else
lhs = build_x_unary_op (input_location, NEGATE_EXPR, rhs,
- tf_warning_or_error);
+ NULL_TREE, tf_warning_or_error);
}
else
- lhs = build_x_binary_op (input_location, op, lhs, ERROR_MARK, rhs,
- ERROR_MARK, NULL, tf_warning_or_error);
+ lhs = build_x_binary_op (input_location, op,
+ lhs, ERROR_MARK,
+ rhs, ERROR_MARK,
+ NULL_TREE, NULL, tf_warning_or_error);
}
}
while (token->type == CPP_PLUS || token->type == CPP_MINUS);
@@ -41873,7 +41875,7 @@ cp_parser_omp_for_loop_init (cp_parser *parser,
orig_init = rhs;
finish_expr_stmt (build_x_modify_expr (EXPR_LOCATION (rhs),
decl, NOP_EXPR,
- rhs,
+ rhs, NULL_TREE,
tf_warning_or_error));
if (!add_private_clause)
add_private_clause = decl;
@@ -41995,7 +41997,7 @@ cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block,
cond = build_x_binary_op (input_location, NE_EXPR,
begin, ERROR_MARK,
end, ERROR_MARK,
- NULL, tf_warning_or_error);
+ NULL_TREE, NULL, tf_warning_or_error);
/* The new increment expression. */
if (CLASS_TYPE_P (iter_type))
@@ -42033,7 +42035,7 @@ cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block,
if (auto_node)
{
tree t = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
- tf_none);
+ NULL_TREE, tf_none);
if (!error_operand_p (t))
TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl),
t, auto_node);
@@ -42073,7 +42075,7 @@ cp_finish_omp_range_for (tree orig, tree begin)
/* The declaration is initialized with *__begin inside the loop body. */
cp_finish_decl (decl,
build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
- tf_warning_or_error),
+ NULL_TREE, tf_warning_or_error),
/*is_constant_init*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING);
if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 62a058d..18c6f11 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 d514aa2..f7ddae7 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 356fb83..6603066 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 284fb5f..29f3c17 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 4e60db4..5184b02 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2602,6 +2602,7 @@ rationalize_conditional_expr (enum tree_code code, tree t,
? LE_EXPR : GE_EXPR),
op0, TREE_CODE (op0),
op1, TREE_CODE (op1),
+ NULL_TREE,
/*overload=*/NULL,
complain),
cp_build_unary_op (code, op0, false, complain),
@@ -3487,6 +3488,67 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
return build_simple_component_ref (ptrmem, member);
}
+/* Return a TREE_LIST of namespace-scope overloads for the given operator,
+ and for any other relevant operator. */
+
+static tree
+op_unqualified_lookup (tree_code code, bool is_assign)
+{
+ tree lookups = NULL_TREE;
+
+ if (cxx_dialect >= cxx20 && !is_assign)
+ {
+ if (code == NE_EXPR)
+ {
+ /* != can get rewritten in terms of ==. */
+ tree fnname = ovl_op_identifier (false, EQ_EXPR);
+ if (tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE))
+ lookups = tree_cons (fnname, fns, lookups);
+ }
+ else if (code == GT_EXPR || code == LE_EXPR
+ || code == LT_EXPR || code == GE_EXPR)
+ {
+ /* These can get rewritten in terms of <=>. */
+ tree fnname = ovl_op_identifier (false, SPACESHIP_EXPR);
+ if (tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE))
+ lookups = tree_cons (fnname, fns, lookups);
+ }
+ }
+
+ tree fnname = ovl_op_identifier (is_assign, code);
+ if (tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE))
+ lookups = tree_cons (fnname, fns, lookups);
+
+ if (lookups)
+ return lookups;
+ else
+ return build_tree_list (NULL_TREE, NULL_TREE);
+}
+
+/* Create a DEPENDENT_OPERATOR_TYPE for a dependent operator expression of
+ the given operator. LOOKUPS, if non-NULL, is the result of phase 1
+ name lookup for the given operator. */
+
+tree
+build_dependent_operator_type (tree lookups, tree_code code, bool is_assign)
+{
+ if (lookups)
+ /* We're partially instantiating a dependent operator expression, and
+ LOOKUPS is the result of phase 1 name lookup that we performed
+ earlier at template definition time, so just reuse the corresponding
+ DEPENDENT_OPERATOR_TYPE. */
+ return TREE_TYPE (lookups);
+
+ /* Otherwise we're processing a dependent operator expression at template
+ definition time, so perform phase 1 name lookup now. */
+ lookups = op_unqualified_lookup (code, is_assign);
+
+ tree type = cxx_make_type (DEPENDENT_OPERATOR_TYPE);
+ DEPENDENT_OPERATOR_TYPE_SAVED_LOOKUPS (type) = lookups;
+ TREE_TYPE (lookups) = type;
+ return type;
+}
+
/* Given an expression PTR for a pointer, return an expression
for the value pointed to.
ERRORSTRING is the name of the operator to appear in error messages.
@@ -3496,7 +3558,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
tree
build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
- tsubst_flags_t complain)
+ tree lookups, tsubst_flags_t complain)
{
tree orig_expr = expr;
tree rval;
@@ -3516,12 +3578,18 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
return build_min (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr);
}
if (type_dependent_expression_p (expr))
- return build_min_nt_loc (loc, INDIRECT_REF, expr);
+ {
+ expr = build_min_nt_loc (loc, INDIRECT_REF, expr);
+ TREE_TYPE (expr)
+ = build_dependent_operator_type (lookups, INDIRECT_REF, false);
+ return expr;
+ }
expr = build_non_dependent_expr (expr);
}
rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr,
- NULL_TREE, NULL_TREE, &overload, complain);
+ NULL_TREE, NULL_TREE, lookups,
+ &overload, complain);
if (!rval)
rval = cp_build_indirect_ref (loc, expr, errorstring, complain);
@@ -4458,8 +4526,8 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
tree
build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
enum tree_code arg1_code, tree arg2,
- enum tree_code arg2_code, tree *overload_p,
- tsubst_flags_t complain)
+ enum tree_code arg2_code, tree lookups,
+ tree *overload_p, tsubst_flags_t complain)
{
tree orig_arg1;
tree orig_arg2;
@@ -4475,7 +4543,8 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
|| type_dependent_expression_p (arg2))
{
expr = build_min_nt_loc (loc, code, arg1, arg2);
- maybe_save_operator_binding (expr);
+ TREE_TYPE (expr)
+ = build_dependent_operator_type (lookups, code, false);
return expr;
}
arg1 = build_non_dependent_expr (arg1);
@@ -4486,7 +4555,7 @@ build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
expr = build_m_component_ref (arg1, arg2, complain);
else
expr = build_new_op (loc, code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
- &overload, complain);
+ lookups, &overload, complain);
if (overload_p != NULL)
*overload_p = overload;
@@ -4538,7 +4607,7 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2,
}
expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, arg1, arg2,
- NULL_TREE, &overload, complain);
+ NULL_TREE, NULL_TREE, &overload, complain);
if (processing_template_decl && expr != error_mark_node)
{
@@ -6402,7 +6471,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
tree
build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
- tsubst_flags_t complain)
+ tree lookups, tsubst_flags_t complain)
{
tree orig_expr = xarg;
tree exp;
@@ -6414,7 +6483,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
if (type_dependent_expression_p (xarg))
{
tree e = build_min_nt_loc (loc, code, xarg.get_value (), NULL_TREE);
- maybe_save_operator_binding (e);
+ TREE_TYPE (e) = build_dependent_operator_type (lookups, code, false);
return e;
}
@@ -6439,7 +6508,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
/* Don't look for a function. */;
else
exp = build_new_op (loc, code, LOOKUP_NORMAL, xarg, NULL_TREE,
- NULL_TREE, &overload, complain);
+ NULL_TREE, lookups, &overload, complain);
if (!exp && code == ADDR_EXPR)
{
@@ -7508,7 +7577,8 @@ build_x_compound_expr_from_list (tree list, expr_list_kind exp,
for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
expr = build_x_compound_expr (EXPR_LOCATION (TREE_VALUE (list)),
- expr, TREE_VALUE (list), complain);
+ expr, TREE_VALUE (list), NULL_TREE,
+ complain);
}
return expr;
@@ -7543,7 +7613,7 @@ build_x_compound_expr_from_vec (vec<tree, va_gc> *vec, const char *msg,
expr = (*vec)[0];
for (ix = 1; vec->iterate (ix, &t); ++ix)
expr = build_x_compound_expr (EXPR_LOCATION (t), expr,
- t, complain);
+ t, NULL_TREE, complain);
return expr;
}
@@ -7553,7 +7623,7 @@ build_x_compound_expr_from_vec (vec<tree, va_gc> *vec, const char *msg,
tree
build_x_compound_expr (location_t loc, tree op1, tree op2,
- tsubst_flags_t complain)
+ tree lookups, tsubst_flags_t complain)
{
tree result;
tree orig_op1 = op1;
@@ -7566,7 +7636,8 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
|| type_dependent_expression_p (op2))
{
result = build_min_nt_loc (loc, COMPOUND_EXPR, op1, op2);
- maybe_save_operator_binding (result);
+ TREE_TYPE (result)
+ = build_dependent_operator_type (lookups, COMPOUND_EXPR, false);
return result;
}
op1 = build_non_dependent_expr (op1);
@@ -7574,7 +7645,7 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
}
result = build_new_op (loc, COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2,
- NULL_TREE, &overload, complain);
+ NULL_TREE, lookups, &overload, complain);
if (!result)
result = cp_build_compound_expr (op1, op2, complain);
@@ -9017,8 +9088,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
{
result = build_new_op (input_location, MODIFY_EXPR,
LOOKUP_NORMAL, lhs, rhs,
- make_node (NOP_EXPR), /*overload=*/NULL,
- complain);
+ make_node (NOP_EXPR), NULL_TREE,
+ /*overload=*/NULL, complain);
if (result == NULL_TREE)
return error_mark_node;
goto ret;
@@ -9233,7 +9304,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
cp_expr
build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
- tree rhs, tsubst_flags_t complain)
+ tree rhs, tree lookups, tsubst_flags_t complain)
{
tree orig_lhs = lhs;
tree orig_rhs = rhs;
@@ -9250,7 +9321,9 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
{
tree op = build_min_nt_loc (loc, modifycode, NULL_TREE, NULL_TREE);
tree rval = build_min_nt_loc (loc, MODOP_EXPR, lhs, op, rhs);
- maybe_save_operator_binding (rval);
+ if (modifycode != NOP_EXPR)
+ TREE_TYPE (rval)
+ = build_dependent_operator_type (lookups, modifycode, true);
return rval;
}
@@ -9262,7 +9335,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
{
tree op = build_nt (modifycode, NULL_TREE, NULL_TREE);
tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, op, &overload, complain);
+ lhs, rhs, op, lookups, &overload, complain);
if (rval)
{
if (rval == error_mark_node)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 3fb651a..724684c 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 0000000..fbd242a
--- /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 bc5eb3d..ab0257a 100644
--- a/gcc/testsuite/g++.dg/lookup/operator-3.C
+++ b/gcc/testsuite/g++.dg/lookup/operator-3.C
@@ -1,4 +1,6 @@
// PR c++/51577
+// Verify we don't consider later-declared namespace-scope operator overloads
+// when instantiating a dependent operator expression that occurs at block scope.
template <class T> void f (T x) {
+x; // { dg-error "no match" }
@@ -50,59 +52,7 @@ template <class T> void f (T x) {
namespace N { struct A { }; }
-void operator+(N::A);
-void operator-(N::A);
-void operator*(N::A);
-void operator~(N::A);
-#if __cplusplus >= 201103L
-void operator&(N::A) = delete;
-#else
-void operator&(N::A);
-#endif
-void operator!(N::A);
-void operator++(N::A);
-void operator--(N::A);
-void operator++(N::A, int);
-void operator--(N::A, int);
-
-void operator->*(N::A, N::A);
-void operator/(N::A, N::A);
-void operator*(N::A, N::A);
-void operator+(N::A, N::A);
-void operator-(N::A, N::A);
-void operator%(N::A, N::A);
-void operator&(N::A, N::A);
-void operator|(N::A, N::A);
-void operator^(N::A, N::A);
-void operator<<(N::A, N::A);
-void operator>>(N::A, N::A);
-void operator&&(N::A, N::A);
-void operator||(N::A, N::A);
-#if __cplusplus >= 201103L
-void operator,(N::A, N::A) = delete;
-#else
-void operator,(N::A, N::A);
-#endif
-
-void operator==(N::A, N::A);
-void operator!=(N::A, N::A);
-void operator<(N::A, N::A);
-void operator>(N::A, N::A);
-void operator<=(N::A, N::A);
-void operator>=(N::A, N::A);
-#if __cplusplus > 201703L
-void operator<=>(N::A, N::A);
-#endif
-
-void operator+=(N::A, N::A);
-void operator-=(N::A, N::A);
-void operator*=(N::A, N::A);
-void operator/=(N::A, N::A);
-void operator%=(N::A, N::A);
-void operator|=(N::A, N::A);
-void operator^=(N::A, N::A);
-void operator<<=(N::A, N::A);
-void operator>>=(N::A, N::A);
+#include "operator-3-ops.h"
int main() {
f(N::A());
diff --git a/gcc/testsuite/g++.dg/lookup/operator-3a.C b/gcc/testsuite/g++.dg/lookup/operator-3a.C
new file mode 100644
index 0000000..62ae5c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-3a.C
@@ -0,0 +1,61 @@
+// PR c++/51577
+// { dg-do compile { target c++14 } }
+// Like operator-3.C but also containing a partial instantiation step.
+
+template <class...> auto f () {
+ return [] (auto x) {
+ +x; // { dg-error "no match" }
+ -x; // { dg-error "no match" }
+ *x; // { dg-error "no match" }
+ ~x; // { dg-error "no match" }
+ &x;
+ !x; // { dg-error "no match" }
+ ++x; // { dg-error "no match" }
+ --x; // { dg-error "no match" }
+ x++; // { dg-error "declared for postfix" }
+ x--; // { dg-error "declared for postfix" }
+
+ x->*x; // { dg-error "no match" }
+ x / x; // { dg-error "no match" }
+ x * x; // { dg-error "no match" }
+ x + x; // { dg-error "no match" }
+ x - x; // { dg-error "no match" }
+ x % x; // { dg-error "no match" }
+ x & x; // { dg-error "no match" }
+ x | x; // { dg-error "no match" }
+ x ^ x; // { dg-error "no match" }
+ x << x; // { dg-error "no match" }
+ x >> x; // { dg-error "no match" }
+ x && x; // { dg-error "no match" }
+ x || x; // { dg-error "no match" }
+ x, x;
+
+ x == x; // { dg-error "no match" }
+ x != x; // { dg-error "no match" }
+ x < x; // { dg-error "no match" }
+ x > x; // { dg-error "no match" }
+ x <= x; // { dg-error "no match" }
+ x >= x; // { dg-error "no match" }
+#if __cplusplus > 201703L
+ x <=> x; // { dg-error "no match" "" { target c++20 } }
+#endif
+
+ x += x; // { dg-error "no match" }
+ x -= x; // { dg-error "no match" }
+ x *= x; // { dg-error "no match" }
+ x /= x; // { dg-error "no match" }
+ x %= x; // { dg-error "no match" }
+ x |= x; // { dg-error "no match" }
+ x ^= x; // { dg-error "no match" }
+ x <<= x; // { dg-error "no match" }
+ x >>= x; // { dg-error "no match" }
+ };
+}
+
+namespace N { struct A { }; }
+
+#include "operator-3-ops.h"
+
+int main() {
+ f()(N::A());
+}
diff --git a/gcc/testsuite/g++.dg/lookup/operator-4.C b/gcc/testsuite/g++.dg/lookup/operator-4.C
new file mode 100644
index 0000000..e0b80a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-4.C
@@ -0,0 +1,74 @@
+// PR c++/51577
+// { dg-do compile { target c++17 } }
+// Like operator-3.C but for unary fold expressions.
+
+template <class... Ts> void f (Ts... xs) {
+ (xs->*...); // { dg-error "no match" }
+ (...->*xs); // { dg-error "no match" }
+ (xs / ...); // { dg-error "no match" }
+ (... / xs); // { dg-error "no match" }
+ (xs * ...); // { dg-error "no match" }
+ (... * xs); // { dg-error "no match" }
+ (xs + ...); // { dg-error "no match" }
+ (... + xs); // { dg-error "no match" }
+ (xs - ...); // { dg-error "no match" }
+ (... - xs); // { dg-error "no match" }
+ (xs % ...); // { dg-error "no match" }
+ (... % xs); // { dg-error "no match" }
+ (xs & ...); // { dg-error "no match" }
+ (... & xs); // { dg-error "no match" }
+ (xs | ...); // { dg-error "no match" }
+ (... | xs); // { dg-error "no match" }
+ (xs ^ ...); // { dg-error "no match" }
+ (... ^ xs); // { dg-error "no match" }
+ (xs << ...); // { dg-error "no match" }
+ (... << xs); // { dg-error "no match" }
+ (xs >> ...); // { dg-error "no match" }
+ (... >> xs); // { dg-error "no match" }
+ (xs && ...); // { dg-error "no match" }
+ (... && xs); // { dg-error "no match" }
+ (xs || ...); // { dg-error "no match" }
+ (... || xs); // { dg-error "no match" }
+ (xs, ...);
+ (..., xs);
+
+ (xs == ...); // { dg-error "no match" }
+ (... == xs); // { dg-error "no match" }
+ (xs != ...); // { dg-error "no match" }
+ (... != xs); // { dg-error "no match" }
+ (xs < ...); // { dg-error "no match" }
+ (... < xs); // { dg-error "no match" }
+ (xs > ...); // { dg-error "no match" }
+ (... > xs); // { dg-error "no match" }
+ (xs <= ...); // { dg-error "no match" }
+ (... <= xs); // { dg-error "no match" }
+ (xs >= ...); // { dg-error "no match" }
+ (... >= xs); // { dg-error "no match" }
+
+ (xs += ...); // { dg-error "no match" }
+ (... += xs); // { dg-error "no match" }
+ (xs -= ...); // { dg-error "no match" }
+ (... -= xs); // { dg-error "no match" }
+ (xs *= ...); // { dg-error "no match" }
+ (... *= xs); // { dg-error "no match" }
+ (xs /= ...); // { dg-error "no match" }
+ (... /= xs); // { dg-error "no match" }
+ (xs %= ...); // { dg-error "no match" }
+ (... %= xs); // { dg-error "no match" }
+ (xs |= ...); // { dg-error "no match" }
+ (... |= xs); // { dg-error "no match" }
+ (xs ^= ...); // { dg-error "no match" }
+ (... ^= xs); // { dg-error "no match" }
+ (xs <<= ...); // { dg-error "no match" }
+ (... <<= xs); // { dg-error "no match" }
+ (xs >>= ...); // { dg-error "no match" }
+ (... >>= xs); // { dg-error "no match" }
+}
+
+namespace N { struct A { }; }
+
+#include "operator-3-ops.h"
+
+int main() {
+ f(N::A(), N::A());
+}
diff --git a/gcc/testsuite/g++.dg/lookup/operator-4a.C b/gcc/testsuite/g++.dg/lookup/operator-4a.C
new file mode 100644
index 0000000..b4a3f94
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-4a.C
@@ -0,0 +1,76 @@
+// PR c++/51577
+// { dg-do compile { target c++17 } }
+// Like operator-4.C but also containing a partial instantiation step.
+
+template <class...> auto f () {
+ return [] (auto... xs) {
+ (xs->*...); // { dg-error "no match" }
+ (...->*xs); // { dg-error "no match" }
+ (xs / ...); // { dg-error "no match" }
+ (... / xs); // { dg-error "no match" }
+ (xs * ...); // { dg-error "no match" }
+ (... * xs); // { dg-error "no match" }
+ (xs + ...); // { dg-error "no match" }
+ (... + xs); // { dg-error "no match" }
+ (xs - ...); // { dg-error "no match" }
+ (... - xs); // { dg-error "no match" }
+ (xs % ...); // { dg-error "no match" }
+ (... % xs); // { dg-error "no match" }
+ (xs & ...); // { dg-error "no match" }
+ (... & xs); // { dg-error "no match" }
+ (xs | ...); // { dg-error "no match" }
+ (... | xs); // { dg-error "no match" }
+ (xs ^ ...); // { dg-error "no match" }
+ (... ^ xs); // { dg-error "no match" }
+ (xs << ...); // { dg-error "no match" }
+ (... << xs); // { dg-error "no match" }
+ (xs >> ...); // { dg-error "no match" }
+ (... >> xs); // { dg-error "no match" }
+ (xs && ...); // { dg-error "no match" }
+ (... && xs); // { dg-error "no match" }
+ (xs || ...); // { dg-error "no match" }
+ (... || xs); // { dg-error "no match" }
+ (xs, ...);
+ (..., xs);
+
+ (xs == ...); // { dg-error "no match" }
+ (... == xs); // { dg-error "no match" }
+ (xs != ...); // { dg-error "no match" }
+ (... != xs); // { dg-error "no match" }
+ (xs < ...); // { dg-error "no match" }
+ (... < xs); // { dg-error "no match" }
+ (xs > ...); // { dg-error "no match" }
+ (... > xs); // { dg-error "no match" }
+ (xs <= ...); // { dg-error "no match" }
+ (... <= xs); // { dg-error "no match" }
+ (xs >= ...); // { dg-error "no match" }
+ (... >= xs); // { dg-error "no match" }
+
+ (xs += ...); // { dg-error "no match" }
+ (... += xs); // { dg-error "no match" }
+ (xs -= ...); // { dg-error "no match" }
+ (... -= xs); // { dg-error "no match" }
+ (xs *= ...); // { dg-error "no match" }
+ (... *= xs); // { dg-error "no match" }
+ (xs /= ...); // { dg-error "no match" }
+ (... /= xs); // { dg-error "no match" }
+ (xs %= ...); // { dg-error "no match" }
+ (... %= xs); // { dg-error "no match" }
+ (xs |= ...); // { dg-error "no match" }
+ (... |= xs); // { dg-error "no match" }
+ (xs ^= ...); // { dg-error "no match" }
+ (... ^= xs); // { dg-error "no match" }
+ (xs <<= ...); // { dg-error "no match" }
+ (... <<= xs); // { dg-error "no match" }
+ (xs >>= ...); // { dg-error "no match" }
+ (... >>= xs); // { dg-error "no match" }
+ };
+}
+
+namespace N { struct A { }; }
+
+#include "operator-3-ops.h"
+
+int main() {
+ f()(N::A(), N::A());
+}
diff --git a/gcc/testsuite/g++.dg/lookup/operator-5.C b/gcc/testsuite/g++.dg/lookup/operator-5.C
new file mode 100644
index 0000000..2bbb2c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-5.C
@@ -0,0 +1,74 @@
+// PR c++/51577
+// { dg-do compile { target c++17 } }
+// Like operator-4.C but for binary fold expressions.
+
+namespace N { struct A { }; }
+
+template <class... Ts> void f (Ts... xs) {
+ (xs->*...->*N::A{}); // { dg-error "no match" }
+ (N::A{}->*...->*xs); // { dg-error "no match" }
+ (xs / ... / N::A{}); // { dg-error "no match" }
+ (N::A{} / ... / xs); // { dg-error "no match" }
+ (xs * ... * N::A{}); // { dg-error "no match" }
+ (N::A{} * ... * xs); // { dg-error "no match" }
+ (xs + ... + N::A{}); // { dg-error "no match" }
+ (N::A{} + ... + xs); // { dg-error "no match" }
+ (xs - ... - N::A{}); // { dg-error "no match" }
+ (N::A{} - ... - xs); // { dg-error "no match" }
+ (xs % ... % N::A{}); // { dg-error "no match" }
+ (N::A{} % ... % xs); // { dg-error "no match" }
+ (xs & ... & N::A{}); // { dg-error "no match" }
+ (N::A{} & ... & xs); // { dg-error "no match" }
+ (xs | ... | N::A{}); // { dg-error "no match" }
+ (N::A{} | ... | xs); // { dg-error "no match" }
+ (xs ^ ... ^ N::A{}); // { dg-error "no match" }
+ (N::A{} ^ ... ^ xs); // { dg-error "no match" }
+ (xs << ... << N::A{}); // { dg-error "no match" }
+ (N::A{} << ... << xs); // { dg-error "no match" }
+ (xs >> ... >> N::A{}); // { dg-error "no match" }
+ (N::A{} >> ... >> xs); // { dg-error "no match" }
+ (xs && ... && N::A{}); // { dg-error "no match" }
+ (N::A{} && ... && xs); // { dg-error "no match" }
+ (xs || ... || N::A{}); // { dg-error "no match" }
+ (N::A{} || ... || xs); // { dg-error "no match" }
+ (xs , ... , N::A{});
+ (N::A{} , ... , xs);
+
+ (xs == ... == N::A{}); // { dg-error "no match" }
+ (N::A{} == ... == xs); // { dg-error "no match" }
+ (xs != ... != N::A{}); // { dg-error "no match" }
+ (N::A{} != ... != xs); // { dg-error "no match" }
+ (xs < ... < N::A{}); // { dg-error "no match" }
+ (N::A{} < ... < xs); // { dg-error "no match" }
+ (xs > ... > N::A{}); // { dg-error "no match" }
+ (N::A{} > ... > xs); // { dg-error "no match" }
+ (xs <= ... <= N::A{}); // { dg-error "no match" }
+ (N::A{} <= ... <= xs); // { dg-error "no match" }
+ (xs >= ... >= N::A{}); // { dg-error "no match" }
+ (N::A{} >= ... >= xs); // { dg-error "no match" }
+
+ (xs += ... += N::A{}); // { dg-error "no match" }
+ (N::A{} += ... += xs); // { dg-error "no match" }
+ (xs -= ... -= N::A{}); // { dg-error "no match" }
+ (N::A{} -= ... -= xs); // { dg-error "no match" }
+ (xs *= ... *= N::A{}); // { dg-error "no match" }
+ (N::A{} *= ... *= xs); // { dg-error "no match" }
+ (xs /= ... /= N::A{}); // { dg-error "no match" }
+ (N::A{} /= ... /= xs); // { dg-error "no match" }
+ (xs %= ... %= N::A{}); // { dg-error "no match" }
+ (N::A{} %= ... %= xs); // { dg-error "no match" }
+ (xs |= ... |= N::A{}); // { dg-error "no match" }
+ (N::A{} |= ... |= xs); // { dg-error "no match" }
+ (xs ^= ... ^= N::A{}); // { dg-error "no match" }
+ (N::A{} ^= ... ^= xs); // { dg-error "no match" }
+ (xs <<= ... <<= N::A{}); // { dg-error "no match" }
+ (N::A{} <<= ... <<= xs); // { dg-error "no match" }
+ (xs >>= ... >>= N::A{}); // { dg-error "no match" }
+ (N::A{} >>= ... >>= xs); // { dg-error "no match" }
+}
+
+#include "operator-3-ops.h"
+
+int main() {
+ f(N::A());
+}
diff --git a/gcc/testsuite/g++.dg/lookup/operator-5a.C b/gcc/testsuite/g++.dg/lookup/operator-5a.C
new file mode 100644
index 0000000..6f9ecd6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-5a.C
@@ -0,0 +1,76 @@
+// PR c++/51577
+// { dg-do compile { target c++17 } }
+// Like operator-5.C but also containing a partial instantiation step.
+
+namespace N { struct A { }; }
+
+template <class...> auto f () {
+ return [] (auto... xs) {
+ (xs->*...->*N::A{}); // { dg-error "no match" }
+ (N::A{}->*...->*xs); // { dg-error "no match" }
+ (xs / ... / N::A{}); // { dg-error "no match" }
+ (N::A{} / ... / xs); // { dg-error "no match" }
+ (xs * ... * N::A{}); // { dg-error "no match" }
+ (N::A{} * ... * xs); // { dg-error "no match" }
+ (xs + ... + N::A{}); // { dg-error "no match" }
+ (N::A{} + ... + xs); // { dg-error "no match" }
+ (xs - ... - N::A{}); // { dg-error "no match" }
+ (N::A{} - ... - xs); // { dg-error "no match" }
+ (xs % ... % N::A{}); // { dg-error "no match" }
+ (N::A{} % ... % xs); // { dg-error "no match" }
+ (xs & ... & N::A{}); // { dg-error "no match" }
+ (N::A{} & ... & xs); // { dg-error "no match" }
+ (xs | ... | N::A{}); // { dg-error "no match" }
+ (N::A{} | ... | xs); // { dg-error "no match" }
+ (xs ^ ... ^ N::A{}); // { dg-error "no match" }
+ (N::A{} ^ ... ^ xs); // { dg-error "no match" }
+ (xs << ... << N::A{}); // { dg-error "no match" }
+ (N::A{} << ... << xs); // { dg-error "no match" }
+ (xs >> ... >> N::A{}); // { dg-error "no match" }
+ (N::A{} >> ... >> xs); // { dg-error "no match" }
+ (xs && ... && N::A{}); // { dg-error "no match" }
+ (N::A{} && ... && xs); // { dg-error "no match" }
+ (xs || ... || N::A{}); // { dg-error "no match" }
+ (N::A{} || ... || xs); // { dg-error "no match" }
+ (xs , ... , N::A{});
+ (N::A{} , ... , xs);
+
+ (xs == ... == N::A{}); // { dg-error "no match" }
+ (N::A{} == ... == xs); // { dg-error "no match" }
+ (xs != ... != N::A{}); // { dg-error "no match" }
+ (N::A{} != ... != xs); // { dg-error "no match" }
+ (xs < ... < N::A{}); // { dg-error "no match" }
+ (N::A{} < ... < xs); // { dg-error "no match" }
+ (xs > ... > N::A{}); // { dg-error "no match" }
+ (N::A{} > ... > xs); // { dg-error "no match" }
+ (xs <= ... <= N::A{}); // { dg-error "no match" }
+ (N::A{} <= ... <= xs); // { dg-error "no match" }
+ (xs >= ... >= N::A{}); // { dg-error "no match" }
+ (N::A{} >= ... >= xs); // { dg-error "no match" }
+
+ (xs += ... += N::A{}); // { dg-error "no match" }
+ (N::A{} += ... += xs); // { dg-error "no match" }
+ (xs -= ... -= N::A{}); // { dg-error "no match" }
+ (N::A{} -= ... -= xs); // { dg-error "no match" }
+ (xs *= ... *= N::A{}); // { dg-error "no match" }
+ (N::A{} *= ... *= xs); // { dg-error "no match" }
+ (xs /= ... /= N::A{}); // { dg-error "no match" }
+ (N::A{} /= ... /= xs); // { dg-error "no match" }
+ (xs %= ... %= N::A{}); // { dg-error "no match" }
+ (N::A{} %= ... %= xs); // { dg-error "no match" }
+ (xs |= ... |= N::A{}); // { dg-error "no match" }
+ (N::A{} |= ... |= xs); // { dg-error "no match" }
+ (xs ^= ... ^= N::A{}); // { dg-error "no match" }
+ (N::A{} ^= ... ^= xs); // { dg-error "no match" }
+ (xs <<= ... <<= N::A{}); // { dg-error "no match" }
+ (N::A{} <<= ... <<= xs); // { dg-error "no match" }
+ (xs >>= ... >>= N::A{}); // { dg-error "no match" }
+ (N::A{} >>= ... >>= xs); // { dg-error "no match" }
+ };
+}
+
+#include "operator-3-ops.h"
+
+int main() {
+ f()(N::A());
+}
diff --git a/gcc/testsuite/g++.dg/lookup/operator-6.C b/gcc/testsuite/g++.dg/lookup/operator-6.C
new file mode 100644
index 0000000..b59c137
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-6.C
@@ -0,0 +1,59 @@
+// PR c++/83035
+// { dg-do compile { target c++11 } }
+// Like operator-3.C but where the lookup occurs at non-block scope.
+
+template<class T, class = void> struct S {
+ static constexpr bool is_primary = true;
+};
+
+template<class T> struct S<T, decltype(+T())> { };
+template<class T> struct S<T, decltype(-T())> { };
+template<class T> struct S<T, decltype(*T())> { };
+template<class T> struct S<T, decltype(~T())> { };
+template<class T> struct S<T, decltype(&T())> { };
+template<class T> struct S<T, decltype(!T())> { };
+template<class T> struct S<T, decltype(++T())> { };
+template<class T> struct S<T, decltype(--T())> { };
+template<class T> struct S<T, decltype(T()++)> { };
+template<class T> struct S<T, decltype(T()--)> { };
+
+template<class T> struct S<T, decltype(T()->*T())> { };
+template<class T> struct S<T, decltype(T() / T())> { };
+template<class T> struct S<T, decltype(T() * T())> { };
+template<class T> struct S<T, decltype(T() + T())> { };
+template<class T> struct S<T, decltype(T() - T())> { };
+template<class T> struct S<T, decltype(T() % T())> { };
+template<class T> struct S<T, decltype(T() & T())> { };
+template<class T> struct S<T, decltype(T() | T())> { };
+template<class T> struct S<T, decltype(T() ^ T())> { };
+template<class T> struct S<T, decltype(T() << T())> { };
+template<class T> struct S<T, decltype(T() >> T())> { };
+template<class T> struct S<T, decltype(T() && T())> { };
+template<class T> struct S<T, decltype(T() || T())> { };
+template<class T> struct S<T, decltype(T(), T())> { };
+
+template<class T> struct S<T, decltype(T() == T())> { };
+template<class T> struct S<T, decltype(T() != T())> { };
+template<class T> struct S<T, decltype(T() < T())> { };
+template<class T> struct S<T, decltype(T() > T())> { };
+template<class T> struct S<T, decltype(T() <= T())> { };
+template<class T> struct S<T, decltype(T() >= T())> { };
+#if __cplusplus > 201703L
+template<class T> struct S<T, decltype(T() <=> T())> { };
+#endif
+
+template<class T> struct S<T, decltype(T() += T())> { };
+template<class T> struct S<T, decltype(T() -= T())> { };
+template<class T> struct S<T, decltype(T() *= T())> { };
+template<class T> struct S<T, decltype(T() /= T())> { };
+template<class T> struct S<T, decltype(T() %= T())> { };
+template<class T> struct S<T, decltype(T() |= T())> { };
+template<class T> struct S<T, decltype(T() ^= T())> { };
+template<class T> struct S<T, decltype(T() <<= T())> { };
+template<class T> struct S<T, decltype(T() >>= T())> { };
+
+namespace N { struct A { }; }
+
+#include "operator-3-ops.h"
+
+static_assert(S<N::A>::is_primary, "");
diff --git a/gcc/testsuite/g++.dg/lookup/operator-7.C b/gcc/testsuite/g++.dg/lookup/operator-7.C
new file mode 100644
index 0000000..546fcb0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-7.C
@@ -0,0 +1,27 @@
+// PR c++/100465
+
+namespace N
+{
+ struct string
+ {
+ template<typename T>
+ void operator+=(T);
+ };
+
+ struct A {
+ void operator+=(char); // #1
+
+ template<typename T>
+ void f() {
+ string s;
+ s += T();
+ }
+
+ void g() {
+ f<char>();
+ }
+ };
+} // namespace N
+
+template<typename T>
+void operator+=(N::string, T);
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8.C b/gcc/testsuite/g++.dg/lookup/operator-8.C
new file mode 100644
index 0000000..64d8a97
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-8.C
@@ -0,0 +1,34 @@
+// Verify phase 1 lookup works properly for rewritten non-dependent conditional
+// operator expressions.
+
+// This test currently fails due to build_min_non_dep_op_overload not knowing
+// how to handle rewritten operator expressions; see the FIXME in build_new_op.
+
+// { dg-do compile { target c++20 } }
+
+#include <compare>
+
+struct A {
+ bool operator==(int);
+ std::strong_ordering operator<=>(int);
+};
+
+template<class T>
+void f() {
+ A a;
+ (void)(a != 0, 0 != a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+ (void)(a < 0, 0 < a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+ (void)(a <= 0, 0 <= a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+ (void)(a > 0, 0 > a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+ (void)(a >= 0, 0 >= a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+}
+
+// These later-declared namespace-scope overloads shouldn't be considered
+// when instantiating f<int>.
+bool operator!=(A, int) = delete;
+bool operator<(A, int) = delete;
+bool operator<=(A, int) = delete;
+bool operator>(A, int) = delete;
+bool operator>=(A, int) = delete;
+
+template void f<int>();
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
index ea6ee55..fccdce6 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;
}