{"id":2231545,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2231545/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/afO3cl6JJrYYVMVu@tucnak/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/1.1/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<afO3cl6JJrYYVMVu@tucnak>","date":"2026-04-30T20:11:30","name":"c, c++, v2: Introduce -Wconstant-logical-operand warning [PR125081]","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"4f0e76f7491209741270a2efebc9c978f564b836","submitter":{"id":671,"url":"http://patchwork.ozlabs.org/api/1.1/people/671/?format=json","name":"Jakub Jelinek","email":"jakub@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/afO3cl6JJrYYVMVu@tucnak/mbox/","series":[{"id":502375,"url":"http://patchwork.ozlabs.org/api/1.1/series/502375/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=502375","date":"2026-04-30T20:11:30","name":"c, c++, v2: Introduce -Wconstant-logical-operand warning [PR125081]","version":1,"mbox":"http://patchwork.ozlabs.org/series/502375/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2231545/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2231545/checks/","tags":{},"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=WDCe48Ic;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=WDCe48Ic","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g652c1h6Pz1yGq\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 01 May 2026 06:13:12 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 34DA742D3773\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 30 Apr 2026 20:13:10 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id 157D542D3766\n for <gcc-patches@gcc.gnu.org>; Thu, 30 Apr 2026 20:12:38 +0000 (GMT)","from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-515-ZHuCUOCvNi24OSXjHO_bTw-1; Thu,\n 30 Apr 2026 16:12:35 -0400","from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 514741956080\n for <gcc-patches@gcc.gnu.org>; Thu, 30 Apr 2026 20:12:34 +0000 (UTC)","from tucnak.zalov.cz (unknown [10.44.34.21])\n by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with\n ESMTPS\n id 7E58919560AB; Thu, 30 Apr 2026 20:12:33 +0000 (UTC)","from tucnak.zalov.cz (localhost [127.0.0.1])\n by tucnak.zalov.cz (8.18.1/8.18.1) with ESMTPS id 63UKBUNd3813292\n (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);\n Thu, 30 Apr 2026 22:11:30 +0200","(from jakub@localhost)\n by tucnak.zalov.cz (8.18.1/8.18.1/Submit) id 63UKBUw83813291;\n Thu, 30 Apr 2026 22:11:30 +0200"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 34DA742D3773","OpenDKIM Filter v2.11.0 sourceware.org 157D542D3766"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 157D542D3766","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 157D542D3766","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777579958; cv=none;\n b=SwvowKwRoZUr9jUESwhpQDZX+W3PZQtXf94q87uyItnNEOQrLIUCqOue0s7qvMmUsXwEABe3UGv2xhE/2m0lB0ZKWH9de4KKzWesje9mEdRKpuzhHX92jlJx3m/2KiRsCd9/c7k2vPZnyC3hVLwMNS4Z1g2ITy6PMGNnfmuq/1E=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777579958; c=relaxed/simple;\n bh=WtH2ithPZ2E3owgCW+mLJKnhNFdh9AyjXOK76c6nlAY=;\n h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version;\n b=kPWEg7XZgke2yvJ0ivBXGLjbOpg0bcE6ehIqMIpURwme/c234seS7EQUjy6AKeLw+yqzq6gwwPQR1P2HkfyNxzRiEmYuQPek3seoJ6oXmIbOkyrsrZyGAE9cfHMWM7qSo8PpZ1XTYYdX5r70hHXugti35EnwGikgcQY66189/Nw=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777579957;\n h=from:from:reply-to:reply-to:subject:subject:date:date:\n message-id:message-id:to:to:cc:cc:mime-version:mime-version:\n content-type:content-type:in-reply-to:in-reply-to:  references:references;\n bh=PNn2SUaM1Q7R7zoq4dxjDFQsWMH8K+Ub8rbuTMLv1xQ=;\n b=WDCe48IczP/zuL1r+Sft3/P69vVlIlhoktsuXE0b9wRn2cOz2FUfBer8qq51p1Kqli0TKZ\n 5UV5Nsc+k1I8JvvDBamya6m8u+68abP3G1EsxDDzLXoeEWdB6r+exKAkvan6mXh2AFdzBm\n yMuHBoFrIst+Koh0P9+EQ7u/WEGClWM=","X-MC-Unique":"ZHuCUOCvNi24OSXjHO_bTw-1","X-Mimecast-MFC-AGG-ID":"ZHuCUOCvNi24OSXjHO_bTw_1777579954","Date":"Thu, 30 Apr 2026 22:11:30 +0200","From":"Jakub Jelinek <jakub@redhat.com>","To":"\"Joseph S. Myers\" <josmyers@redhat.com>,\n Marek Polacek <polacek@redhat.com>, Jason Merrill <jason@redhat.com>","Cc":"gcc-patches@gcc.gnu.org","Subject":"[PATCH] c, c++, v2: Introduce -Wconstant-logical-operand warning\n [PR125081]","Message-ID":"<afO3cl6JJrYYVMVu@tucnak>","References":"<afMPwPZBZlyCU7TG@tucnak>\n <8d188ded-0e3a-426d-b3ef-6357cc98440f@redhat.com>\n <afNwI0F3WFI9i1bL@tucnak>\n <9acfb25a-8cb0-45f1-8059-d959d8e88b2a@redhat.com>","MIME-Version":"1.0","In-Reply-To":"<9acfb25a-8cb0-45f1-8059-d959d8e88b2a@redhat.com>","X-Scanned-By":"MIMEDefang 3.0 on 10.30.177.12","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"z_Yr1S6FfvdyeFATc7JT33dO093oPq79vFe2lB7AiAo_1777579954","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Reply-To":"Jakub Jelinek <jakub@redhat.com>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"On Thu, Apr 30, 2026 at 02:08:46PM -0400, Jason Merrill wrote:\n> > I can certainly implement that.  Or just warn also whenever the constant is\n> > 1 with some enum type originally, I don't see why people actually would write\n> > enum { A, B }; if (x && B) unless it is a poor man's pre-C11 replacement of bool (so\n> > say typedef enum BOOL { FALSE, TRUE } BOOL;\n> > and using if (x && TRUE)).  Or warn for constant 1 if it has enum type and\n> > the enum type contains more enumerators than just 0/1.  One can always get\n> > rid of the warning by using && ENUM != 0 instead of just && ENUM and make\n> > the code even more readable that way.\n> \n> Sounds good.\n\nHere is another version of the patch which implements that.\nThis version would have caught the && ff_genericize case.\n\n2026-04-30  Jakub Jelinek  <jakub@redhat.com>\n\n\tPR c++/125081\ngcc/doc/\n\t* invoke.texi (Wconstant-logical-operand): Document.\ngcc/c-family/\n\t* c.opt (Wconstant-logical-operand): New option.\n\t* c.opt.urls: Regenerate.\ngcc/c/\n\t* c-tree.h (parser_build_binary_op): Add ORIG_ARG1 argument.\n\t* c-typeck.cc (parser_build_binary_op): Likewise.  Emit\n\t-Wconstant-logical-operand warnings.\n\t* c-parser.cc (c_parser_binary_expression): Adjust\n\tparser_build_binary_op caller, pass to it the original\n\tstack[sp - 1].expr.value before c_objc_common_truthvalue_conversion.\ngcc/cp/\n\t* typeck.cc (cp_build_binary_op): Emit -Wconstant-logical-operand\n\twarnings.\n\t* c-c++-common/Wconstant-logical-operand-1.c: New test.\n\t* c-c++-common/Wconstant-logical-operand-2.c: New test.\n\n\n\n\tJakub","diff":"--- gcc/doc/invoke.texi.jj\t2026-04-30 10:18:13.834688557 +0200\n+++ gcc/doc/invoke.texi\t2026-04-30 22:07:50.717947812 +0200\n@@ -385,7 +385,7 @@ Objective-C and Objective-C++ Dialects}.\n -Wchar-subscripts\n -Wclobbered  -Wcomment\n -Wcompare-distinct-pointer-types\n--Wno-complain-wrong-lang\n+-Wno-complain-wrong-lang  -Wconstant-logical-operand\n -Wconversion  -Wno-coverage-mismatch  -Wno-cpp\n -Wdangling-else  -Wdangling-pointer  -Wdangling-pointer=@var{n}\n -Wdate-time\n@@ -10647,6 +10647,22 @@ extern int a;\n if (a < 0 && a < 0) @{ @dots{} @}\n @end smallexample\n \n+@opindex Wconstant-logical-operand\n+@opindex Wno-constant-logical-operand\n+@item -Wconstant-logical-operand\n+Warn about another case of suspicious uses of logical operators in\n+expressions, when neither operand of a logical operator is boolean\n+and one of the operands is (or folds into) a constant other than 0 or 1,\n+or enumerator with value 1 if the enumeral type contains enumerators with\n+values other than 0 or 1.\n+In such case the warning will suggest using corresponding bitwise operator.\n+@smallexample\n+extern int a;\n+if (a && 64) @{ @dots{} @}\n+@end smallexample\n+If the warning is a false positive, one can clarify the code by using\n+e.g. @code{a && 64 != 0} instead.\n+\n @opindex Wlogical-not-parentheses\n @opindex Wno-logical-not-parentheses\n @item -Wlogical-not-parentheses\n--- gcc/c-family/c.opt.jj\t2026-04-30 10:18:08.247786966 +0200\n+++ gcc/c-family/c.opt\t2026-04-30 20:14:14.864156018 +0200\n@@ -595,6 +595,10 @@ Wconditionally-supported\n C++ ObjC++ Var(warn_conditionally_supported) Warning\n Warn for conditionally-supported constructs.\n \n+Wconstant-logical-operand\n+C ObjC C++ ObjC++ Var(warn_constant_logical_operand) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)\n+Warn for constant operands of logical operators other than 0 or 1.\n+\n Wconversion\n C ObjC C++ ObjC++ Var(warn_conversion) Warning\n Warn for implicit type conversions that may change a value.\n--- gcc/c-family/c.opt.urls.jj\t2026-04-30 10:18:08.248786948 +0200\n+++ gcc/c-family/c.opt.urls\t2026-04-30 20:14:14.865118139 +0200\n@@ -415,6 +415,9 @@ UrlSuffix(gcc/Warning-Options.html#index\n Wconditionally-supported\n UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wconditionally-supported)\n \n+Wconstant-logical-operand\n+UrlSuffix(gcc/Warning-Options.html#index-Wconstant-logical-operand)\n+\n Wconversion\n UrlSuffix(gcc/Warning-Options.html#index-Wconversion) LangUrlSuffix_Fortran(gfortran/Error-and-Warning-Options.html#index-Wconversion)\n \n--- gcc/c/c-typeck.cc.jj\t2026-04-30 10:18:08.260786737 +0200\n+++ gcc/c/c-typeck.cc\t2026-04-30 21:18:33.663623866 +0200\n@@ -5112,13 +5112,15 @@ char_type_p (tree type)\n    in the input.  CODE, a tree_code, specifies the binary operator, and\n    ARG1 and ARG2 are the operands.  In addition to constructing the\n    expression, we check for operands that were written with other binary\n-   operators in a way that is likely to confuse the user.\n+   operators in a way that is likely to confuse the user.  ORIG_ARG1 is\n+   the original first operand for TRUTH_{AND,OR}IF_EXPR before it is\n+   converted to truth value, otherwise NULL_TREE.\n \n    LOCATION is the location of the binary operator.  */\n \n struct c_expr\n parser_build_binary_op (location_t location, enum tree_code code,\n-\t\t\tstruct c_expr arg1, struct c_expr arg2)\n+\t\t\tstruct c_expr arg1, struct c_expr arg2, tree orig_arg1)\n {\n   struct c_expr result;\n   result.m_decimal = 0;\n@@ -5163,6 +5165,55 @@ parser_build_binary_op (location_t locat\n     warn_logical_operator (location, code, TREE_TYPE (result.value),\n \t\t\t   code1, arg1.value, code2, arg2.value);\n \n+  if (warn_constant_logical_operand\n+      && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)\n+      && (TREE_CODE (type1) == INTEGER_TYPE\n+\t  || TREE_CODE (type1) == ENUMERAL_TYPE\n+\t  || TREE_CODE (type1) == BITINT_TYPE)\n+      && (TREE_CODE (type2) == INTEGER_TYPE\n+\t  || TREE_CODE (type2) == ENUMERAL_TYPE\n+\t  || TREE_CODE (type2) == BITINT_TYPE))\n+    {\n+      const char *name = code == TRUTH_ANDIF_EXPR ? \"&&\" : \"||\";\n+      if (orig_arg1 == NULL_TREE)\n+\torig_arg1 = arg1.value;\n+      auto enum_other_than_0_1 = [] (tree type) {\n+\tif (TREE_CODE (type) != ENUMERAL_TYPE)\n+\t  return false;\n+\tfor (tree l = TYPE_VALUES (type); l; l = TREE_CHAIN (l))\n+\t  {\n+\t    tree v = DECL_INITIAL (TREE_VALUE (l));\n+\t    if (!integer_zerop (v) && !integer_onep (v))\n+\t      return true;\n+\t  }\n+\treturn false;\n+      };\n+      if (TREE_CODE (arg2.value) == INTEGER_CST\n+\t  && !integer_zerop (arg2.value)\n+\t  && (!integer_onep (arg2.value) || enum_other_than_0_1 (type2)))\n+\t{\n+\t  gcc_rich_location richloc (location);\n+\t  richloc.add_fixit_replace (name + 1);\n+\t  auto_diagnostic_group d;\n+\t  if (warning_at (location, OPT_Wconstant_logical_operand,\n+\t\t\t  \"use of logical %qs with constant operand %qE\",\n+\t\t\t  name, arg2.value))\n+\t    inform (&richloc, \"use %qs for bitwise operation\", name + 1);\n+\t}\n+      else if (TREE_CODE (orig_arg1) == INTEGER_CST\n+\t       && !integer_zerop (orig_arg1)\n+\t       && (!integer_onep (orig_arg1) || enum_other_than_0_1 (type1)))\n+\t{\n+\t  gcc_rich_location richloc (location);\n+\t  richloc.add_fixit_replace (name + 1);\n+\t  auto_diagnostic_group d;\n+\t  if (warning_at (location, OPT_Wconstant_logical_operand,\n+\t\t\t  \"use of logical %qs with constant operand %qE\",\n+\t\t\t  name, orig_arg1))\n+\t    inform (&richloc, \"use %qs for bitwise operation\", name + 1);\n+\t}\n+    }\n+\n   if (warn_tautological_compare)\n     {\n       tree lhs = arg1.value;\n--- gcc/c/c-parser.cc.jj\t2026-04-30 10:18:13.802689121 +0200\n+++ gcc/c/c-parser.cc\t2026-04-30 20:14:14.869155933 +0200\n@@ -10304,6 +10304,9 @@ c_parser_binary_expression (c_parser *pa\n     location_t loc;\n     /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR.  */\n     tree sizeof_arg;\n+    /* The original expr.value before c_objc_common_truthvalue_conversion\n+       for TRUTH_{AND,OR}*_EXPR lhs operands.  */\n+    tree orig_expr;\n   } stack[NUM_PRECS];\n   int sp;\n   /* Location of the binary operator.  */\n@@ -10399,7 +10402,9 @@ c_parser_binary_expression (c_parser *pa\n       stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,\t      \\\n \t\t\t\t\t\t   stack[sp].op,\t      \\\n \t\t\t\t\t\t   stack[sp - 1].expr,\t      \\\n-\t\t\t\t\t\t   stack[sp].expr);\t      \\\n+\t\t\t\t\t\t   stack[sp].expr,\t      \\\n+\t\t\t\t\t\t   stack[sp - 1].orig_expr);  \\\n+    stack[sp - 1].orig_expr = NULL_TREE;\t\t\t\t      \\\n     sp--;\t\t\t\t\t\t\t\t      \\\n   } while (0)\n   gcc_assert (!after || c_dialect_objc ());\n@@ -10407,6 +10412,7 @@ c_parser_binary_expression (c_parser *pa\n   stack[0].expr = c_parser_cast_expression (parser, after);\n   stack[0].prec = PREC_NONE;\n   stack[0].sizeof_arg = c_last_sizeof_arg;\n+  stack[0].orig_expr = NULL_TREE;\n   sp = 0;\n   while (true)\n     {\n@@ -10505,6 +10511,7 @@ c_parser_binary_expression (c_parser *pa\n \t  stack[sp].expr\n \t    = convert_lvalue_to_rvalue (stack[sp].loc,\n \t\t\t\t\tstack[sp].expr, true, true);\n+\t  stack[sp].orig_expr = stack[sp].expr.value;\n \t  stack[sp].expr.value = c_objc_common_truthvalue_conversion\n \t    (stack[sp].loc, default_conversion (stack[sp].expr.value));\n \t  c_inhibit_evaluation_warnings += (stack[sp].expr.value\n@@ -10516,6 +10523,7 @@ c_parser_binary_expression (c_parser *pa\n \t  stack[sp].expr\n \t    = convert_lvalue_to_rvalue (stack[sp].loc,\n \t\t\t\t\tstack[sp].expr, true, true);\n+\t  stack[sp].orig_expr = stack[sp].expr.value;\n \t  stack[sp].expr.value = c_objc_common_truthvalue_conversion\n \t    (stack[sp].loc, default_conversion (stack[sp].expr.value));\n \t  c_inhibit_evaluation_warnings += (stack[sp].expr.value\n@@ -10531,6 +10539,7 @@ c_parser_binary_expression (c_parser *pa\n       stack[sp].prec = oprec;\n       stack[sp].op = ocode;\n       stack[sp].sizeof_arg = c_last_sizeof_arg;\n+      stack[sp].orig_expr = NULL_TREE;\n     }\n  out:\n   while (sp > 0)\n--- gcc/c/c-tree.h.jj\t2026-04-30 10:18:13.803689103 +0200\n+++ gcc/c/c-tree.h\t2026-04-30 20:14:14.870460631 +0200\n@@ -890,7 +890,7 @@ extern struct c_expr parser_build_unary_\n     \t\t\t\t\t    struct c_expr);\n extern struct c_expr parser_build_binary_op (location_t,\n     \t\t\t\t\t     enum tree_code, struct c_expr,\n-\t\t\t\t\t     struct c_expr);\n+\t\t\t\t\t     struct c_expr, tree);\n extern tree build_conditional_expr (location_t, tree, bool, tree, tree,\n \t\t\t\t    location_t, tree, tree, location_t);\n extern tree build_compound_expr (location_t, tree, tree);\n--- gcc/cp/typeck.cc.jj\t2026-04-30 10:18:08.342785292 +0200\n+++ gcc/cp/typeck.cc\t2026-04-30 21:18:00.423192892 +0200\n@@ -5953,6 +5953,53 @@ cp_build_binary_op (const op_location_t\n \t  return cp_build_binary_op (location, code, op0, op1, complain);\n \t}\n \n+      if (warn_constant_logical_operand\n+\t  && (complain & tf_warning)\n+\t  && (code0 == INTEGER_TYPE || code0 == ENUMERAL_TYPE)\n+\t  && (code1 == INTEGER_TYPE || code1 == ENUMERAL_TYPE))\n+\t{\n+\t  tree cop0 = fold_for_warn (op0), cop1 = fold_for_warn (op1);\n+\t  const char *name\n+\t    = ((code == TRUTH_ANDIF_EXPR || code == TRUTH_AND_EXPR)\n+\t       ? \"&&\" : \"||\");\n+\t  auto enum_other_than_0_1 = [] (tree type) {\n+\t    if (TREE_CODE (type) != ENUMERAL_TYPE)\n+\t      return false;\n+\t    for (tree l = TYPE_VALUES (type); l; l = TREE_CHAIN (l))\n+\t      {\n+\t\ttree v = DECL_INITIAL (TREE_VALUE (l));\n+\t\tif (!integer_zerop (v) && !integer_onep (v))\n+\t\t  return true;\n+\t      }\n+\t    return false;\n+\t  };\n+\t  if (TREE_CODE (cop1) == INTEGER_CST\n+\t      && !integer_zerop (cop1)\n+\t      && (!integer_onep (cop1) || enum_other_than_0_1 (orig_type1)))\n+\t    {\n+\t      gcc_rich_location richloc (location);\n+\t      richloc.add_fixit_replace (location.m_operator_loc, name + 1);\n+\t      auto_diagnostic_group d;\n+\t      if (warning_at (location, OPT_Wconstant_logical_operand,\n+\t\t\t      \"use of logical %qs with constant operand %qE\",\n+\t\t\t      name, cop1))\n+\t\tinform (&richloc, \"use %qs for bitwise operation\", name + 1);\n+\t    }\n+\t  else if (TREE_CODE (cop0) == INTEGER_CST\n+\t\t   && !integer_zerop (cop0)\n+\t\t   && (!integer_onep (cop0)\n+\t\t       || enum_other_than_0_1 (orig_type0)))\n+\t    {\n+\t      gcc_rich_location richloc (location);\n+\t      richloc.add_fixit_replace (location.m_operator_loc, name + 1);\n+\t      auto_diagnostic_group d;\n+\t      if (warning_at (location, OPT_Wconstant_logical_operand,\n+\t\t\t      \"use of logical %qs with constant operand %qE\",\n+\t\t\t      name, cop0))\n+\t\tinform (&richloc, \"use %qs for bitwise operation\", name + 1);\n+\t    }\n+\t}\n+\n       result_type = boolean_type_node;\n       break;\n \n--- gcc/testsuite/c-c++-common/Wconstant-logical-operand-1.c.jj\t2026-04-30 20:14:14.871996788 +0200\n+++ gcc/testsuite/c-c++-common/Wconstant-logical-operand-1.c\t2026-04-30 21:23:09.467902519 +0200\n@@ -0,0 +1,106 @@\n+/* PR c++/125081 */\n+/* { dg-do compile } */\n+/* { dg-options \"-std=c23\" { target c } } */\n+/* { dg-additional-options \"-Wconstant-logical-operand\" } */\n+\n+void foo (int);\n+enum A { B, C };\n+enum D { E, F, G, H, I };\n+\n+void\n+bar (int x, bool y)\n+{\n+  if (x && 64)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '64'\" } */\n+    foo (1);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (128 && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '128'\" } */\n+    foo (2);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x && 1)\n+    foo (3);\n+  if (1 && x)\n+    foo (4);\n+  if (x && 0)\n+    foo (5);\n+  if (0 && x)\n+    foo (6);\n+  if (x || 32)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '32'\" } */\n+    foo (7);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (256 || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '256'\" } */\n+    foo (8);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || 1)\n+    foo (9);\n+  if (1 || x)\n+    foo (10);\n+  if (x || 0)\n+    foo (11);\n+  if (0 || x)\n+    foo (12);\n+  if (y && 64)\n+    foo (13);\n+  if (128 && y)\n+    foo (14);\n+  if (y || 32)\n+    foo (15);\n+  if (256 || y)\n+    foo (16);\n+  if (x && B)\n+    foo (17);\n+  if (B && x)\n+    foo (18);\n+  if (x && C)\n+    foo (19);\n+  if (C && x)\n+    foo (20);\n+  if (x && E)\n+    foo (21);\n+  if (E && x)\n+    foo (22);\n+  if (x && F)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[1F]'\" } */\n+    foo (23);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (F && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[1F]'\" } */\n+    foo (24);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x && G)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[2G]'\" } */\n+    foo (25);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (G && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[2G]'\" } */\n+    foo (26);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || B)\n+    foo (27);\n+  if (B || x)\n+    foo (28);\n+  if (x || C)\n+    foo (29);\n+  if (C || x)\n+    foo (30);\n+  if (x || E)\n+    foo (31);\n+  if (E || x)\n+    foo (32);\n+  if (x || F)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[1F]'\" } */\n+    foo (33);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (F || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[1F]'\" } */\n+    foo (34);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || G)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[2G]'\" } */\n+    foo (35);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (G || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[2G]'\" } */\n+    foo (36);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+}\n+\n+void\n+baz (int x, bool y)\n+{\n+  if (x && 63 + 1)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '64'\" } */\n+    foo (1);\t\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (127 + 1 && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '128'\" } */\n+    foo (2);\t\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || 31 + 1)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '32'\" } */\n+    foo (7);\t\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (255 + 1 || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '256'\" } */\n+    foo (8);\t\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (y && 63 + 1)\n+    foo (13);\n+  if (127 + 1 && y)\n+    foo (14);\n+  if (y || 31 + 1)\n+    foo (15);\n+  if (255 + 1 || y)\n+    foo (16);\n+}\n--- gcc/testsuite/c-c++-common/Wconstant-logical-operand-2.c.jj\t2026-04-30 20:14:14.872108767 +0200\n+++ gcc/testsuite/c-c++-common/Wconstant-logical-operand-2.c\t2026-04-30 22:05:37.782226847 +0200\n@@ -0,0 +1,110 @@\n+/* PR c++/125081 */\n+/* { dg-do compile } */\n+/* { dg-options \"-std=c23\" { target c } } */\n+/* { dg-additional-options \"-Wall\" } */\n+\n+void foo (int);\n+enum A { B, C };\n+enum D { E, F, G, H, I };\n+\n+void\n+bar (int x, bool y)\n+{\n+  if (x && 64)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '64'\" } */\n+    foo (1);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (128 && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '128'\" } */\n+    foo (2);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x && 1)\n+    foo (3);\n+  if (1 && x)\n+    foo (4);\n+  if (x && 0)\n+    foo (5);\n+  if (0 && x)\n+    foo (6);\n+  if (x || 32)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '32'\" } */\n+    foo (7);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (256 || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '256'\" } */\n+    foo (8);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || 1)\n+    foo (9);\n+  if (1 || x)\n+    foo (10);\n+  if (x || 0)\n+    foo (11);\n+  if (0 || x)\n+    foo (12);\n+  if (y && 64)\n+    foo (13);\n+  if (128 && y)\n+    foo (14);\n+  if (y || 32)\n+    foo (15);\n+  if (256 || y)\n+    foo (16);\n+  if (x && B)\n+    foo (17);\n+  if (B && x)\n+    foo (18);\n+  if (x && C)\n+    foo (19);\n+  if (C && x)\n+    foo (20);\n+  if (x && E)\n+    foo (21);\n+  if (E && x)\n+    foo (22);\n+  if (x && F)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[1F]'\" } */\n+    foo (23);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (F && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[1F]'\" } */\n+    foo (24);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x && G)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[2G]'\" } */\n+    foo (25);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+\t\t/* { dg-warning \"enum constant in boolean context\" \"\" { target c++ } .-2 } */\n+  if (G && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '\\[2G]'\" } */\n+    foo (26);\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+\t\t/* { dg-warning \"enum constant in boolean context\" \"\" { target c++ } .-2 } */\n+  if (x || B)\n+    foo (27);\n+  if (B || x)\n+    foo (28);\n+  if (x || C)\n+    foo (29);\n+  if (C || x)\n+    foo (30);\n+  if (x || E)\n+    foo (31);\n+  if (E || x)\n+    foo (32);\n+  if (x || F)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[1F]'\" } */\n+    foo (33);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (F || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[1F]'\" } */\n+    foo (34);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || G)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[2G]'\" } */\n+    foo (35);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+\t\t/* { dg-warning \"enum constant in boolean context\" \"\" { target c++ } .-2 } */\n+  if (G || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '\\[2G]'\" } */\n+    foo (36);\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+\t\t/* { dg-warning \"enum constant in boolean context\" \"\" { target c++ } .-2 } */\n+}\n+\n+void\n+baz (int x, bool y)\n+{\n+  if (x && 63 + 1)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '64'\" } */\n+    foo (1);\t\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (127 + 1 && x)\t/* { dg-warning \"use of logical '\\\\\\&\\\\\\&' with constant operand '128'\" } */\n+    foo (2);\t\t/* { dg-message \"note: use '\\\\\\&' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (x || 31 + 1)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '32'\" } */\n+    foo (7);\t\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (255 + 1 || x)\t/* { dg-warning \"use of logical '\\\\\\|\\\\\\|' with constant operand '256'\" } */\n+    foo (8);\t\t/* { dg-message \"note: use '\\\\\\|' for bitwise operation\" \"\" { target *-*-* } .-1 } */\n+  if (y && 63 + 1)\n+    foo (13);\n+  if (127 + 1 && y)\n+    foo (14);\n+  if (y || 31 + 1)\n+    foo (15);\n+  if (255 + 1 || y)\n+    foo (16);\n+}\n","prefixes":[]}