From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27647 invoked by alias); 15 Dec 2015 00:14:15 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 27631 invoked by uid 89); 15 Dec 2015 00:14:14 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mail-qg0-f43.google.com Received: from mail-qg0-f43.google.com (HELO mail-qg0-f43.google.com) (209.85.192.43) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 15 Dec 2015 00:14:10 +0000 Received: by qgx21 with SMTP id 21so20267411qgx.1 for ; Mon, 14 Dec 2015 16:14:08 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=oQ3Hm/q+VPwJQCmtTn30O7nRI3fTcuHYECDhFbd51do=; b=ekvdu1iH6YbuF8SEx0I0+6vY1OmrH4BTSnGUR/9/j0kqquC6glxkcXLtVAxE9VUGaq 8s6mtvfPAnkNT7Kq+jpEcWK5ir4MAJug7DJrxd9nOS/KN7MvUsFuNryszyayzXdozpom PHgZ/meN1+JYHSSKwKFiqBCb1zYsP8R0PwnDcTpenpLb8cVk6mCTCQcFNd8R1tl7X8x/ +e8JECuMk8shIiCsJph3sCrm4LMB7tagcpI592VUINpqG9SGdZJec/zfBFMTiYcMoqrV ZXuep8R68FliHaxwH32Hczdoa77wMQSq0MTH3ZzunoDOtSq2/eV9km5cGyenhKxnsZSh CMUQ== X-Gm-Message-State: ALoCoQmjH+KKj8dKiiFaETYP3UFjpMJfzete5LbAWwQLffBjv5LCY3W0nyLI8RuPclnEupn+3nz0/0vwPCrCrZQHXUHAOuBxDw== X-Received: by 10.140.160.69 with SMTP id g66mr36991940qhg.86.1450138448480; Mon, 14 Dec 2015 16:14:08 -0800 (PST) Received: from localhost.localdomain (ool-4353a8be.dyn.optonline.net. [67.83.168.190]) by smtp.gmail.com with ESMTPSA id k26sm14953295qkh.12.2015.12.14.16.14.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Dec 2015 16:14:07 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com, Patrick Palka Subject: [PATCH] Fix PR c++/21802 (two-stage name lookup fails for operators) Date: Tue, 15 Dec 2015 00:14:00 -0000 Message-Id: <1450138442-25061-1-git-send-email-patrick@parcs.ath.cx> In-Reply-To: <566F29AB.5010106@redhat.com> References: <566F29AB.5010106@redhat.com> X-SW-Source: 2015-12/txt/msg01446.txt.bz2 On Mon, 14 Dec 2015, Jason Merrill wrote: > On 12/12/2015 06:32 PM, Patrick Palka wrote: >>> >This should use cp_tree_operand_length. >> Hmm, I don't immediately see how I can use this function here. It >> expects a tree but I dont have an appropriate tree to give to it, only a >> tree_code. > > True. So let's introduce cp_tree_code_length next to cp_tree_operand_length. > > Jason > > Like this? Incremental diff followed by patch v4: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3487d77..59c70b2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6477,6 +6477,7 @@ extern bool is_lambda_ignored_entity (tree); /* in tree.c */ extern int cp_tree_operand_length (const_tree); +extern int cp_tree_code_length (enum tree_code); void cp_free_lang_data (tree t); extern tree force_target_expr (tree, tree, tsubst_flags_t); extern tree build_target_expr_with_type (tree, tree, tsubst_flags_t); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index ca72877..6e671b7 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2766,14 +2766,10 @@ build_min_non_dep_op_overload (enum tree_code op, nargs = call_expr_nargs (non_dep); - if (op == PREINCREMENT_EXPR - || op == PREDECREMENT_EXPR) - expected_nargs = 1; - else if (op == MODOP_EXPR - || op == ARRAY_REF) - expected_nargs = 2; - else - expected_nargs = TREE_CODE_LENGTH (op); + expected_nargs = cp_tree_code_length (op); + if (op == POSTINCREMENT_EXPR + || op == POSTDECREMENT_EXPR) + expected_nargs += 1; gcc_assert (nargs == expected_nargs); args = make_tree_vector (); @@ -4450,6 +4446,32 @@ cp_tree_operand_length (const_tree t) } } +/* Like cp_tree_operand_length, but takes a tree_code CODE. */ + +int +cp_tree_code_length (enum tree_code code) +{ + gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); + + switch (code) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + return 1; + + case ARRAY_REF: + return 2; + + case EXPR_PACK_EXPANSION: + return 1; + + default: + return TREE_CODE_LENGTH (code); + } +} + /* Implement -Wzero_as_null_pointer_constant. Return true if the conditions for the warning hold, false otherwise. */ bool diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 2e5e46e..39c1af2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7864,7 +7864,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { if (overload != NULL_TREE) return (build_min_non_dep_op_overload - (MODOP_EXPR, rval, overload, orig_lhs, orig_rhs)); + (MODIFY_EXPR, rval, overload, orig_lhs, orig_rhs)); return (build_min_non_dep (MODOP_EXPR, rval, orig_lhs, op, orig_rhs)); -- 8< -- Bootstrapped and regtested on x86_64-pc-linux-gnu. gcc/cp/ChangeLog: PR c++/21802 PR c++/53223 * cp-tree.h (cp_tree_code_length): Declare. (build_min_non_dep_op_overload): Declare. * tree.c (cp_tree_code_length): Define. (build_min_non_dep_op_overload): Define. (build_win_non_dep_call_vec): Copy the KOENIG_LOOKUP_P flag. * 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. * decl2.c (grok_array_decl): Likewise. * call.c (build_new_op_1): If during template processing we chose an operator overload that is a hidden friend function, set the call's KOENIG_LOOKUP_P flag to 1. 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/call.c | 13 ++ gcc/cp/cp-tree.h | 2 + gcc/cp/decl2.c | 13 +- gcc/cp/tree.c | 89 ++++++++++ gcc/cp/typeck.c | 100 ++++++++--- gcc/testsuite/g++.dg/cpp0x/pr53223.C | 45 +++++ gcc/testsuite/g++.dg/lookup/pr21802.C | 276 +++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/lookup/two-stage4.C | 2 +- 8 files changed, 517 insertions(+), 23 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/call.c b/gcc/cp/call.c index 117dd79..cdfa01a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5630,6 +5630,19 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1, result = error_mark_node; else result = build_over_call (cand, LOOKUP_NORMAL, complain); + + if (processing_template_decl + && result != NULL_TREE + && result != error_mark_node + && DECL_HIDDEN_FRIEND_P (cand->fn)) + { + tree call = result; + if (REFERENCE_REF_P (call)) + call = TREE_OPERAND (call, 0); + /* This prevents build_new_function_call from discarding this + function during instantiation of the enclosing template. */ + KOENIG_LOOKUP_P (call) = 1; + } } else { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6190f4e..d5e3acd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6477,6 +6477,7 @@ extern bool is_lambda_ignored_entity (tree); /* in tree.c */ extern int cp_tree_operand_length (const_tree); +extern int cp_tree_code_length (enum tree_code); void cp_free_lang_data (tree t); extern tree force_target_expr (tree, tree, tsubst_flags_t); extern tree build_target_expr_with_type (tree, tree, tsubst_flags_t); @@ -6513,6 +6514,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 *); extern tree build_cplus_new (tree, tree, tsubst_flags_t); extern tree build_aggr_init_expr (tree, tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2cc51d6..5ae6266 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -354,6 +354,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, tree expr; tree orig_array_expr = array_expr; tree orig_index_exp = index_exp; + tree overload = NULL_TREE; if (error_operand_p (array_expr) || error_operand_p (index_exp)) return error_mark_node; @@ -379,7 +380,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, if (decltype_p) complain |= tf_decltype; expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, - index_exp, NULL_TREE, /*overload=*/NULL, complain); + index_exp, NULL_TREE, &overload, complain); } else { @@ -424,8 +425,14 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, expr = build_array_ref (input_location, array_expr, index_exp); } if (processing_template_decl && expr != error_mark_node) - return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp, - NULL_TREE, NULL_TREE); + { + if (overload != NULL_TREE) + return (build_min_non_dep_op_overload + (ARRAY_REF, expr, overload, orig_array_expr, orig_index_exp)); + + return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp, + NULL_TREE, NULL_TREE); + } return expr; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5dad0a7..0c0987d 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2741,9 +2741,72 @@ build_min_non_dep_call_vec (tree non_dep, tree fn, vec *argvec) non_dep = TREE_OPERAND (non_dep, 0); TREE_TYPE (t) = TREE_TYPE (non_dep); TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (non_dep); + KOENIG_LOOKUP_P (t) = KOENIG_LOOKUP_P (non_dep); 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, expected_nargs; + tree fn, call; + vec *args; + + if (REFERENCE_REF_P (non_dep)) + non_dep = TREE_OPERAND (non_dep, 0); + + nargs = call_expr_nargs (non_dep); + + expected_nargs = cp_tree_code_length (op); + if (op == POSTINCREMENT_EXPR + || op == POSTDECREMENT_EXPR) + expected_nargs += 1; + gcc_assert (nargs == expected_nargs); + + 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) { @@ -4383,6 +4446,32 @@ cp_tree_operand_length (const_tree t) } } +/* Like cp_tree_operand_length, but takes a tree_code CODE. */ + +int +cp_tree_code_length (enum tree_code code) +{ + gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); + + switch (code) + { + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + return 1; + + case ARRAY_REF: + return 2; + + case EXPR_PACK_EXPANSION: + return 1; + + default: + return TREE_CODE_LENGTH (code); + } +} + /* Implement -Wzero_as_null_pointer_constant. Return true if the conditions for the warning hold, false otherwise. */ bool diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 17671ee..39c1af2 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 **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< + +#define SA(x) static_assert ((x), #x) + +struct A +{ + int good() const; + int operator *() const; + int operator ++() const; + int operator [](int) const; +}; + +int operator-- (const A&); + +template +void func(T t) +{ + A x; + auto &&g1 = x.good(); + auto &&g2 = x.operator*(); + auto &&error1 = *x; + auto &&error2 = ++x; + auto &&error3 = --x; + auto &&error4 = x[5]; + SA ((std::is_same::value)); + SA ((std::is_same::value)); + SA ((std::is_same::value)); + SA ((std::is_same::value)); +} + +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..139f7b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/pr21802.C @@ -0,0 +1,276 @@ +// PR c++/21802 +// { dg-do run } +#include + +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. */ + +template +inline int operator+(const X &, T 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) { } + template + int operator%(T 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; } + friend int operator==(X o, int x) { return o.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. */ + template + int operator&(T x) { return m + x + 1; } + friend int operator==(Y o, int x) { return o.m + x + 1; } +}; + +/* The folloiwng "FooN" functions each contain a different way to call and to + resolve these operator overloads. */ + +template +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; 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); } + { int t = x == I; assert (t == 8); } +} + +template +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 +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 +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* (); 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); } + { int t = operator== (x, 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 (even though they 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 bool operator==(wrap, wrap); template void g(T, wrap > x) { - bool b = x == x; // { dg-bogus "" "" { xfail *-*-* } } + bool b = x == x; // { dg-bogus "" "" } } template void operator==(wrap >, wrap >); -- 2.7.0.rc0.50.g1470d8f.dirty