From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 25C18382FDAE for ; Tue, 30 Aug 2022 20:18:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 25C18382FDAE Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1661890695; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yGtXP25I+JCYv8qR0NZTl+dvC/ebGQOh9s/VR7gUYgM=; b=dXZIDwZCmgoUomnwmJf8NlAgg6wQafyFRlJkYxr4IYFmdJIlN08AQeXSLooT6PTW6CdB2h zC96Uk5CPGVlUorMGZkjL44rLbBN4PJ6k7kjM7q9YAcGOcVvolYxNvHjEPVsMmm90zgo2C dwo8l7TKUR2MPbK4IfrDqOOhnsBuPiw= Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-205-_05lMNLgMw6MTKZKYV_QLQ-1; Tue, 30 Aug 2022 16:18:14 -0400 X-MC-Unique: _05lMNLgMw6MTKZKYV_QLQ-1 Received: by mail-qk1-f200.google.com with SMTP id l15-20020a05620a28cf00b006b46997c070so10229471qkp.20 for ; Tue, 30 Aug 2022 13:18:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc; bh=GSnJBVVjh4AEwxX722iUf95TpTB8SlEoH7OfHNGBNrI=; b=yUm0MiFYkzW3rEIUBpuRTScq+++o+A49hMaTlLpNUSXnxRgA2/l3i9Cm6CvBS1b61f wLpcz10YNy3midazpyLrfM2vKsjkeg+mbuxOvzKeVlhtrz6eKBdeSP6J/BIr8COFtWmE qlrhLH9eqAejlyIsSyvGa8PK8aGF9SeNgEp508WfhOn71cN75SmHMMY9YsjHLvRUrmCx JYH9Q+TmPXM78/R0HTeAAgXRxE4E1SUkK6Li8pbLQjqiCDAioNF2brYchWEPtYZjl6Y6 c2RuFEkdnSZRzQIN+TWaD64ec+pw2QAdrRVTCqOpM9gxgO8P/n/wLV6h7+4XLrw1cy2y uFfg== X-Gm-Message-State: ACgBeo1uZMYo5/FrU0qm+wtD/G/VpGrAhWxEDixNgqSnH8/zyCG6P02k odjQTy/6DAZl/cm3fbFNBXAjUQsJX+3TaAvBeEPpuK7N+vFWpr7S27uavybMicUmYjbVTkz9TiX GZ99SRfm+vUBq1GgDGw== X-Received: by 2002:a05:6214:4013:b0:499:14b2:a40b with SMTP id kd19-20020a056214401300b0049914b2a40bmr3082878qvb.130.1661890692883; Tue, 30 Aug 2022 13:18:12 -0700 (PDT) X-Google-Smtp-Source: AA6agR7YMskzkG1rnsEQ9wMmecQFhfpzChlLGx7JpvoWtEZcLuaHoUZKkgZQjkTwLGrhyIxb03+wQQ== X-Received: by 2002:a05:6214:4013:b0:499:14b2:a40b with SMTP id kd19-20020a056214401300b0049914b2a40bmr3082842qvb.130.1661890692101; Tue, 30 Aug 2022 13:18:12 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id t2-20020a05622a148200b003434d3b5938sm7970579qtx.2.2022.08.30.13.18.10 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 30 Aug 2022 13:18:11 -0700 (PDT) Message-ID: <6e646969-8b4b-d1ce-e256-a69fab6726a0@redhat.com> Date: Tue, 30 Aug 2022 16:18:09 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.0 Subject: Re: [PATCH] c/c++: new warning: -Wxor-used-as-pow [PR90885] To: David Malcolm , gcc-patches@gcc.gnu.org References: <20220812013812.3183820-1-dmalcolm@redhat.com> From: Jason Merrill In-Reply-To: <20220812013812.3183820-1-dmalcolm@redhat.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-25.8 required=5.0 tests=BAYES_00,DKIM_INVALID,DKIM_SIGNED,GIT_PATCH_0,KAM_DMARC_NONE,KAM_DMARC_STATUS,NICE_REPLY_A,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 8/11/22 21:38, David Malcolm via Gcc-patches wrote: > PR c/90885 notes various places in real-world code where people have > written C/C++ code that uses ^ (exclusive or) where presumbably they > meant exponentiation. > > For example > https://codesearch.isocpp.org/cgi-bin/cgi_ppsearch?q=2%5E32&search=Search > currently finds 11 places using "2^32", and all of them appear to be > places where the user means 2 to the power of 32, rather than 2 > exclusive-orred with 32 (which is 34). > > This patch adds a new -Wxor-used-as-pow warning to the C and C++ > frontends to complain about ^ when the left-hand side is the decimal > constant 2 or the decimal constant 10. > > This is the same name as the corresponding clang warning: > https://clang.llvm.org/docs/DiagnosticsReference.html#wxor-used-as-pow > > As per the clang warning, the warning suggests converting the left-hand > side to a hexadecimal constant if you really mean xor, which suppresses > the warning (and this patch implements a fix-it hint for that, whereas > the clang implementation only has a fix-it hint for the initial > suggestion of exponentiation). > > I initially tried implementing this without checking for decimals, but > this version had lots of false positives. Checking for decimals > requires extending the lexer to capture whether or not a CPP_NUMBER > token was decimal. I added a new DECIMAL_INT flag to cpplib.h for this. > Unfortunately, c_token and cp_tokens both have only an unsigned char for > their flags (as captured by c_lex_with_flags), whereas this would add > the 12th flag to cpp_tokens. Of the first 8 flags, all but BOL are used > in the C or C++ frontends, but BOL is not, so I moved that to a higher > position, using its old value for the new DECIMAL_INT flag, so that it > is representable within an unsigned char. > > Example output: > > demo.c:5:13: warning: result of '2^8' is 10; did you mean '1 << 8' (256)? [-Wxor-used-as-pow] > 5 | int t2_8 = 2^8; > | ^ > | -- > | 1<< > demo.c:5:12: note: you can silence this warning by using a hexadecimal constant (0x2 rather than 2) > 5 | int t2_8 = 2^8; > | ^ > | 0x2 > demo.c:21:15: warning: result of '10^6' is 12; did you mean '1e6'? [-Wxor-used-as-pow] > 21 | int t10_6 = 10^6; > | ^ > | --- > | 1e > demo.c:21:13: note: you can silence this warning by using a hexadecimal constant (0xa rather than 10) > 21 | int t10_6 = 10^6; > | ^~ > | 0xa > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > > OK for trunk? Looks good to me, but a C maintainer should sign off on the C front-end changes. > Thanks > Dave > > > gcc/c-family/ChangeLog: > PR c/90885 > * c-common.h (check_for_xor_used_as_pow): New decl. > * c-lex.cc (c_lex_with_flags): Add DECIMAL_INT to flags as appropriate. > * c-warn.cc (check_for_xor_used_as_pow): New. > * c.opt (Wxor-used-as-pow): New. > > gcc/c/ChangeLog: > PR c/90885 > * c-parser.cc (c_parser_string_literal): Clear ret.m_decimal. > (c_parser_expr_no_commas): Likewise. > (c_parser_conditional_expression): Likewise. > (c_parser_binary_expression): Clear m_decimal when popping the > stack. > (c_parser_unary_expression): Clear ret.m_decimal. > (c_parser_has_attribute_expression): Likewise for result. > (c_parser_predefined_identifier): Likewise for expr. > (c_parser_postfix_expression): Likewise for expr. > Set expr.m_decimal when handling a CPP_NUMBER that was a decimal > token. > * c-tree.h (c_expr::m_decimal): New bitfield. > * c-typeck.cc (parser_build_binary_op): Clear result.m_decimal. > (parser_build_binary_op): Call check_for_xor_used_as_pow. > > gcc/cp/ChangeLog: > PR c/90885 > * cp-tree.h (class cp_expr): Add bitfield m_decimal. Clear it in > existing ctors. Add ctor that allows specifying its value. > (cp_expr::decimal_p): New accessor. > * parser.cc (cp_parser_expression_stack_entry::flags): New field. > (cp_parser_primary_expression): Set m_decimal of cp_expr when > handling numbers. > (cp_parser_binary_expression): Extract flags from token when > populating stack. Call check_for_xor_used_as_pow. > > gcc/ChangeLog: > PR c/90885 > * doc/invoke.texi (Warning Options): Add -Wxor-used-as-pow. > > gcc/testsuite/ChangeLog: > PR c/90885 > * c-c++-common/Wxor-used-as-pow-1.c: New test. > * c-c++-common/Wxor-used-as-pow-fixits.c: New test. > * g++.dg/parse/expr3.C: Convert 2 to 0x2 to suppress > -Wxor-used-as-pow. > * g++.dg/warn/Wparentheses-10.C: Likewise. > * g++.dg/warn/Wparentheses-18.C: Likewise. > * g++.dg/warn/Wparentheses-19.C: Likewise. > * g++.dg/warn/Wparentheses-9.C: Likewise. > * g++.dg/warn/Wxor-used-as-pow-named-op.C: New test. > * gcc.dg/Wparentheses-6.c: Convert 2 to 0x2 to suppress > -Wxor-used-as-pow. > * gcc.dg/Wparentheses-7.c: Likewise. > * gcc.dg/precedence-1.c: Likewise. > > libcpp/ChangeLog: > PR c/90885 > * include/cpplib.h (BOL): Move macro to 1 << 12 since it is > not used by C/C++'s unsigned char token flags. > (DECIMAL_INT): New, using 1 << 6, so that it is visible as > part of C/C++'s 8 bits of token flags. > > Signed-off-by: David Malcolm > --- > gcc/c-family/c-common.h | 4 + > gcc/c-family/c-lex.cc | 6 +- > gcc/c-family/c-warn.cc | 94 +++++++++++++++++++ > gcc/c-family/c.opt | 4 + > gcc/c/c-parser.cc | 9 ++ > gcc/c/c-tree.h | 3 + > gcc/c/c-typeck.cc | 9 ++ > gcc/cp/cp-tree.h | 19 +++- > gcc/cp/parser.cc | 17 +++- > gcc/doc/invoke.texi | 15 +++ > .../c-c++-common/Wxor-used-as-pow-1.c | 57 +++++++++++ > .../c-c++-common/Wxor-used-as-pow-fixits.c | 34 +++++++ > gcc/testsuite/g++.dg/parse/expr3.C | 2 +- > gcc/testsuite/g++.dg/warn/Wparentheses-10.C | 14 +-- > gcc/testsuite/g++.dg/warn/Wparentheses-18.C | 4 +- > gcc/testsuite/g++.dg/warn/Wparentheses-19.C | 12 +-- > gcc/testsuite/g++.dg/warn/Wparentheses-9.C | 4 +- > .../g++.dg/warn/Wxor-used-as-pow-named-op.C | 8 ++ > gcc/testsuite/gcc.dg/Wparentheses-6.c | 4 +- > gcc/testsuite/gcc.dg/Wparentheses-7.c | 12 +-- > gcc/testsuite/gcc.dg/precedence-1.c | 4 +- > libcpp/include/cpplib.h | 3 +- > 22 files changed, 304 insertions(+), 34 deletions(-) > create mode 100644 gcc/testsuite/c-c++-common/Wxor-used-as-pow-1.c > create mode 100644 gcc/testsuite/c-c++-common/Wxor-used-as-pow-fixits.c > create mode 100644 gcc/testsuite/g++.dg/warn/Wxor-used-as-pow-named-op.C > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index c06769b6f0b..78ce94c6591 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -1475,6 +1475,10 @@ extern tree do_warn_duplicated_branches_r (tree *, int *, void *); > extern void warn_for_multistatement_macros (location_t, location_t, > location_t, enum rid); > > +extern void check_for_xor_used_as_pow (location_t lhs_loc, tree lhs_val, > + location_t operator_loc, > + tree rhs_val); > + > /* In c-attribs.cc. */ > extern bool attribute_takes_identifier_p (const_tree); > extern tree handle_deprecated_attribute (tree *, tree, tree, int, bool *); > diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc > index 8bfa4f4024f..1eda6f1fccc 100644 > --- a/gcc/c-family/c-lex.cc > +++ b/gcc/c-family/c-lex.cc > @@ -509,7 +509,11 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, > /* C++ uses '0' to mark virtual functions as pure. > Set PURE_ZERO to pass this information to the C++ parser. */ > if (tok->val.str.len == 1 && *tok->val.str.text == '0') > - add_flags = PURE_ZERO; > + add_flags = PURE_ZERO | DECIMAL_INT; > + else if ((flags & CPP_N_INTEGER) && (flags & CPP_N_DECIMAL)) > + /* -Wxor-used-as-pow is only active for LHS of ^ expressed > + as a decimal integer. */ > + add_flags = DECIMAL_INT; > *value = interpret_integer (tok, flags, &overflow); > break; > > diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc > index ea7335f3edf..ed79cc3ca40 100644 > --- a/gcc/c-family/c-warn.cc > +++ b/gcc/c-family/c-warn.cc > @@ -3799,3 +3799,97 @@ do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1) > op0, op_symbol_code (code), op1); > } > } > + > +/* Given LHS_VAL ^ RHS_VAL, where LHS_LOC is the location of the LHS and > + OPERATOR_LOC is the location of the ^, complain with -Wxor-used-as-pow > + if it looks like the user meant exponentiation rather than xor. */ > + > +void > +check_for_xor_used_as_pow (location_t lhs_loc, tree lhs_val, > + location_t operator_loc, > + tree rhs_val) > +{ > + /* Only complain if both args are non-negative integer constants. */ > + if (!(TREE_CODE (lhs_val) == INTEGER_CST > + && tree_int_cst_sgn (lhs_val) >= 0)) > + return; > + if (!(TREE_CODE (rhs_val) == INTEGER_CST > + && tree_int_cst_sgn (rhs_val) >= 0)) > + return; > + > + /* Only complain if the LHS is 2 or 10. */ > + unsigned HOST_WIDE_INT lhs_uhwi = tree_to_uhwi (lhs_val); > + if (lhs_uhwi != 2 && lhs_uhwi != 10) > + return; > + > + unsigned HOST_WIDE_INT rhs_uhwi = tree_to_uhwi (rhs_val); > + unsigned HOST_WIDE_INT xor_result = lhs_uhwi ^ rhs_uhwi; > + binary_op_rich_location loc (operator_loc, > + lhs_val, rhs_val, false); > + > + /* If we issue fix-it hints with the warning then we will also issue a > + note suggesting how to suppress the warning with a different change. > + These proposed changes are incompatible. */ > + loc.fixits_cannot_be_auto_applied (); > + > + auto_diagnostic_group d; > + bool warned = false; > + if (lhs_uhwi == 2) > + { > + /* Would exponentiation fit in int, in long long, or not at all? */ > + if (rhs_uhwi < (INT_TYPE_SIZE - 1)) > + { > + unsigned HOST_WIDE_INT suggested_result = 1 << rhs_uhwi; > + loc.add_fixit_replace (lhs_loc, "1"); > + loc.add_fixit_replace (operator_loc, "<<"); > + warned = warning_at (&loc, OPT_Wxor_used_as_pow, > + "result of %<%wu^%wu%> is %wu;" > + " did you mean %<1 << %wu%> (%wu)?", > + lhs_uhwi, rhs_uhwi, xor_result, > + rhs_uhwi, suggested_result); > + } > + else if (rhs_uhwi < (LONG_LONG_TYPE_SIZE - 1)) > + { > + loc.add_fixit_replace (lhs_loc, "1LL"); > + loc.add_fixit_replace (operator_loc, "<<"); > + warned = warning_at (&loc, OPT_Wxor_used_as_pow, > + "result of %<%wu^%wu%> is %wu;" > + " did you mean %<1LL << %wu%>?", > + lhs_uhwi, rhs_uhwi, xor_result, > + rhs_uhwi); > + } > + else if (rhs_uhwi <= LONG_LONG_TYPE_SIZE) > + warned = warning_at (&loc, OPT_Wxor_used_as_pow, > + "result of %<%wu^%wu%> is %wu;" > + " did you mean exponentiation?", > + lhs_uhwi, rhs_uhwi, xor_result); > + /* Otherwise assume it's an xor. */ > + } > + else > + { > + gcc_assert (lhs_uhwi == 10); > + loc.add_fixit_replace (lhs_loc, "1"); > + loc.add_fixit_replace (operator_loc, "e"); > + warned = warning_at (&loc, OPT_Wxor_used_as_pow, > + "result of %<%wu^%wu%> is %wu;" > + " did you mean %<1e%wu%>?", > + lhs_uhwi, rhs_uhwi, xor_result, > + rhs_uhwi); > + } > + if (warned) > + { > + gcc_rich_location note_loc (lhs_loc); > + if (lhs_uhwi == 2) > + note_loc.add_fixit_replace (lhs_loc, "0x2"); > + else > + { > + gcc_assert (lhs_uhwi == 10); > + note_loc.add_fixit_replace (lhs_loc, "0xa"); > + } > + note_loc.fixits_cannot_be_auto_applied (); > + inform (¬e_loc, > + "you can silence this warning by using a hexadecimal constant" > + " (%wx rather than %wd)", > + lhs_uhwi, lhs_uhwi); > + } > +} > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index 44e1a60ce24..c11ea50ac42 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -1439,6 +1439,10 @@ Wwrite-strings > C ObjC C++ ObjC++ Var(warn_write_strings) Warning > In C++, nonzero means warn about deprecated conversion from string literals to 'char *'. In C, similar warning, except that the conversion is of course not deprecated by the ISO C standard. > > +Wxor-used-as-pow > +C C++ Common Var(warn_xor_used_as_pow) Warning Init(1) > +Warn about xor operators where it appears the user meant exponentiation. > + > Wzero-as-null-pointer-constant > C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning > Warn when a literal '0' is used as null pointer. > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > index 92049d1a101..25064576829 100644 > --- a/gcc/c/c-parser.cc > +++ b/gcc/c/c-parser.cc > @@ -7496,6 +7496,7 @@ c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) > ret.original_code = STRING_CST; > ret.original_type = NULL_TREE; > set_c_expr_source_range (&ret, get_range_from_loc (line_table, loc)); > + ret.m_decimal = 0; > parser->seen_string_literal = true; > return ret; > } > @@ -7575,6 +7576,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after, > ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type, > code, exp_location, rhs.value, > rhs.original_type); > + ret.m_decimal = 0; > set_c_expr_source_range (&ret, lhs.get_start (), rhs.get_finish ()); > if (code == NOP_EXPR) > ret.original_code = MODIFY_EXPR; > @@ -7712,6 +7714,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, > : NULL); > } > set_c_expr_source_range (&ret, start, exp2.get_finish ()); > + ret.m_decimal = 0; > return ret; > } > > @@ -7901,6 +7904,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, > TREE_OPERAND (t, 0) = stack[0].expr.value; \ > TREE_OPERAND (t, 1) = stack[1].expr.value; \ > stack[0].expr.value = t; \ > + stack[0].expr.m_decimal = 0; \ > } \ > else \ > stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \ > @@ -8187,6 +8191,7 @@ c_parser_unary_expression (c_parser *parser) > ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR); > ret.src_range.m_start = op_loc; > ret.src_range.m_finish = finish; > + ret.m_decimal = 0; > return ret; > } > case CPP_PLUS: > @@ -8560,6 +8565,7 @@ c_parser_has_attribute_expression (c_parser *parser) > result.value = boolean_false_node; > > set_c_expr_source_range (&result, start, finish); > + result.m_decimal = 0; > return result; > } > > @@ -8925,6 +8931,7 @@ c_parser_predefined_identifier (c_parser *parser) > expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, > c_parser_peek_token (parser)->value); > set_c_expr_source_range (&expr, loc, loc); > + expr.m_decimal = 0; > c_parser_consume_token (parser); > return expr; > } > @@ -9003,12 +9010,14 @@ c_parser_postfix_expression (c_parser *parser) > source_range tok_range = c_parser_peek_token (parser)->get_range (); > expr.original_code = ERROR_MARK; > expr.original_type = NULL; > + expr.m_decimal = 0; > switch (c_parser_peek_token (parser)->type) > { > case CPP_NUMBER: > expr.value = c_parser_peek_token (parser)->value; > set_c_expr_source_range (&expr, tok_range); > loc = c_parser_peek_token (parser)->location; > + expr.m_decimal = c_parser_peek_token (parser)->flags & DECIMAL_INT; > c_parser_consume_token (parser); > if (TREE_CODE (expr.value) == FIXED_CST > && !targetm.fixed_point_supported_p ()) > diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h > index e655afd1cd4..b4231a17859 100644 > --- a/gcc/c/c-tree.h > +++ b/gcc/c/c-tree.h > @@ -147,6 +147,9 @@ struct c_expr > etc), so we stash a copy here. */ > source_range src_range; > > + /* True if this was directly from a decimal constant token. */ > + bool m_decimal : 1; > + > /* Access to the first and last locations within the source spelling > of this expression. */ > location_t get_start () const { return src_range.m_start; } > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc > index 8514488b7a5..1f5fa07c925 100644 > --- a/gcc/c/c-typeck.cc > +++ b/gcc/c/c-typeck.cc > @@ -3821,6 +3821,7 @@ parser_build_binary_op (location_t location, enum tree_code code, > struct c_expr arg1, struct c_expr arg2) > { > struct c_expr result; > + result.m_decimal = 0; > > enum tree_code code1 = arg1.original_code; > enum tree_code code2 = arg2.original_code; > @@ -3978,6 +3979,14 @@ parser_build_binary_op (location_t location, enum tree_code code, > "comparison between %qT and %qT", > type1, type2); > > + if (warn_xor_used_as_pow > + && code == BIT_XOR_EXPR > + && arg1.m_decimal > + && arg2.m_decimal) > + check_for_xor_used_as_pow (arg1.get_location (), arg1.value, > + location, > + arg2.value); > + > return result; > } > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 3278b4114bd..cdff8282e64 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -54,13 +54,23 @@ class cp_expr > { > public: > cp_expr () : > - m_value (NULL), m_loc (UNKNOWN_LOCATION) {} > + m_value (NULL), m_loc (UNKNOWN_LOCATION), > + m_decimal (false) > + {} > > cp_expr (tree value) : > - m_value (value), m_loc (cp_expr_location (m_value)) {} > + m_value (value), m_loc (cp_expr_location (m_value)), > + m_decimal (false) > + {} > > cp_expr (tree value, location_t loc): > - m_value (value), m_loc (loc) > + m_value (value), m_loc (loc), m_decimal (false) > + { > + protected_set_expr_location (value, loc); > + } > + > + cp_expr (tree value, location_t loc, bool decimal): > + m_value (value), m_loc (loc), m_decimal (decimal) > { > protected_set_expr_location (value, loc); > } > @@ -102,9 +112,12 @@ public: > return *this; > } > > + bool decimal_p () const { return m_decimal; } > + > private: > tree m_value; > location_t m_loc; > + bool m_decimal : 1; > }; > > inline bool > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index 33926d23179..73c46e79979 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -2066,6 +2066,8 @@ struct cp_parser_expression_stack_entry > enum cp_parser_prec prec; > /* Location of the binary operation we are parsing. */ > location_t loc; > + /* Flags from the operator token. */ > + unsigned char flags; > }; > > /* The stack for storing partial expressions. We only need NUM_PREC_VALUES > @@ -5611,7 +5613,7 @@ cp_parser_primary_expression (cp_parser *parser, > if (!cast_p) > cp_parser_non_integral_constant_expression (parser, NIC_FLOAT); > } > - return (cp_expr (token->u.value, token->location) > + return (cp_expr (token->u.value, token->location, token->flags & DECIMAL_INT) > .maybe_add_location_wrapper ()); > > case CPP_CHAR_USERDEF: > @@ -10157,6 +10159,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, > get_rhs: > current.tree_type = binops_by_token[token->type].tree_type; > current.loc = token->location; > + current.flags = token->flags; > > /* We used the operator token. */ > cp_lexer_consume_token (parser->lexer); > @@ -10241,6 +10244,18 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, > warn_logical_not_parentheses (current.loc, current.tree_type, > current.lhs, maybe_constant_value (rhs)); > > + if (warn_xor_used_as_pow > + && current.tree_type == BIT_XOR_EXPR > + /* Don't warn for named "xor" (as opposed to '^'). */ > + && !(current.flags & NAMED_OP) > + && current.lhs.decimal_p () > + && rhs.decimal_p ()) > + check_for_xor_used_as_pow > + (current.lhs.get_location (), > + tree_strip_any_location_wrapper (current.lhs), > + current.loc, > + tree_strip_any_location_wrapper (rhs)); > + > overload = NULL; > > location_t combined_loc = make_location (current.loc, > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index a17c059d515..31516ded123 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -414,6 +414,7 @@ Objective-C and Objective-C++ Dialects}. > -Wvector-operation-performance @gol > -Wvla -Wvla-larger-than=@var{byte-size} -Wno-vla-larger-than @gol > -Wvolatile-register-var -Wwrite-strings @gol > +-Wxor-used-as-pow @gol > -Wzero-length-bounds} > > @item Static Analyzer Options > @@ -9661,6 +9662,20 @@ modifier does not inhibit all optimizations that may eliminate reads > and/or writes to register variables. This warning is enabled by > @option{-Wall}. > > +@item -Wxor-used-as-pow @r{(C, C++, Objective-C and Objective-C++ only)} > +@opindex Wxor-used-as-pow > +@opindex Wno-xor-used-as-pow > +Warn about uses of @code{^}, the exclusive or operator, where it appears > +the user meant exponentiation. Specifically, the warning occurs when the > +left-hand side is the decimal constant 2 or 10 and the right-hand side > +is also a decimal constant. > + > +In C and C++, @code{^} means exclusive or, whereas in some other languages > +(e.g. TeX and some versions of BASIC) it means exponentiation. > + > +This warning is enabled by default. It can be silenced by converting one > +of the operands to hexadecimal. > + > @item -Wdisabled-optimization > @opindex Wdisabled-optimization > @opindex Wno-disabled-optimization > diff --git a/gcc/testsuite/c-c++-common/Wxor-used-as-pow-1.c b/gcc/testsuite/c-c++-common/Wxor-used-as-pow-1.c > new file mode 100644 > index 00000000000..962902c3a05 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wxor-used-as-pow-1.c > @@ -0,0 +1,57 @@ > +/* The precise output depends of sizeof(int) and sizeof(long long), so > + filter by target. */ > +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ > + > +/* Apparent uses of ^ for powers of 2. */ > + > +short t2_16 = 2^16; /* { dg-warning "result of '2\\^16' is 18; did you mean '1 << 16' \\(65536\\)\\? \\\[-Wxor-used-as-pow\\\]" } */ > +int t2_17 = 2^17; /* { dg-warning "result of '2\\^17' is 19; did you mean '1 << 17' \\(131072\\)\\?" } */ > +int t2_30 = 2^30; /* { dg-warning "result of '2\\^30' is 28; did you mean '1 << 30' \\(1073741824\\)\\?" } */ > + > +/* Should be 1LL at 31 and above, due to overflow. */ > +int t2_31 = 2^31; /* { dg-warning "result of '2\\^31' is 29; did you mean '1LL << 31'\\?" } */ > +int t2_32 = 2^32; /* { dg-warning "result of '2\\^32' is 34; did you mean '1LL << 32'\\?" } */ > + > +long t2_63 = 2^63; /* { dg-warning "result of '2\\^63' is 61; did you mean exponentiation\\?" } */ > +long t2_64 = 2^64; /* { dg-warning "result of '2\\^64' is 66; did you mean exponentiation\\?" } */ > + > +/* ...but don't warn when RHS is large enough. */ > +long t2_65 = 2^65; > +long t2_127 = 2^127; > +long t2_128 = 2^128; > +long t2_129 = 2^129; > + > +/* Verify that -Wxor-used-as-pow happens before folding. */ > +long t2_32_m1 = ((2^32)-1); /* { dg-warning "result of '2\\^32' is 34; did you mean '1LL << 32'\\?" } */ > + > + > +/* Apparent uses of ^ for powers of 10. */ > + > +long t10_2 = 10^2; /* { dg-warning "result of '10\\^2' is 8; did you mean '1e2'\\?" } */ > +long t10_9 = 10^9; /* { dg-warning "result of '10\\^9' is 3; did you mean '1e9'\\?" } */ > +long t10_10 = 10^10; /* { dg-warning "result of '10\\^10' is 0; did you mean '1e10'\\?" } */ > +long t10_100 = 10^100; /* { dg-warning "result of '10\\^100' is 110; did you mean '1e100'\\?" } */ > + > +/* Don't warn on negatives. */ > +long tm2_2 = -2^2; > +long t2_m2 = 2^-2; > +long tm10_10 = -10^10; > +long t10_m10 = 10^-10; > + > +/* If LHS is not 2 or 10, we shouldn't complain. */ > +int t0_0 = 0 ^ 0; > +int t6_7 = 6 ^ 7; > + > +/* Floating point is already covered by type-checking. */ > +float f10_10 = 10.f^10; /* { dg-error "invalid operands to binary \\^ \\(have 'float' and 'int'\\)" "" { target c } } */ > +/* { dg-error "invalid operands of types 'float' and 'int' to binary 'operator\\^'" "" { target c++ } .-1 } */ > + > +/* Don't complain if the LHS isn't literal decimal 2 or 10. */ > +int t1p1_16 = (1 + 1) ^ 16; > +int t5p5_6 = (5 + 5) ^ 6; > +int h2_8 = 0x2 ^ 8; > +int h10_3 = 0xa ^ 3; > + > +/* Don't complain if the RHS isn't literal decimal. */ > +int t2_x16 = 2^0x10; > +int h10_x3 = 10 ^ 0x3; > diff --git a/gcc/testsuite/c-c++-common/Wxor-used-as-pow-fixits.c b/gcc/testsuite/c-c++-common/Wxor-used-as-pow-fixits.c > new file mode 100644 > index 00000000000..f612b761c30 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wxor-used-as-pow-fixits.c > @@ -0,0 +1,34 @@ > +/* { dg-options "-fdiagnostics-show-caret" } */ > + > +/* Test fixit hints for -Wxor-used-as-pow. */ > + > +int t2_8 = 2^8; /* { dg-line line_a } */ > +/* { dg-warning "result of '2\\^8' is 10; did you mean '1 << 8' \\(256\\)\\?" "warn" { target *-*-* } line_a } */ > +/* { dg-begin-multiline-output "" } > + int t2_8 = 2^8; > + ^ > + -- > + 1<< > + { dg-end-multiline-output "" } */ > +/* { dg-message "you can silence this warning by using a hexadecimal constant \\(0x2 rather than 2\\)" "note" { target *-*-* } line_a } */ > +/* { dg-begin-multiline-output "" } > + int t2_8 = 2^8; > + ^ > + 0x2 > + { dg-end-multiline-output "" } */ > + > + > +int t10_6 = 10^6; /* { dg-line line_b } */ > +/* { dg-warning "result of '10\\^6' is 12; did you mean '1e6'\\?" "warn" { target *-*-* } line_b } */ > +/* { dg-begin-multiline-output "" } > + int t10_6 = 10^6; > + ^ > + --- > + 1e > + { dg-end-multiline-output "" } */ > +/* { dg-message "you can silence this warning by using a hexadecimal constant \\(0xa rather than 10\\)" "note" { target *-*-* } line_b } */ > +/* { dg-begin-multiline-output "" } > + int t10_6 = 10^6; > + ^~ > + 0xa > + { dg-end-multiline-output "" } */ > diff --git a/gcc/testsuite/g++.dg/parse/expr3.C b/gcc/testsuite/g++.dg/parse/expr3.C > index 95d332f41b0..1e166733843 100644 > --- a/gcc/testsuite/g++.dg/parse/expr3.C > +++ b/gcc/testsuite/g++.dg/parse/expr3.C > @@ -23,7 +23,7 @@ > > test (||, &&, 1, 1, 0, 0) > test (&&, |, 5, 1, 1, 19) > -test (|, ^, 1, 2, 2, 1) > +test (|, ^, 1, 2, 0x2, 1) > test (^, &, 1, 3, 2, 6) > test (&, ==, 1, 3, 2, 0) > test (==, <, 2, 0, 0, 0) > diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-10.C b/gcc/testsuite/g++.dg/warn/Wparentheses-10.C > index 557db091ad0..a5d28efcc2e 100644 > --- a/gcc/testsuite/g++.dg/warn/Wparentheses-10.C > +++ b/gcc/testsuite/g++.dg/warn/Wparentheses-10.C > @@ -16,7 +16,7 @@ bar (int a, int b, int c) > foo (1 & (2 ^ c)); > foo (1 & 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 & 2) ^ 3); > - foo (1 & (2 ^ 3)); > + foo (1 & (0x2 ^ 3)); > foo (a ^ b & c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) & c); > foo (a ^ (b & c)); > @@ -34,7 +34,7 @@ bar (int a, int b, int c) > foo (1 + (2 ^ c)); > foo (1 + 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 + 2) ^ 3); > - foo (1 + (2 ^ 3)); > + foo (1 + (0x2 ^ 3)); > foo (a ^ b + c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) + c); > foo (a ^ (b + c)); > @@ -52,7 +52,7 @@ bar (int a, int b, int c) > foo (1 - (2 ^ c)); > foo (1 - 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 - 2) ^ 3); > - foo (1 - (2 ^ 3)); > + foo (1 - (0x2 ^ 3)); > foo (a ^ b - c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) - c); > foo (a ^ (b - c)); > @@ -70,7 +70,7 @@ bar (int a, int b, int c) > foo (1 >= (2 ^ c)); > foo (1 >= 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 >= 2) ^ 3); > - foo (1 >= (2 ^ 3)); > + foo (1 >= (0x2 ^ 3)); > foo (a ^ b >= c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) >= c); > foo (a ^ (b >= c)); > @@ -88,7 +88,7 @@ bar (int a, int b, int c) > foo (1 == (2 ^ c)); > foo (1 == 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 == 2) ^ 3); > - foo (1 == (2 ^ 3)); > + foo (1 == (0x2 ^ 3)); > foo (a ^ b == c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) == c); > foo (a ^ (b == c)); > @@ -104,9 +104,9 @@ bar (int a, int b, int c) > foo (1 < 2 ^ c); // { dg-warning "parentheses" "correct warning" } > foo ((1 < 2) ^ c); > foo (1 < (2 ^ c)); > - foo (1 < 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > + foo (1 < 0x2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 < 2) ^ 3); > - foo (1 < (2 ^ 3)); > + foo (1 < (0x2 ^ 3)); > foo (a ^ b < c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) < c); > foo (a ^ (b < c)); > diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-18.C b/gcc/testsuite/g++.dg/warn/Wparentheses-18.C > index 83efaff4189..d50fad8ae80 100644 > --- a/gcc/testsuite/g++.dg/warn/Wparentheses-18.C > +++ b/gcc/testsuite/g++.dg/warn/Wparentheses-18.C > @@ -42,9 +42,9 @@ bar (T a, T b, T c) > foo (1 | 2 ^ c); // { dg-warning "parentheses" "correct warning" } > foo ((1 | 2) ^ c); > foo (1 | (2 ^ c)); > - foo (1 | 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > + foo (1 | 0x2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 | 2) ^ 3); > - foo (1 | (2 ^ 3)); > + foo (1 | (0x2 ^ 3)); > foo (a + b | c); // { dg-warning "parentheses" "correct warning" } > foo ((a + b) | c); > foo (a + (b | c)); > diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-19.C b/gcc/testsuite/g++.dg/warn/Wparentheses-19.C > index f0e2b805c9e..2ad8036ac84 100644 > --- a/gcc/testsuite/g++.dg/warn/Wparentheses-19.C > +++ b/gcc/testsuite/g++.dg/warn/Wparentheses-19.C > @@ -17,7 +17,7 @@ bar (T a, T b, T c) > foo (1 & (2 ^ c)); > foo (1 & 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 & 2) ^ 3); > - foo (1 & (2 ^ 3)); > + foo (1 & (0x2 ^ 3)); > foo (a ^ b & c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) & c); > foo (a ^ (b & c)); > @@ -35,7 +35,7 @@ bar (T a, T b, T c) > foo (1 + (2 ^ c)); > foo (1 + 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 + 2) ^ 3); > - foo (1 + (2 ^ 3)); > + foo (1 + (0x2 ^ 3)); > foo (a ^ b + c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) + c); > foo (a ^ (b + c)); > @@ -53,7 +53,7 @@ bar (T a, T b, T c) > foo (1 - (2 ^ c)); > foo (1 - 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 - 2) ^ 3); > - foo (1 - (2 ^ 3)); > + foo (1 - (0x2 ^ 3)); > foo (a ^ b - c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) - c); > foo (a ^ (b - c)); > @@ -71,7 +71,7 @@ bar (T a, T b, T c) > foo (1 >= (2 ^ c)); > foo (1 >= 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 >= 2) ^ 3); > - foo (1 >= (2 ^ 3)); > + foo (1 >= (0x2 ^ 3)); > foo (a ^ b >= c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) >= c); > foo (a ^ (b >= c)); > @@ -89,7 +89,7 @@ bar (T a, T b, T c) > foo (1 == (2 ^ c)); > foo (1 == 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 == 2) ^ 3); > - foo (1 == (2 ^ 3)); > + foo (1 == (0x2 ^ 3)); > foo (a ^ b == c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) == c); > foo (a ^ (b == c)); > @@ -107,7 +107,7 @@ bar (T a, T b, T c) > foo (1 < (2 ^ c)); > foo (1 < 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 < 2) ^ 3); > - foo (1 < (2 ^ 3)); > + foo (1 < (0x2 ^ 3)); > foo (a ^ b < c); // { dg-warning "parentheses" "correct warning" } > foo ((a ^ b) < c); > foo (a ^ (b < c)); > diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-9.C b/gcc/testsuite/g++.dg/warn/Wparentheses-9.C > index 7c8f01d327b..69976b3bacf 100644 > --- a/gcc/testsuite/g++.dg/warn/Wparentheses-9.C > +++ b/gcc/testsuite/g++.dg/warn/Wparentheses-9.C > @@ -41,9 +41,9 @@ bar (int a, int b, int c) > foo (1 | 2 ^ c); // { dg-warning "parentheses" "correct warning" } > foo ((1 | 2) ^ c); > foo (1 | (2 ^ c)); > - foo (1 | 2 ^ 3); // { dg-warning "parentheses" "correct warning" } > + foo (1 | 0x2 ^ 3); // { dg-warning "parentheses" "correct warning" } > foo ((1 | 2) ^ 3); > - foo (1 | (2 ^ 3)); > + foo (1 | (0x2 ^ 3)); > foo (a + b | c); // { dg-warning "parentheses" "correct warning" } > foo ((a + b) | c); > foo (a + (b | c)); > diff --git a/gcc/testsuite/g++.dg/warn/Wxor-used-as-pow-named-op.C b/gcc/testsuite/g++.dg/warn/Wxor-used-as-pow-named-op.C > new file mode 100644 > index 00000000000..4899d72b11b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wxor-used-as-pow-named-op.C > @@ -0,0 +1,8 @@ > +/* Verify that -Wxor-used-as-pow only warns with ^ and not with > + named "xor". */ > + > +int t2_16 = 2^16; /* { dg-warning "result of '2\\^16' is 18; did you mean '1 << 16' \\(65536\\)\\?" } */ > +int t2x16 = 2 xor 16; > + > +int t10_6 = 10^6; /* { dg-warning "result of '10\\^6' is 12; did you mean '1e6'\\?" } */ > +int t10x6 = 10 xor 6; > diff --git a/gcc/testsuite/gcc.dg/Wparentheses-6.c b/gcc/testsuite/gcc.dg/Wparentheses-6.c > index 2d2cc161394..260b6adebea 100644 > --- a/gcc/testsuite/gcc.dg/Wparentheses-6.c > +++ b/gcc/testsuite/gcc.dg/Wparentheses-6.c > @@ -43,9 +43,9 @@ bar (int a, int b, int c) > foo (1 | 2 ^ c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 | 2) ^ c); > foo (1 | (2 ^ c)); > - foo (1 | 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > + foo (1 | 0x2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 | 2) ^ 3); > - foo (1 | (2 ^ 3)); > + foo (1 | (0x2 ^ 3)); > foo (a + b | c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a + b) | c); > foo (a + (b | c)); > diff --git a/gcc/testsuite/gcc.dg/Wparentheses-7.c b/gcc/testsuite/gcc.dg/Wparentheses-7.c > index f3516969d23..6805094d296 100644 > --- a/gcc/testsuite/gcc.dg/Wparentheses-7.c > +++ b/gcc/testsuite/gcc.dg/Wparentheses-7.c > @@ -18,7 +18,7 @@ bar (int a, int b, int c) > foo (1 & (2 ^ c)); > foo (1 & 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 & 2) ^ 3); > - foo (1 & (2 ^ 3)); > + foo (1 & (0x2 ^ 3)); > foo (a ^ b & c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a ^ b) & c); > foo (a ^ (b & c)); > @@ -36,7 +36,7 @@ bar (int a, int b, int c) > foo (1 + (2 ^ c)); > foo (1 + 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 + 2) ^ 3); > - foo (1 + (2 ^ 3)); > + foo (1 + (0x2 ^ 3)); > foo (a ^ b + c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a ^ b) + c); > foo (a ^ (b + c)); > @@ -54,7 +54,7 @@ bar (int a, int b, int c) > foo (1 - (2 ^ c)); > foo (1 - 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 - 2) ^ 3); > - foo (1 - (2 ^ 3)); > + foo (1 - (0x2 ^ 3)); > foo (a ^ b - c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a ^ b) - c); > foo (a ^ (b - c)); > @@ -72,7 +72,7 @@ bar (int a, int b, int c) > foo (1 >= (2 ^ c)); > foo (1 >= 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 >= 2) ^ 3); > - foo (1 >= (2 ^ 3)); > + foo (1 >= (0x2 ^ 3)); > foo (a ^ b >= c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a ^ b) >= c); > foo (a ^ (b >= c)); > @@ -90,7 +90,7 @@ bar (int a, int b, int c) > foo (1 == (2 ^ c)); > foo (1 == 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 == 2) ^ 3); > - foo (1 == (2 ^ 3)); > + foo (1 == (0x2 ^ 3)); > foo (a ^ b == c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a ^ b) == c); > foo (a ^ (b == c)); > @@ -108,7 +108,7 @@ bar (int a, int b, int c) > foo (1 < (2 ^ c)); > foo (1 < 2 ^ 3); /* { dg-warning "parentheses" "correct warning" } */ > foo ((1 < 2) ^ 3); > - foo (1 < (2 ^ 3)); > + foo (1 < (0x2 ^ 3)); > foo (a ^ b < c); /* { dg-warning "parentheses" "correct warning" } */ > foo ((a ^ b) < c); > foo (a ^ (b < c)); > diff --git a/gcc/testsuite/gcc.dg/precedence-1.c b/gcc/testsuite/gcc.dg/precedence-1.c > index f3f1e352708..089cdfc1472 100644 > --- a/gcc/testsuite/gcc.dg/precedence-1.c > +++ b/gcc/testsuite/gcc.dg/precedence-1.c > @@ -135,10 +135,10 @@ f (void) > ASSERT_BIN (0, !=, 2, &, 1, 1, 1, 0); > ASSERT_BIN (1, &, 2, ==, 0, 0, 1, 0); > ASSERT_BIN (1, &, 2, !=, 0, 1, 0, 1); > - ASSERT_BIN (1, &, 2, ^, 3, 3, 3, 1); > + ASSERT_BIN (1, &, 0x2, ^, 3, 3, 3, 1); > ASSERT_BIN (3, ^, 2, &, 1, 3, 1, 3); > ASSERT_BIN (3, ^, 2, |, 1, 1, 1, 0); > - ASSERT_BIN (3, |, 2, ^, 1, 3, 2, 3); > + ASSERT_BIN (3, |, 0x2, ^, 1, 3, 2, 3); > ASSERT_BIN (2, |, 0, &&, 2, 1, 1, 2); > ASSERT_BIN (2, &&, 0, |, 2, 1, 2, 1); > ASSERT_BIN (0, &&, 0, ||, 1, 1, 1, 0); > diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h > index 3eba6f74b57..f1e7c2b3b2a 100644 > --- a/libcpp/include/cpplib.h > +++ b/libcpp/include/cpplib.h > @@ -190,7 +190,7 @@ struct GTY(()) cpp_string { > #define NAMED_OP (1 << 4) /* C++ named operators. */ > #define PREV_FALLTHROUGH (1 << 5) /* On a token preceeded by FALLTHROUGH > comment. */ > -#define BOL (1 << 6) /* Token at beginning of line. */ > +#define DECIMAL_INT (1 << 6) /* Decimal integer, set in c-lex.cc. */ > #define PURE_ZERO (1 << 7) /* Single 0 digit, used by the C++ frontend, > set in c-lex.cc. */ > #define SP_DIGRAPH (1 << 8) /* # or ## token was a digraph. */ > @@ -199,6 +199,7 @@ struct GTY(()) cpp_string { > after a # operator. */ > #define NO_EXPAND (1 << 10) /* Do not macro-expand this token. */ > #define PRAGMA_OP (1 << 11) /* _Pragma token. */ > +#define BOL (1 << 12) /* Token at beginning of line. */ > > /* Specify which field, if any, of the cpp_token union is used. */ >