Message ID | 1449783827-27797-1-git-send-email-patrick@parcs.ath.cx |
---|---|
State | New |
Headers | show |
On Thu, Dec 10, 2015 at 4:43 PM, Patrick Palka <patrick@parcs.ath.cx> wrote: > This patch fixes name-lookup of operators in template definitions whose > operands are non-dependent expressions, i.e. PR c++/21802 (and > incidentally 53223). > > The approach that this patch takes is to detect when build_new_op() > returns a call to an overloaded function and to store a call to this > overload intothe template AST instead of storing the raw operator > (an operator would be erroneously subject to overload resolution during > instantiation). > > The new function build_min_non_dep_op_overload is the workhorse of the > patch. It reconstructs the CALL_EXPR that would have been built had an > explicit operator+, operator* etc call been used, i.e. had the overload > gone through finish_call_expr() / build_new_method_call() instead of > through build_new_op(). The parameter OVERLOAD of this new function is > probably not strictly necessary -- one can probably just look at the > CALL_EXPR_FN of the parameter NON_DEP to figure out the overload to use > -- but since the requisite plumbing from build_new_op() already existed > to conveniently get at the overload information I thought I might as > well use it. > > I have also created a test case that hopefully exercises all the changes > that were made and to verify that these operator calls are being built > correctly. > > Does this approach seem adequate? Bootstrap and regtesting in progress > on x86_64, OK to commit if testing succeeds? Unfortunately this patch doesn't work properly on operator overloads that are defined as friend functions. E.g. the following now fails to compile: struct A { friend int operator* (A); }; template <typename T> void func(T t) { A x; int y = *x; } int main() { func(0); } I think this happens because KOENIG_LOOKUP_P is not being properly set in in the CALL_EXPR we are reconstructing. Not sure how to fix that yet. > > gcc/cp/ChangeLog: > > PR c++/21802 > PR c++/53223 > * cp-tree.h (build_min_non_dep_op_overload): Declare. > * tree.c (build_min_non_dep_op_overload): Define. > * typeck.c (build_x_indirect_ref): Use > build_min_non_dep_op_overload when the given expression > has been resolved to an operator overload. > (build_x_binary_op): Likewise. > (build_x_array_ref): Likewise. > (build_x_unary_op): Likewise. > (build_x_compound_expr): Likewise. > (build_x_modify_expr): Likewise. > > gcc/testsuite/ChangeLog: > > PR c++/21802 > PR c++/53223 > * g++.dg/cpp0x/pr53223.C: New test. > * g++.dg/lookup/pr21802.C: New test. > * g++.dg/lookup/two-stage4.C: Remove XFAIL. > --- > gcc/cp/cp-tree.h | 1 + > gcc/cp/tree.c | 64 ++++++++ > gcc/cp/typeck.c | 100 +++++++++--- > gcc/testsuite/g++.dg/cpp0x/pr53223.C | 35 ++++ > gcc/testsuite/g++.dg/lookup/pr21802.C | 271 +++++++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/lookup/two-stage4.C | 2 +- > 6 files changed, 453 insertions(+), 20 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr53223.C > create mode 100644 gcc/testsuite/g++.dg/lookup/pr21802.C > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 6190f4e..3487d77 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -6513,6 +6513,7 @@ extern tree build_min (enum tree_code, tree, ...); > extern tree build_min_nt_loc (location_t, enum tree_code, > ...); > extern tree build_min_non_dep (enum tree_code, tree, ...); > +extern tree build_min_non_dep_op_overload (enum tree_code, tree, tree, ...); > extern tree build_min_non_dep_call_vec (tree, tree, vec<tree, va_gc> *); > extern tree build_cplus_new (tree, tree, tsubst_flags_t); > extern tree build_aggr_init_expr (tree, tree); > diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c > index 5dad0a7..2635736 100644 > --- a/gcc/cp/tree.c > +++ b/gcc/cp/tree.c > @@ -2744,6 +2744,70 @@ build_min_non_dep_call_vec (tree non_dep, tree fn, vec<tree, va_gc> *argvec) > return convert_from_reference (t); > } > > +/* Similar to build_min_non_dep, but for expressions that have been resolved to > + a call to an operator overload. OP is the operator that has been > + overloaded. NON_DEP is the non-dependent expression that's been built, > + which should be a CALL_EXPR or an INDIRECT_REF to a CALL_EXPR. OVERLOAD is > + the overload that NON_DEP is calling. */ > + > +tree > +build_min_non_dep_op_overload (enum tree_code op, > + tree non_dep, > + tree overload, ...) > +{ > + va_list p; > + int nargs; > + tree fn, call; > + vec<tree, va_gc> *args; > + > + if (REFERENCE_REF_P (non_dep)) > + non_dep = TREE_OPERAND (non_dep, 0); > + > + nargs = call_expr_nargs (non_dep); > + > + if (op == PREINCREMENT_EXPR > + || op == PREDECREMENT_EXPR) > + gcc_assert (nargs == 1); > + else if (op == MODOP_EXPR) > + gcc_assert (nargs == 2); > + else > + gcc_assert (nargs == TREE_CODE_LENGTH (op)); > + > + args = make_tree_vector (); > + va_start (p, overload); > + > + if (TREE_CODE (TREE_TYPE (overload)) == FUNCTION_TYPE) > + { > + fn = overload; > + for (int i = 0; i < nargs; i++) > + { > + tree arg = va_arg (p, tree); > + vec_safe_push (args, arg); > + } > + } > + else if (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE) > + { > + tree object = va_arg (p, tree); > + tree binfo = TYPE_BINFO (TREE_TYPE (object)); > + tree method = build_baselink (binfo, binfo, overload, NULL_TREE); > + fn = build_min (COMPONENT_REF, TREE_TYPE (overload), > + object, method, NULL_TREE); > + for (int i = 1; i < nargs; i++) > + { > + tree arg = va_arg (p, tree); > + vec_safe_push (args, arg); > + } > + } > + else > + gcc_unreachable (); > + > + va_end (p); > + call = build_min_non_dep_call_vec (non_dep, fn, args); > + release_tree_vector (args); > + > + return call; > +} > + > tree > get_type_decl (tree t) > { > diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c > index 17671ee..2e5e46e 100644 > --- a/gcc/cp/typeck.c > +++ b/gcc/cp/typeck.c > @@ -2905,6 +2905,7 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, > { > tree orig_expr = expr; > tree rval; > + tree overload = NULL_TREE; > > if (processing_template_decl) > { > @@ -2917,12 +2918,18 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, > } > > rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr, > - NULL_TREE, NULL_TREE, /*overload=*/NULL, complain); > + NULL_TREE, NULL_TREE, &overload, complain); > if (!rval) > rval = cp_build_indirect_ref (expr, errorstring, complain); > > if (processing_template_decl && rval != error_mark_node) > - return build_min_non_dep (INDIRECT_REF, rval, orig_expr); > + { > + if (overload != NULL_TREE) > + return (build_min_non_dep_op_overload > + (INDIRECT_REF, rval, overload, orig_expr)); > + > + return build_min_non_dep (INDIRECT_REF, rval, orig_expr); > + } > else > return rval; > } > @@ -3814,12 +3821,13 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl, > tree > build_x_binary_op (location_t loc, enum tree_code code, tree arg1, > enum tree_code arg1_code, tree arg2, > - enum tree_code arg2_code, tree *overload, > + enum tree_code arg2_code, tree *overload_p, > tsubst_flags_t complain) > { > tree orig_arg1; > tree orig_arg2; > tree expr; > + tree overload = NULL_TREE; > > orig_arg1 = arg1; > orig_arg2 = arg2; > @@ -3837,7 +3845,10 @@ build_x_binary_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); > + &overload, complain); > + > + if (overload_p != NULL) > + *overload_p = overload; > > /* Check for cases such as x+y<<z which users are likely to > misinterpret. But don't warn about obj << x + y, since that is a > @@ -3853,7 +3864,13 @@ build_x_binary_op (location_t loc, enum tree_code code, tree arg1, > arg2_code, orig_arg2); > > if (processing_template_decl && expr != error_mark_node) > - return build_min_non_dep (code, expr, orig_arg1, orig_arg2); > + { > + if (overload != NULL_TREE) > + return (build_min_non_dep_op_overload > + (code, expr, overload, orig_arg1, orig_arg2)); > + > + return build_min_non_dep (code, expr, orig_arg1, orig_arg2); > + } > > return expr; > } > @@ -3867,6 +3884,7 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2, > tree orig_arg1 = arg1; > tree orig_arg2 = arg2; > tree expr; > + tree overload = NULL_TREE; > > if (processing_template_decl) > { > @@ -3879,11 +3897,17 @@ 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=*/NULL, complain); > + NULL_TREE, &overload, complain); > > if (processing_template_decl && expr != error_mark_node) > - return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2, > - NULL_TREE, NULL_TREE); > + { > + if (overload != NULL_TREE) > + return (build_min_non_dep_op_overload > + (ARRAY_REF, expr, overload, orig_arg1, orig_arg2)); > + > + return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2, > + NULL_TREE, NULL_TREE); > + } > return expr; > } > > @@ -5278,6 +5302,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, > tree orig_expr = xarg; > tree exp; > int ptrmem = 0; > + tree overload = NULL_TREE; > > if (processing_template_decl) > { > @@ -5305,7 +5330,8 @@ 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=*/NULL, complain); > + NULL_TREE, &overload, complain); > + > if (!exp && code == ADDR_EXPR) > { > if (is_overloaded_fn (xarg)) > @@ -5371,8 +5397,14 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, > } > > if (processing_template_decl && exp != error_mark_node) > - exp = build_min_non_dep (code, exp, orig_expr, > - /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE); > + { > + if (overload != NULL_TREE) > + return (build_min_non_dep_op_overload > + (code, exp, overload, orig_expr, integer_zero_node)); > + > + exp = build_min_non_dep (code, exp, orig_expr, > + /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE); > + } > if (TREE_CODE (exp) == ADDR_EXPR) > PTRMEM_OK_P (exp) = ptrmem; > return exp; > @@ -6335,6 +6367,7 @@ build_x_compound_expr (location_t loc, tree op1, tree op2, > tree result; > tree orig_op1 = op1; > tree orig_op2 = op2; > + tree overload = NULL_TREE; > > if (processing_template_decl) > { > @@ -6346,12 +6379,18 @@ 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=*/NULL, complain); > + NULL_TREE, &overload, complain); > if (!result) > result = cp_build_compound_expr (op1, op2, complain); > > if (processing_template_decl && result != error_mark_node) > - return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2); > + { > + if (overload != NULL_TREE) > + return (build_min_non_dep_op_overload > + (COMPOUND_EXPR, result, overload, orig_op1, orig_op2)); > + > + return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2); > + } > > return result; > } > @@ -7794,19 +7833,42 @@ cp_expr > build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > tree rhs, tsubst_flags_t complain) > { > + tree orig_lhs = lhs; > + tree orig_rhs = rhs; > + tree overload = NULL_TREE; > + tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); > + > if (processing_template_decl) > - return build_min_nt_loc (loc, MODOP_EXPR, lhs, > - build_min_nt_loc (loc, modifycode, NULL_TREE, > - NULL_TREE), rhs); > + { > + if (modifycode == NOP_EXPR > + || type_dependent_expression_p (lhs) > + || type_dependent_expression_p (rhs)) > + return build_min_nt_loc (loc, MODOP_EXPR, lhs, > + build_min_nt_loc (loc, modifycode, NULL_TREE, > + NULL_TREE), rhs); > + > + lhs = build_non_dependent_expr (lhs); > + rhs = build_non_dependent_expr (rhs); > + } > > if (modifycode != NOP_EXPR) > { > - tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, > - make_node (modifycode), /*overload=*/NULL, > - complain); > + tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, > + lhs, rhs, op, &overload, complain); > if (rval) > { > + if (rval == error_mark_node) > + return rval; > TREE_NO_WARNING (rval) = 1; > + if (processing_template_decl) > + { > + if (overload != NULL_TREE) > + return (build_min_non_dep_op_overload > + (MODOP_EXPR, rval, overload, orig_lhs, orig_rhs)); > + > + return (build_min_non_dep > + (MODOP_EXPR, rval, orig_lhs, op, orig_rhs)); > + } > return rval; > } > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53223.C b/gcc/testsuite/g++.dg/cpp0x/pr53223.C > new file mode 100644 > index 0000000..4ca2da1 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/pr53223.C > @@ -0,0 +1,35 @@ > +// PR c++/53223 > +// { dg-do compile { target c++11 } } > + > +struct A > +{ > + int good() const; > + int operator *() const; > + int operator ++() const; > +}; > + > +int operator-- (const A&); > + > +template<typename T> > +void func(T t) > +{ > + A x; > + auto &&g1 = x.good(); > + auto &&g2 = x.operator*(); > + auto &&error1 = *x; // { dg-bogus "invalid initialization" } > + auto &&error2 = ++x; // { dg-bogus "invalid initialization" } > + auto &&error3 = --x; // { dg-bogus "invalid initialization" } > +} > + > +void func2(int) > +{ > + A x; > + auto &&g = *x; > +} > + > +int main() > +{ > + func(0); > + func2(0); > +} > + > diff --git a/gcc/testsuite/g++.dg/lookup/pr21802.C b/gcc/testsuite/g++.dg/lookup/pr21802.C > new file mode 100644 > index 0000000..4909bad > --- /dev/null > +++ b/gcc/testsuite/g++.dg/lookup/pr21802.C > @@ -0,0 +1,271 @@ > +// PR c++/21802 > +// { dg-do run } > +#include <cassert> > + > +struct X; > +int I = 6; > + > +/* A mostly exhaustive and ad-hoc assortment of operator overloads and calls > + thereof, to stress-test two-stage name lookup of operators inside template > + definitions and then to verify that the calls get built correctly. */ > + > +inline int operator+(const X &, int x) { return x; } > +inline int operator-(const X &, int x) { return x; } > +inline int operator*(const X &, int x) { return x; } > +inline int operator/(const X &, int x) { return x; } > +inline int operator+=(const X &, int x) { return x; } > + > +struct X > +{ > + X () : m (1) { } > + int operator%(int x) { return m + x; } > + virtual int operator>>(int x) { return m + x; } > + int operator<<(int x) { return m + x; } > + int operator&(int x) { return m + x; } > + int operator|(int x) { return m + x; } > + int operator^(int x) { return m + x; } > + int operator&&(int x) { return m + x; } > + int operator||(int x) { return m + x; } > + int operator==(int x) { return m + x; } > + int operator!=(int x) { return m + x; } > + int operator<(int x) { return m + x; } > + int operator<=(int x) { return m + x; } > + int operator>(int x) { return m + x; } > + int operator>=(int x) { return m + x; } > + int operator*() { return m + I; } > + int operator!() { return m + I; } > + int operator~() { return m + I; } > + int operator++() { return m + I + 100; } > + int operator--() { return m + I + 100; } > + int operator++(int) { return m + I; } > + int operator--(int) { return m + I; } > + int operator()() { return m + I; } > + int operator,(int x) { return m + x; } > + int operator[](int x) { return m + x; } > + int operator*=(int x) { return m + x; } > + int operator-=(int x) { return m + x; } > + int operator/=(int x) { return m + x; } > + virtual int operator& () { return m + I; } > + int m; > +}; > +struct Y : virtual X > +{ > + /* Virtual override. */ > + int operator>>(int x) { return m + x + 1; } > + int operator& () { return m + I + 1; } > + > + /* Not virtual. */ > + int operator&(int x) { return m + x + 1; } > +}; > + > +/* The folloiwng "FooN" functions each contain a different way to call and to > + resolve these operator overloads. */ > + > +template <typename T> > +void > +Foo1 (T) > +{ > + Y x; > + { int t = x + I; assert (t == 6); } > + { int t = x - I; assert (t == 6); } > + { int t = x * I; assert (t == 6); } > + { int t = x / I; assert (t == 6); } > + { int t = (x+=I); assert (t == 6); } > + > + { int t = x % I; assert (t == 7); } > + { int t = x << I; assert (t == 7); } > + { int t = x | I; assert (t == 7); } > + { int t = x && I; assert (t == 7); } > + { int t = x || I; assert (t == 7); } > + { int t = x == I; assert (t == 7); } > + { int t = x != I; assert (t == 7); } > + { int t = x < I; assert (t == 7); } > + { int t = x <= I; assert (t == 7); } > + { int t = x > I; assert (t == 7); } > + { int t = x >= I; assert (t == 7); } > + { int t = *x; assert (t == 7); } > + { int t = !x; assert (t == 7); } > + { int t = ~x; assert (t == 7); } > + { int t = x++; assert (t == 7); } > + { int t = x--; assert (t == 7); } > + { int t = ++x; assert (t == 107); } > + { int t = --x; assert (t == 107); } > + { int t = x (); assert (t == 7); } > + { int t = (x, I); assert (t == 7); } > + { int t = x[I]; assert (t == 7); } > + { int t = (x-=I); assert (t == 7); } > + { int t = (x/=I); assert (t == 7); } > + { int t = (x*=I); assert (t == 7); } > + > + { int t = x >> I; assert (t == 8); } > + { int t = x & I; assert (t == 8); } > + { int t = &x; assert (t == 8); } > +} > + > +template <typename T> > +void > +Foo2 (T) > +{ > + X x; > + { int t = x + I; assert (t == 6); } > + { int t = x - I; assert (t == 6); } > + { int t = x * I; assert (t == 6); } > + { int t = x / I; assert (t == 6); } > + { int t = (x+=I); assert (t == 6); } > + > + { int t = x % I; assert (t == 7); } > + { int t = x >> I; assert (t == 7); } > + { int t = x << I; assert (t == 7); } > + { int t = x | I; assert (t == 7); } > + { int t = x && I; assert (t == 7); } > + { int t = x || I; assert (t == 7); } > + { int t = x == I; assert (t == 7); } > + { int t = x != I; assert (t == 7); } > + { int t = x < I; assert (t == 7); } > + { int t = x <= I; assert (t == 7); } > + { int t = x > I; assert (t == 7); } > + { int t = x >= I; assert (t == 7); } > + { int t = *x; assert (t == 7); } > + { int t = !x; assert (t == 7); } > + { int t = ~x; assert (t == 7); } > + { int t = x++; assert (t == 7); } > + { int t = x--; assert (t == 7); } > + { int t = ++x; assert (t == 107); } > + { int t = --x; assert (t == 107); } > + { int t = x (); assert (t == 7); } > + { int t = (x, I); assert (t == 7); } > + { int t = x[I]; assert (t == 7); } > + { int t = &x; assert (t == 7); } > + { int t = (x-=I); assert (t == 7); } > + { int t = (x/=I); assert (t == 7); } > + { int t = (x*=I); assert (t == 7); } > + { int t = x & I; assert (t == 7); } > +} > + > +template <typename T> > +void > +Foo3 (T) > +{ > + Y o; > + X &x = o; > + { int t = x + I; assert (t == 6); } > + { int t = x - I; assert (t == 6); } > + { int t = x * I; assert (t == 6); } > + { int t = x / I; assert (t == 6); } > + { int t = (x+=I); assert (t == 6); } > + > + { int t = x % I; assert (t == 7); } > + { int t = x << I; assert (t == 7); } > + { int t = x | I; assert (t == 7); } > + { int t = x && I; assert (t == 7); } > + { int t = x || I; assert (t == 7); } > + { int t = x == I; assert (t == 7); } > + { int t = x != I; assert (t == 7); } > + { int t = x < I; assert (t == 7); } > + { int t = x <= I; assert (t == 7); } > + { int t = x > I; assert (t == 7); } > + { int t = x >= I; assert (t == 7); } > + { int t = *x; assert (t == 7); } > + { int t = !x; assert (t == 7); } > + { int t = ~x; assert (t == 7); } > + { int t = x++; assert (t == 7); } > + { int t = x--; assert (t == 7); } > + { int t = ++x; assert (t == 107); } > + { int t = --x; assert (t == 107); } > + { int t = x (); assert (t == 7); } > + { int t = (x, I); assert (t == 7); } > + { int t = x[I]; assert (t == 7); } > + { int t = (x-=I); assert (t == 7); } > + { int t = (x/=I); assert (t == 7); } > + { int t = (x*=I); assert (t == 7); } > + > + { int t = x & I; assert (t == 7); } > + { int t = x >> I; assert (t == 8); } > + { int t = &x; assert (t == 8); } > +} > + > +template <typename T> > +void > +Foo4 (T) > +{ > + Y x; > + { int t = operator+ (x, I); assert (t == 6); } > + { int t = operator- (x, I); assert (t == 6); } > + { int t = operator* (x, I); assert (t == 6); } > + { int t = operator/ (x, I); assert (t == 6); } > + { int t = operator+= (x, I); assert (t == 6); } > + > + { int t = x.operator% (I); assert (t == 7); } > + { int t = x.operator<< (I); assert (t == 7); } > + { int t = x.operator| (I); assert (t == 7); } > + { int t = x.operator&& (I); assert (t == 7); } > + { int t = x.operator|| (I); assert (t == 7); } > + { int t = x.operator== (I); assert (t == 7); } > + { int t = x.operator!= (I); assert (t == 7); } > + { int t = x.operator< (I); assert (t == 7); } > + { int t = x.operator<= (I); assert (t == 7); } > + { int t = x.operator> (I); assert (t == 7); } > + { int t = x.operator>= (I); assert (t == 7); } > + { int t = x.operator* (); assert (t == 7); } > + { int t = x.operator! (); assert (t == 7); } > + { int t = x.operator~ (); assert (t == 7); } > + { int t = x.operator++ (0); assert (t == 7); } > + { int t = x.operator-- (0); assert (t == 7); } > + { int t = x.operator++ (); assert (t == 107); } > + { int t = x.operator-- (); assert (t == 107); } > + { int t = x.operator() (); assert (t == 7); } > + { int t = x.operator, (I); assert (t == 7); } > + { int t = x.operator[] (I); assert (t == 7); } > + { int t = x.operator-= (I); assert (t == 7); } > + { int t = x.operator/= (I); assert (t == 7); } > + { int t = x.operator*= (I); assert (t == 7); } > + > + { int t = x.operator>> (I); assert (t == 8); } > + { int t = x.operator& (); assert (t == 8); } > + { int t = x.operator& (I); assert (t == 8); } > +} > + > + > +/* These definitions should be irrelevant to operator lookup of non-dependent > + expressions inside the above templates since they are not in scope at > + template-definition time (but are in scope at instantiation time). */ > +inline int operator+(const Y&, int) { return 11; } > +inline int operator-(const Y&, int) { return 11; } > +inline int operator*(const Y&, int) { return 11; } > +inline int operator/(const Y&, int) { return 11; } > +inline int operator%(const Y&, int) { return 11; } > +inline int operator>>(const Y&, int) { return 11; } > +inline int operator<<(const Y&, int) { return 11; } > +inline int operator&(const Y&, int) { return 11; } > +inline int operator|(const Y&, int) { return 11; } > +inline int operator^(const Y&, int) { return 11; } > +inline int operator&&(const Y&, int) { return 11; } > +inline int operator||(const Y&, int) { return 11; } > +inline int operator==(const Y&, int) { return 11; } > +inline int operator!=(const Y&, int) { return 11; } > +inline int operator<(const Y&, int) { return 11; } > +inline int operator<=(const Y&, int) { return 11; } > +inline int operator>(const Y&, int) { return 11; } > +inline int operator>=(const Y&, int) { return 11; } > +inline int operator*(const Y&) { return 11; } > +inline int operator!(const Y&) { return 11; } > +inline int operator~(const Y&) { return 11; } > +inline int operator++(const Y&) { return 11; } > +inline int operator--(const Y&) { return 11; } > +inline int operator++(const Y&, int) { return 11; } > +inline int operator--(const Y&, int) { return 11; } > +inline int operator,(const Y&, int) { return 11; } > +inline int operator&(const Y&) { return 11; } > +inline int operator+=(const Y&, int x) { return 11; } > +inline int operator*=(const Y&, int x) { return 11; } > +inline int operator-=(const Y&, int x) { return 11; } > +inline int operator/=(const Y&, int x) { return 11; } > + > +int > +main () > +{ > + Foo1 (0); > + Foo2 (0); > + Foo3 (0); > + Foo4 (0); > +} > diff --git a/gcc/testsuite/g++.dg/lookup/two-stage4.C b/gcc/testsuite/g++.dg/lookup/two-stage4.C > index 7d97109..a89e618 100644 > --- a/gcc/testsuite/g++.dg/lookup/two-stage4.C > +++ b/gcc/testsuite/g++.dg/lookup/two-stage4.C > @@ -8,7 +8,7 @@ template<typename T> bool operator==(wrap<T>, wrap<T>); > template<typename T> > void g(T, wrap<wrap<int> > x) > { > - bool b = x == x; // { dg-bogus "" "" { xfail *-*-* } } > + bool b = x == x; // { dg-bogus "" "" } > } > > template<typename T> void operator==(wrap<wrap<T> >, wrap<wrap<T> >); > -- > 2.6.4.491.gda30757.dirty >
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6190f4e..3487d77 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6513,6 +6513,7 @@ extern tree build_min (enum tree_code, tree, ...); extern tree build_min_nt_loc (location_t, enum tree_code, ...); extern tree build_min_non_dep (enum tree_code, tree, ...); +extern tree build_min_non_dep_op_overload (enum tree_code, tree, tree, ...); extern tree build_min_non_dep_call_vec (tree, tree, vec<tree, va_gc> *); extern tree build_cplus_new (tree, tree, tsubst_flags_t); extern tree build_aggr_init_expr (tree, tree); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5dad0a7..2635736 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2744,6 +2744,70 @@ build_min_non_dep_call_vec (tree non_dep, tree fn, vec<tree, va_gc> *argvec) return convert_from_reference (t); } +/* Similar to build_min_non_dep, but for expressions that have been resolved to + a call to an operator overload. OP is the operator that has been + overloaded. NON_DEP is the non-dependent expression that's been built, + which should be a CALL_EXPR or an INDIRECT_REF to a CALL_EXPR. OVERLOAD is + the overload that NON_DEP is calling. */ + +tree +build_min_non_dep_op_overload (enum tree_code op, + tree non_dep, + tree overload, ...) +{ + va_list p; + int nargs; + tree fn, call; + vec<tree, va_gc> *args; + + if (REFERENCE_REF_P (non_dep)) + non_dep = TREE_OPERAND (non_dep, 0); + + nargs = call_expr_nargs (non_dep); + + if (op == PREINCREMENT_EXPR + || op == PREDECREMENT_EXPR) + gcc_assert (nargs == 1); + else if (op == MODOP_EXPR) + gcc_assert (nargs == 2); + else + gcc_assert (nargs == TREE_CODE_LENGTH (op)); + + args = make_tree_vector (); + va_start (p, overload); + + if (TREE_CODE (TREE_TYPE (overload)) == FUNCTION_TYPE) + { + fn = overload; + for (int i = 0; i < nargs; i++) + { + tree arg = va_arg (p, tree); + vec_safe_push (args, arg); + } + } + else if (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE) + { + tree object = va_arg (p, tree); + tree binfo = TYPE_BINFO (TREE_TYPE (object)); + tree method = build_baselink (binfo, binfo, overload, NULL_TREE); + fn = build_min (COMPONENT_REF, TREE_TYPE (overload), + object, method, NULL_TREE); + for (int i = 1; i < nargs; i++) + { + tree arg = va_arg (p, tree); + vec_safe_push (args, arg); + } + } + else + gcc_unreachable (); + + va_end (p); + call = build_min_non_dep_call_vec (non_dep, fn, args); + release_tree_vector (args); + + return call; +} + tree get_type_decl (tree t) { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 17671ee..2e5e46e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2905,6 +2905,7 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, { tree orig_expr = expr; tree rval; + tree overload = NULL_TREE; if (processing_template_decl) { @@ -2917,12 +2918,18 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring, } rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr, - NULL_TREE, NULL_TREE, /*overload=*/NULL, complain); + NULL_TREE, NULL_TREE, &overload, complain); if (!rval) rval = cp_build_indirect_ref (expr, errorstring, complain); if (processing_template_decl && rval != error_mark_node) - return build_min_non_dep (INDIRECT_REF, rval, orig_expr); + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (INDIRECT_REF, rval, overload, orig_expr)); + + return build_min_non_dep (INDIRECT_REF, rval, orig_expr); + } else return rval; } @@ -3814,12 +3821,13 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl, tree build_x_binary_op (location_t loc, enum tree_code code, tree arg1, enum tree_code arg1_code, tree arg2, - enum tree_code arg2_code, tree *overload, + enum tree_code arg2_code, tree *overload_p, tsubst_flags_t complain) { tree orig_arg1; tree orig_arg2; tree expr; + tree overload = NULL_TREE; orig_arg1 = arg1; orig_arg2 = arg2; @@ -3837,7 +3845,10 @@ build_x_binary_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); + &overload, complain); + + if (overload_p != NULL) + *overload_p = overload; /* Check for cases such as x+y<<z which users are likely to misinterpret. But don't warn about obj << x + y, since that is a @@ -3853,7 +3864,13 @@ build_x_binary_op (location_t loc, enum tree_code code, tree arg1, arg2_code, orig_arg2); if (processing_template_decl && expr != error_mark_node) - return build_min_non_dep (code, expr, orig_arg1, orig_arg2); + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (code, expr, overload, orig_arg1, orig_arg2)); + + return build_min_non_dep (code, expr, orig_arg1, orig_arg2); + } return expr; } @@ -3867,6 +3884,7 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2, tree orig_arg1 = arg1; tree orig_arg2 = arg2; tree expr; + tree overload = NULL_TREE; if (processing_template_decl) { @@ -3879,11 +3897,17 @@ 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=*/NULL, complain); + NULL_TREE, &overload, complain); if (processing_template_decl && expr != error_mark_node) - return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2, - NULL_TREE, NULL_TREE); + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (ARRAY_REF, expr, overload, orig_arg1, orig_arg2)); + + return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2, + NULL_TREE, NULL_TREE); + } return expr; } @@ -5278,6 +5302,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, tree orig_expr = xarg; tree exp; int ptrmem = 0; + tree overload = NULL_TREE; if (processing_template_decl) { @@ -5305,7 +5330,8 @@ 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=*/NULL, complain); + NULL_TREE, &overload, complain); + if (!exp && code == ADDR_EXPR) { if (is_overloaded_fn (xarg)) @@ -5371,8 +5397,14 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg, } if (processing_template_decl && exp != error_mark_node) - exp = build_min_non_dep (code, exp, orig_expr, - /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE); + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (code, exp, overload, orig_expr, integer_zero_node)); + + exp = build_min_non_dep (code, exp, orig_expr, + /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE); + } if (TREE_CODE (exp) == ADDR_EXPR) PTRMEM_OK_P (exp) = ptrmem; return exp; @@ -6335,6 +6367,7 @@ build_x_compound_expr (location_t loc, tree op1, tree op2, tree result; tree orig_op1 = op1; tree orig_op2 = op2; + tree overload = NULL_TREE; if (processing_template_decl) { @@ -6346,12 +6379,18 @@ 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=*/NULL, complain); + NULL_TREE, &overload, complain); if (!result) result = cp_build_compound_expr (op1, op2, complain); if (processing_template_decl && result != error_mark_node) - return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2); + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (COMPOUND_EXPR, result, overload, orig_op1, orig_op2)); + + return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2); + } return result; } @@ -7794,19 +7833,42 @@ cp_expr build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, tree rhs, tsubst_flags_t complain) { + tree orig_lhs = lhs; + tree orig_rhs = rhs; + tree overload = NULL_TREE; + tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); + if (processing_template_decl) - return build_min_nt_loc (loc, MODOP_EXPR, lhs, - build_min_nt_loc (loc, modifycode, NULL_TREE, - NULL_TREE), rhs); + { + if (modifycode == NOP_EXPR + || type_dependent_expression_p (lhs) + || type_dependent_expression_p (rhs)) + return build_min_nt_loc (loc, MODOP_EXPR, lhs, + build_min_nt_loc (loc, modifycode, NULL_TREE, + NULL_TREE), rhs); + + lhs = build_non_dependent_expr (lhs); + rhs = build_non_dependent_expr (rhs); + } if (modifycode != NOP_EXPR) { - tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, - make_node (modifycode), /*overload=*/NULL, - complain); + tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, + lhs, rhs, op, &overload, complain); if (rval) { + if (rval == error_mark_node) + return rval; TREE_NO_WARNING (rval) = 1; + if (processing_template_decl) + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (MODOP_EXPR, rval, overload, orig_lhs, orig_rhs)); + + return (build_min_non_dep + (MODOP_EXPR, rval, orig_lhs, op, orig_rhs)); + } return rval; } } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53223.C b/gcc/testsuite/g++.dg/cpp0x/pr53223.C new file mode 100644 index 0000000..4ca2da1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr53223.C @@ -0,0 +1,35 @@ +// PR c++/53223 +// { dg-do compile { target c++11 } } + +struct A +{ + int good() const; + int operator *() const; + int operator ++() const; +}; + +int operator-- (const A&); + +template<typename T> +void func(T t) +{ + A x; + auto &&g1 = x.good(); + auto &&g2 = x.operator*(); + auto &&error1 = *x; // { dg-bogus "invalid initialization" } + auto &&error2 = ++x; // { dg-bogus "invalid initialization" } + auto &&error3 = --x; // { dg-bogus "invalid initialization" } +} + +void func2(int) +{ + A x; + auto &&g = *x; +} + +int main() +{ + func(0); + func2(0); +} + diff --git a/gcc/testsuite/g++.dg/lookup/pr21802.C b/gcc/testsuite/g++.dg/lookup/pr21802.C new file mode 100644 index 0000000..4909bad --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/pr21802.C @@ -0,0 +1,271 @@ +// PR c++/21802 +// { dg-do run } +#include <cassert> + +struct X; +int I = 6; + +/* A mostly exhaustive and ad-hoc assortment of operator overloads and calls + thereof, to stress-test two-stage name lookup of operators inside template + definitions and then to verify that the calls get built correctly. */ + +inline int operator+(const X &, int x) { return x; } +inline int operator-(const X &, int x) { return x; } +inline int operator*(const X &, int x) { return x; } +inline int operator/(const X &, int x) { return x; } +inline int operator+=(const X &, int x) { return x; } + +struct X +{ + X () : m (1) { } + int operator%(int x) { return m + x; } + virtual int operator>>(int x) { return m + x; } + int operator<<(int x) { return m + x; } + int operator&(int x) { return m + x; } + int operator|(int x) { return m + x; } + int operator^(int x) { return m + x; } + int operator&&(int x) { return m + x; } + int operator||(int x) { return m + x; } + int operator==(int x) { return m + x; } + int operator!=(int x) { return m + x; } + int operator<(int x) { return m + x; } + int operator<=(int x) { return m + x; } + int operator>(int x) { return m + x; } + int operator>=(int x) { return m + x; } + int operator*() { return m + I; } + int operator!() { return m + I; } + int operator~() { return m + I; } + int operator++() { return m + I + 100; } + int operator--() { return m + I + 100; } + int operator++(int) { return m + I; } + int operator--(int) { return m + I; } + int operator()() { return m + I; } + int operator,(int x) { return m + x; } + int operator[](int x) { return m + x; } + int operator*=(int x) { return m + x; } + int operator-=(int x) { return m + x; } + int operator/=(int x) { return m + x; } + virtual int operator& () { return m + I; } + int m; +}; +struct Y : virtual X +{ + /* Virtual override. */ + int operator>>(int x) { return m + x + 1; } + int operator& () { return m + I + 1; } + + /* Not virtual. */ + int operator&(int x) { return m + x + 1; } +}; + +/* The folloiwng "FooN" functions each contain a different way to call and to + resolve these operator overloads. */ + +template <typename T> +void +Foo1 (T) +{ + Y x; + { int t = x + I; assert (t == 6); } + { int t = x - I; assert (t == 6); } + { int t = x * I; assert (t == 6); } + { int t = x / I; assert (t == 6); } + { int t = (x+=I); assert (t == 6); } + + { int t = x % I; assert (t == 7); } + { int t = x << I; assert (t == 7); } + { int t = x | I; assert (t == 7); } + { int t = x && I; assert (t == 7); } + { int t = x || I; assert (t == 7); } + { int t = x == I; assert (t == 7); } + { int t = x != I; assert (t == 7); } + { int t = x < I; assert (t == 7); } + { int t = x <= I; assert (t == 7); } + { int t = x > I; assert (t == 7); } + { int t = x >= I; assert (t == 7); } + { int t = *x; assert (t == 7); } + { int t = !x; assert (t == 7); } + { int t = ~x; assert (t == 7); } + { int t = x++; assert (t == 7); } + { int t = x--; assert (t == 7); } + { int t = ++x; assert (t == 107); } + { int t = --x; assert (t == 107); } + { int t = x (); assert (t == 7); } + { int t = (x, I); assert (t == 7); } + { int t = x[I]; assert (t == 7); } + { int t = (x-=I); assert (t == 7); } + { int t = (x/=I); assert (t == 7); } + { int t = (x*=I); assert (t == 7); } + + { int t = x >> I; assert (t == 8); } + { int t = x & I; assert (t == 8); } + { int t = &x; assert (t == 8); } +} + +template <typename T> +void +Foo2 (T) +{ + X x; + { int t = x + I; assert (t == 6); } + { int t = x - I; assert (t == 6); } + { int t = x * I; assert (t == 6); } + { int t = x / I; assert (t == 6); } + { int t = (x+=I); assert (t == 6); } + + { int t = x % I; assert (t == 7); } + { int t = x >> I; assert (t == 7); } + { int t = x << I; assert (t == 7); } + { int t = x | I; assert (t == 7); } + { int t = x && I; assert (t == 7); } + { int t = x || I; assert (t == 7); } + { int t = x == I; assert (t == 7); } + { int t = x != I; assert (t == 7); } + { int t = x < I; assert (t == 7); } + { int t = x <= I; assert (t == 7); } + { int t = x > I; assert (t == 7); } + { int t = x >= I; assert (t == 7); } + { int t = *x; assert (t == 7); } + { int t = !x; assert (t == 7); } + { int t = ~x; assert (t == 7); } + { int t = x++; assert (t == 7); } + { int t = x--; assert (t == 7); } + { int t = ++x; assert (t == 107); } + { int t = --x; assert (t == 107); } + { int t = x (); assert (t == 7); } + { int t = (x, I); assert (t == 7); } + { int t = x[I]; assert (t == 7); } + { int t = &x; assert (t == 7); } + { int t = (x-=I); assert (t == 7); } + { int t = (x/=I); assert (t == 7); } + { int t = (x*=I); assert (t == 7); } + { int t = x & I; assert (t == 7); } +} + +template <typename T> +void +Foo3 (T) +{ + Y o; + X &x = o; + { int t = x + I; assert (t == 6); } + { int t = x - I; assert (t == 6); } + { int t = x * I; assert (t == 6); } + { int t = x / I; assert (t == 6); } + { int t = (x+=I); assert (t == 6); } + + { int t = x % I; assert (t == 7); } + { int t = x << I; assert (t == 7); } + { int t = x | I; assert (t == 7); } + { int t = x && I; assert (t == 7); } + { int t = x || I; assert (t == 7); } + { int t = x == I; assert (t == 7); } + { int t = x != I; assert (t == 7); } + { int t = x < I; assert (t == 7); } + { int t = x <= I; assert (t == 7); } + { int t = x > I; assert (t == 7); } + { int t = x >= I; assert (t == 7); } + { int t = *x; assert (t == 7); } + { int t = !x; assert (t == 7); } + { int t = ~x; assert (t == 7); } + { int t = x++; assert (t == 7); } + { int t = x--; assert (t == 7); } + { int t = ++x; assert (t == 107); } + { int t = --x; assert (t == 107); } + { int t = x (); assert (t == 7); } + { int t = (x, I); assert (t == 7); } + { int t = x[I]; assert (t == 7); } + { int t = (x-=I); assert (t == 7); } + { int t = (x/=I); assert (t == 7); } + { int t = (x*=I); assert (t == 7); } + + { int t = x & I; assert (t == 7); } + { int t = x >> I; assert (t == 8); } + { int t = &x; assert (t == 8); } +} + +template <typename T> +void +Foo4 (T) +{ + Y x; + { int t = operator+ (x, I); assert (t == 6); } + { int t = operator- (x, I); assert (t == 6); } + { int t = operator* (x, I); assert (t == 6); } + { int t = operator/ (x, I); assert (t == 6); } + { int t = operator+= (x, I); assert (t == 6); } + + { int t = x.operator% (I); assert (t == 7); } + { int t = x.operator<< (I); assert (t == 7); } + { int t = x.operator| (I); assert (t == 7); } + { int t = x.operator&& (I); assert (t == 7); } + { int t = x.operator|| (I); assert (t == 7); } + { int t = x.operator== (I); assert (t == 7); } + { int t = x.operator!= (I); assert (t == 7); } + { int t = x.operator< (I); assert (t == 7); } + { int t = x.operator<= (I); assert (t == 7); } + { int t = x.operator> (I); assert (t == 7); } + { int t = x.operator>= (I); assert (t == 7); } + { int t = x.operator* (); assert (t == 7); } + { int t = x.operator! (); assert (t == 7); } + { int t = x.operator~ (); assert (t == 7); } + { int t = x.operator++ (0); assert (t == 7); } + { int t = x.operator-- (0); assert (t == 7); } + { int t = x.operator++ (); assert (t == 107); } + { int t = x.operator-- (); assert (t == 107); } + { int t = x.operator() (); assert (t == 7); } + { int t = x.operator, (I); assert (t == 7); } + { int t = x.operator[] (I); assert (t == 7); } + { int t = x.operator-= (I); assert (t == 7); } + { int t = x.operator/= (I); assert (t == 7); } + { int t = x.operator*= (I); assert (t == 7); } + + { int t = x.operator>> (I); assert (t == 8); } + { int t = x.operator& (); assert (t == 8); } + { int t = x.operator& (I); assert (t == 8); } +} + + +/* These definitions should be irrelevant to operator lookup of non-dependent + expressions inside the above templates since they are not in scope at + template-definition time (but are in scope at instantiation time). */ +inline int operator+(const Y&, int) { return 11; } +inline int operator-(const Y&, int) { return 11; } +inline int operator*(const Y&, int) { return 11; } +inline int operator/(const Y&, int) { return 11; } +inline int operator%(const Y&, int) { return 11; } +inline int operator>>(const Y&, int) { return 11; } +inline int operator<<(const Y&, int) { return 11; } +inline int operator&(const Y&, int) { return 11; } +inline int operator|(const Y&, int) { return 11; } +inline int operator^(const Y&, int) { return 11; } +inline int operator&&(const Y&, int) { return 11; } +inline int operator||(const Y&, int) { return 11; } +inline int operator==(const Y&, int) { return 11; } +inline int operator!=(const Y&, int) { return 11; } +inline int operator<(const Y&, int) { return 11; } +inline int operator<=(const Y&, int) { return 11; } +inline int operator>(const Y&, int) { return 11; } +inline int operator>=(const Y&, int) { return 11; } +inline int operator*(const Y&) { return 11; } +inline int operator!(const Y&) { return 11; } +inline int operator~(const Y&) { return 11; } +inline int operator++(const Y&) { return 11; } +inline int operator--(const Y&) { return 11; } +inline int operator++(const Y&, int) { return 11; } +inline int operator--(const Y&, int) { return 11; } +inline int operator,(const Y&, int) { return 11; } +inline int operator&(const Y&) { return 11; } +inline int operator+=(const Y&, int x) { return 11; } +inline int operator*=(const Y&, int x) { return 11; } +inline int operator-=(const Y&, int x) { return 11; } +inline int operator/=(const Y&, int x) { return 11; } + +int +main () +{ + Foo1 (0); + Foo2 (0); + Foo3 (0); + Foo4 (0); +} diff --git a/gcc/testsuite/g++.dg/lookup/two-stage4.C b/gcc/testsuite/g++.dg/lookup/two-stage4.C index 7d97109..a89e618 100644 --- a/gcc/testsuite/g++.dg/lookup/two-stage4.C +++ b/gcc/testsuite/g++.dg/lookup/two-stage4.C @@ -8,7 +8,7 @@ template<typename T> bool operator==(wrap<T>, wrap<T>); template<typename T> void g(T, wrap<wrap<int> > x) { - bool b = x == x; // { dg-bogus "" "" { xfail *-*-* } } + bool b = x == x; // { dg-bogus "" "" } } template<typename T> void operator==(wrap<wrap<T> >, wrap<wrap<T> >);