From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-lj1-x233.google.com (mail-lj1-x233.google.com [IPv6:2a00:1450:4864:20::233]) by sourceware.org (Postfix) with ESMTPS id 30C7A384773A for ; Wed, 3 Apr 2024 07:35:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 30C7A384773A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 30C7A384773A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::233 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712129725; cv=none; b=SngJRiwjQy37va3v/wY2BxMbNvegogbAe+8uFn600p+/cWFa+NlbKyJ1+Vy0e106MIe6ebN/m6t7cBnJwE5LczY0FP1xdKfOXpDrQifmE6GYuWB6AxbEGaksQdgPxIgLPn+EKhXRhCqP/6VzmUPJNWJC9vi0/tCjpQK0FUNKIww= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712129725; c=relaxed/simple; bh=lUAygyCARU1YQEDJAMlnO0QCewUIjjlKnMroyWF9h0M=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=Y1gHVfyu6tE3BtWyXZxrh1s5EssH7cvX7HNmR+7xmLbA/1wlnj+sWyerP/2gSOVUZGWFLl/G7h6W2V1Pd1LavxWqZZGP4R7sFN94jb8vE4bZVt5/D7eG5Wku1zZhem6pMXfdfmmzq3Qb7my8tkUN73ZjbH0MQqLEvU243PNaLsE= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-lj1-x233.google.com with SMTP id 38308e7fff4ca-2d717603aa5so63409091fa.0 for ; Wed, 03 Apr 2024 00:35:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1712129719; x=1712734519; darn=gcc.gnu.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=9emh3RLQ14enQfjFwM5wK5+xJ7pVsE9wgy8jlxe6qqs=; b=j2kauoe/w1Wbe2fWgRn1OAC6Q2vnDJRVxKCXOUbjqRoJ0dFdAI+eLbyxoj+egsf1hW yfx04cBEvJEUsgrnbwPKHRfwR5wmxVWZNGyeGtRNF39vdsr4RXTceHHDuTBw4IiPUihv yVgePRzOK8uZytsK12uu1/rc2zqfuM7fiES9xO4zwlcekSOOE2K9JRmyKUuVVdsPZ6mk lrIV72K8u0m2PXlb0z4RmpG0h2+B52d98PbC6Otx1C+Z+d2g/1wP5yidBfw0sHh0KvSQ zIct4JgixzcQ5BLRFgejd1hrYHEE9JZqudH5HZwyhutDNyyQ1/yE+ujNB3Ywdfrg9sk9 nRXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712129719; x=1712734519; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9emh3RLQ14enQfjFwM5wK5+xJ7pVsE9wgy8jlxe6qqs=; b=g1saFKI7voHazcXak/BBDVdVwVkWZcyz3v6gDSK59JfM5/Qvj5MZdlderSy8hbHKEG nnAGk4LaxpwHT4u37DFm//AzJjQO6oR0NZcOF6235FIl55H+8TsDgFhO5QfDKa1oBW03 7PwId6mkxdYEG4eOk9ztflHkWItsoMFPRz7xWOuJHbaW4v07tffY4iHbK7XAej+tsEAa iEZrAvwo2fbgoINCdVpGt+klJHstxw7FRotwtUY8LfDY2Qp9+CB3MGITz0bNebXPY09m JAHSdV6XQq/XSGFqiAtvkPE3WhC59xt++sR4fsjdmdBx+wiy5FGbValyxvYKxj+sKROI +nfQ== X-Forwarded-Encrypted: i=1; AJvYcCUGJiILiJPYTtxU3+kQy2dzIuWO+ckQIdJ+kGYZXWiv6l57qNbho6Ac24VSXjzzknsh4OnTy3HNEAotQX0AQLLZ0KU40j8uLQ== X-Gm-Message-State: AOJu0YymG9HGAZpxg6BcaD65t6SQIydX6E1r5e8Q8hXY0VczM8uymDEe q12s8jtDy1u1ioR/4+KdhVoBXJ/r3oNvuzUTfjGahfG7oz8t+gIQ3tGLkuxA8gpTgxubBLG2kPi zCZblM6LTt0zdRdraJPei6cvkF+E= X-Google-Smtp-Source: AGHT+IG187fkVZvE6+w/gYIsEOxX11P/uhVucKFry98CcwsoeAeCx92IK1wQZHq9DNTjmS0ZeXM12iYNYpfe5mquSRU= X-Received: by 2002:a2e:2407:0:b0:2d4:5b06:b9c7 with SMTP id k7-20020a2e2407000000b002d45b06b9c7mr10723804ljk.39.1712129719041; Wed, 03 Apr 2024 00:35:19 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Richard Biener Date: Wed, 3 Apr 2024 09:35:07 +0200 Message-ID: Subject: Re: [PATCH] c++: Implement C++26 P2809R3 - Trivial infinite loops are not Undefined Behavior To: Jakub Jelinek Cc: Jason Merrill , gcc-patches@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP 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 Wed, Apr 3, 2024 at 9:25=E2=80=AFAM Jakub Jelinek wro= te: > > Hi! > > The following patch attempts to implement P2809R3, which has been voted > in as a DR. > > The middle-end has its behavior documented: > '-ffinite-loops' > Assume that a loop with an exit will eventually take the exit and > not loop indefinitely. This allows the compiler to remove loops > that otherwise have no side-effects, not considering eventual > endless looping as such. > > This option is enabled by default at '-O2' for C++ with -std=3Dc++11 > or higher. > > So, the following patch attempts to detect trivial infinite loops and > turn their conditions into INTEGER_CSTs so that they don't really have > exits in the middle-end and so regardless of -ffinite-loops or > -fno-finite-loops they are handled as infinite loops by the middle-end. > Otherwise, if the condition would be a large expression calling various > constexpr functions, I'd be afraid we could e.g. just inline some of them > and not all of them and the middle-end could still see tests in the > condition and with -ffinite-loops optimize it by assuming that such loops > need to be finite. > > The "A trivial infinite loop is a trivially empty iteration statement for > which the converted controlling expression is a constant expression, when > interpreted as a constant-expression ([expr.const]), and evaluates to tru= e." > wording isn't clear to me what it implies for manifest constant evaluatio= n > of the expression, especially given the > int x =3D 42; > while (std::is_constant_evaluated() || --x) ; > example in the rationale. > > The patch assumes that the condition expression aren't manifestly constan= t > evaluated. If it would be supposed to be manifestly constant evaluated, > then I think the DR would significantly change behavior of existing progr= ams > and have really weird effects. Before the DR has been voted in, I think > void foo (int x) > { > if (x =3D=3D 0) > while (std::is_constant_evaluated()) > ; > else > while (!std::is_constant_evaluated()) > ; > } > would have well defined behavior of zero loop body iterations if x =3D=3D= 0 and > undefined behavior otherwise. If the condition expression is manifestly > constant evaluated if it evaluates to true, and otherwise can be > non-constant or not manifestly constant evaluated otherwise, then the > behavior would be that for x =3D=3D 0 it is well defined trvial infinite = loop, > while for x !=3D 0 it would keep to be undefined behavior (infinite loop, > as !std::is_constant_evaluated() is false when manifestly constant evalua= ted > and if we keep the condition as is, evaluates then to true. I think it > would be fairly strange if both loops are infinite even when their condit= ion > are negated. Similar for anything that is dependent on if consteval or > std::is_constant_evaluated() inside of it. > > So, the patch below attempts to discover trivially empty iteration > statements at cp_fold time if it is the final mce_false folding, > attempts to maybe_constant_value with mce_false evaluate the conditions > and replaces it with the returned value if constant non-zero. > > The testcases then try to check if the FE changed the calls in the > conditions into constants. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? I'll note that -ffinite-loops is reflected into the IL (the loop structure)= at CFG build time in the following simple way: /* Push the global flag_finite_loops state down to individual loops. = */ loop->finite_p =3D flag_finite_loops; and the "has an exit" is checked when we evalutate a loop->finite_p loop. The above flag evaluation could be made a langhook as it's suitably early, but I'm not sure whether that would help. The flag is evaluated when we evaluate the loop ANNOTATE_EXPRs, so annotating finite loops with a new annotate might be possible as well. Just in case making the control expression constant to the middle-end doesn't scale. Richard. > Or is it really supposed to be mce_true with the above described weird > behavior? If so, I think the standard at least should mention it in Anne= x C > (though, where when it is a DR?). > > 2024-04-02 Jakub Jelinek > > PR c++/114462 > * cp-gimplify.cc (cp_fold): Implement C++26 P2809R3 - Trivial inf= inite > loops are not Undefined Behavior. For trivially empty WHILE_STMT= , > DO_STMT or FOR_STMT iteration statements check if the condition i= s > constant expression which evaluates to true and in that case repl= ace > the condition with true. > > * g++.dg/cpp26/trivial-infinite-loop1.C: New test. > * g++.dg/cpp26/trivial-infinite-loop2.C: New test. > * g++.dg/cpp26/trivial-infinite-loop3.C: New test. > > --- gcc/cp/cp-gimplify.cc.jj 2024-03-23 11:17:06.958445857 +0100 > +++ gcc/cp/cp-gimplify.cc 2024-04-02 11:27:56.069170914 +0200 > @@ -3527,6 +3527,78 @@ cp_fold (tree x, fold_flags_t flags) > x =3D evaluate_requires_expr (x); > break; > > + case WHILE_STMT: > + /* For trivially empty iteration statements check if the condition > + is constant expression which evaluates to true and in that case > + change the condition to the constant, so that the middle-end tre= ats > + it as an infinite loop regardless of -ffinite-loops. */ > + if ((flags & ff_mce_false) && !integer_nonzerop (WHILE_COND (x))) > + { > + tree body =3D WHILE_BODY (x); > + if (expr_first (body) =3D=3D NULL_TREE) > + { > + r =3D maybe_constant_value (WHILE_COND (x), /*decl=3D*/NULL= _TREE, > + mce_false); > + if (integer_nonzerop (r)) > + { > + x =3D copy_node (x); > + WHILE_COND (x) =3D r; > + break; > + } > + } > + } > + return org_x; > + > + case DO_STMT: > + /* For trivially empty iteration statements check if the condition > + is constant expression which evaluates to true and in that case > + change the condition to the constant, so that the middle-end tre= ats > + it as an infinite loop regardless of -ffinite-loops. */ > + if ((flags & ff_mce_false) && !integer_nonzerop (DO_COND (x))) > + { > + tree body =3D DO_BODY (x); > + if (expr_first (body) =3D=3D NULL_TREE > + || (CONVERT_EXPR_P (body) > + && integer_zerop (TREE_OPERAND (body, 0)) > + && VOID_TYPE_P (TREE_TYPE (body)))) > + { > + r =3D maybe_constant_value (DO_COND (x), /*decl=3D*/NULL_TR= EE, > + mce_false); > + if (integer_nonzerop (r)) > + { > + x =3D copy_node (x); > + DO_COND (x) =3D r; > + break; > + } > + } > + } > + return org_x; > + > + case FOR_STMT: > + /* For trivially empty iteration statements check if the condition > + is constant expression which evaluates to true and in that case > + change the condition to the constant, so that the middle-end tre= ats > + it as an infinite loop regardless of -ffinite-loops. */ > + if ((flags & ff_mce_false) > + && FOR_COND (x) > + && FOR_EXPR (x) =3D=3D NULL_TREE > + && !integer_nonzerop (FOR_COND (x))) > + { > + tree body =3D FOR_BODY (x); > + if (expr_first (body) =3D=3D NULL_TREE) > + { > + r =3D maybe_constant_value (FOR_COND (x), /*decl=3D*/NULL_T= REE, > + mce_false); > + if (integer_nonzerop (r)) > + { > + x =3D copy_node (x); > + FOR_COND (x) =3D r; > + break; > + } > + } > + } > + return org_x; > + > default: > return org_x; > } > --- gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C.jj 2024-04-0= 2 11:50:00.943874185 +0200 > +++ gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop1.C 2024-04-02 12:19:= 52.132211449 +0200 > @@ -0,0 +1,150 @@ > +// P2809R3 - Trivial infinite loops are not Undefined Behavior > +// { dg-do compile { target c++11 } } > +// { dg-additional-options "-fdump-tree-gimple -fno-inline" } > +// { dg-final { scan-tree-dump-not " =3D foo \\\(\\\)" "gimple" } } > +// { dg-final { scan-tree-dump-not " =3D S::operator bool \\\(" "gimple"= } } > +// { dg-final { scan-tree-dump-not " =3D baz \\\(\\\)" "gimple" } } > +// { dg-final { scan-tree-dump-not " =3D std::is_constant_evaluated \\\(= \\\)" "gimple" } } > + > +volatile int v; > + > +constexpr bool > +foo () > +{ > + return true; > +} > + > +struct S > +{ > + constexpr S () : s (true) {} > + constexpr operator bool () const { return s; } > + bool s; > +}; > + > +#if __cplusplus >=3D 202002L > +namespace std { > + constexpr inline bool > + is_constant_evaluated () noexcept > + { > +#if __cpp_if_consteval >=3D 202106L > + if consteval { return true; } else { return false; } > +#else > + return __builtin_is_constant_evaluated (); > +#endif > + } > +} > + > +constexpr bool > +baz () > +{ > + return !std::is_constant_evaluated (); > +} > +#endif > + > +void > +bar (int x) > +{ > + switch (x) > + { > + case 0: > + while (foo ()) ; > + break; > + case 1: > + while (foo ()) {} > + break; > + case 2: > + do ; while (foo ()); > + break; > + case 3: > + do {} while (foo ()); > + break; > + case 4: > + for (v =3D 42; foo (); ) ; > + break; > + case 5: > + for (v =3D 42; foo (); ) {} > + break; > + case 6: > + for (int w =3D 42; foo (); ) ; > + break; > + case 7: > + for (int w =3D 42; foo (); ) {} > + break; > + case 10: > + while (S {}) ; > + break; > + case 11: > + while (S {}) {} > + break; > + case 12: > + do ; while (S {}); > + break; > + case 13: > + do {} while (S {}); > + break; > + case 14: > + for (v =3D 42; S {}; ) ; > + break; > + case 15: > + for (v =3D 42; S {}; ) {} > + break; > + case 16: > + for (int w =3D 42; S {}; ) ; > + break; > + case 17: > + for (int w =3D 42; S {}; ) {} > + break; > +#if __cplusplus >=3D 202002L > + case 20: > + while (baz ()) ; > + break; > + case 21: > + while (baz ()) {} > + break; > + case 22: > + do ; while (baz ()); > + break; > + case 23: > + do {} while (baz ()); > + break; > + case 24: > + for (v =3D 42; baz (); ) ; > + break; > + case 25: > + for (v =3D 42; baz (); ) {} > + break; > + case 26: > + for (int w =3D 42; baz (); ) ; > + break; > + case 27: > + for (int w =3D 42; baz (); ) {} > + break; > + case 30: > + while (!std::is_constant_evaluated ()) ; > + break; > + case 31: > + while (!std::is_constant_evaluated ()) {} > + break; > + case 32: > + do ; while (!std::is_constant_evaluated ()); > + break; > + case 33: > + do {} while (!std::is_constant_evaluated ()); > + break; > + case 34: > + for (v =3D 42; !std::is_constant_evaluated (); ) ; > + break; > + case 35: > + for (v =3D 42; !std::is_constant_evaluated (); ) {} > + break; > + case 36: > + for (int w =3D 42; !std::is_constant_evaluated (); ) ; > + break; > + case 37: > + for (int w =3D 42; !std::is_constant_evaluated (); ) {} > + break; > +#endif > + default: > + break; > + } > +} > --- gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C.jj 2024-04-0= 2 12:06:31.494215751 +0200 > +++ gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop2.C 2024-04-02 12:20:= 32.037663398 +0200 > @@ -0,0 +1,150 @@ > +// P2809R3 - Trivial infinite loops are not Undefined Behavior > +// { dg-do compile { target c++11 } } > +// { dg-additional-options "-fdump-tree-gimple -fno-inline" } > +// { dg-final { scan-tree-dump-times " =3D foo \\\(\\\)" 8 "gimple" } } > +// { dg-final { scan-tree-dump-times " =3D S::operator bool \\\(" 8 "gim= ple" } } > +// { dg-final { scan-tree-dump-times " =3D baz \\\(\\\)" 8 "gimple" { ta= rget c++20 } } } > +// { dg-final { scan-tree-dump-times " =3D std::is_constant_evaluated \\= \(\\\)" 9 "gimple" { target c++20 } } } > + > +volatile int v; > + > +constexpr bool > +foo () > +{ > + return false; > +} > + > +struct S > +{ > + constexpr S () : s (false) {} > + constexpr operator bool () const { return s; } > + bool s; > +}; > + > +#if __cplusplus >=3D 202002L > +namespace std { > + constexpr inline bool > + is_constant_evaluated () noexcept > + { > +#if __cpp_if_consteval >=3D 202106L > + if consteval { return true; } else { return false; } > +#else > + return __builtin_is_constant_evaluated (); > +#endif > + } > +} > + > +constexpr bool > +baz () > +{ > + return std::is_constant_evaluated (); > +} > +#endif > + > +void > +bar (int x) > +{ > + switch (x) > + { > + case 0: > + while (foo ()) ; > + break; > + case 1: > + while (foo ()) {} > + break; > + case 2: > + do ; while (foo ()); > + break; > + case 3: > + do {} while (foo ()); > + break; > + case 4: > + for (v =3D 42; foo (); ) ; > + break; > + case 5: > + for (v =3D 42; foo (); ) {} > + break; > + case 6: > + for (int w =3D 42; foo (); ) ; > + break; > + case 7: > + for (int w =3D 42; foo (); ) {} > + break; > + case 10: > + while (S {}) ; > + break; > + case 11: > + while (S {}) {} > + break; > + case 12: > + do ; while (S {}); > + break; > + case 13: > + do {} while (S {}); > + break; > + case 14: > + for (v =3D 42; S {}; ) ; > + break; > + case 15: > + for (v =3D 42; S {}; ) {} > + break; > + case 16: > + for (int w =3D 42; S {}; ) ; > + break; > + case 17: > + for (int w =3D 42; S {}; ) {} > + break; > +#if __cplusplus >=3D 202002L > + case 20: > + while (baz ()) ; > + break; > + case 21: > + while (baz ()) {} > + break; > + case 22: > + do ; while (baz ()); > + break; > + case 23: > + do {} while (baz ()); > + break; > + case 24: > + for (v =3D 42; baz (); ) ; > + break; > + case 25: > + for (v =3D 42; baz (); ) {} > + break; > + case 26: > + for (int w =3D 42; baz (); ) ; > + break; > + case 27: > + for (int w =3D 42; baz (); ) {} > + break; > + case 30: > + while (std::is_constant_evaluated ()) ; > + break; > + case 31: > + while (std::is_constant_evaluated ()) {} > + break; > + case 32: > + do ; while (std::is_constant_evaluated ()); > + break; > + case 33: > + do {} while (std::is_constant_evaluated ()); > + break; > + case 34: > + for (v =3D 42; std::is_constant_evaluated (); ) ; > + break; > + case 35: > + for (v =3D 42; std::is_constant_evaluated (); ) {} > + break; > + case 36: > + for (int w =3D 42; std::is_constant_evaluated (); ) ; > + break; > + case 37: > + for (int w =3D 42; std::is_constant_evaluated (); ) {} > + break; > +#endif > + default: > + break; > + } > +} > --- gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C.jj 2024-04-0= 2 12:14:23.993717999 +0200 > +++ gcc/testsuite/g++.dg/cpp26/trivial-infinite-loop3.C 2024-04-02 12:21:= 10.341137353 +0200 > @@ -0,0 +1,151 @@ > +// P2809R3 - Trivial infinite loops are not Undefined Behavior > +// { dg-do compile { target c++11 } } > +// { dg-additional-options "-fdump-tree-gimple -fno-inline" } > +// { dg-final { scan-tree-dump-times " =3D foo \\\(\\\)" 8 "gimple" } } > +// { dg-final { scan-tree-dump-times " =3D S::operator bool \\\(" 8 "gim= ple" } } > +// { dg-final { scan-tree-dump-times " =3D baz \\\(\\\)" 8 "gimple" { ta= rget c++20 } } } > +// { dg-final { scan-tree-dump-times " =3D std::is_constant_evaluated \\= \(\\\)" 9 "gimple" { target c++20 } } } > + > +volatile int v; > +int y; > + > +constexpr bool > +foo () > +{ > + return true; > +} > + > +struct S > +{ > + constexpr S () : s (true) {} > + constexpr operator bool () const { return s; } > + bool s; > +}; > + > +#if __cplusplus >=3D 202002L > +namespace std { > + constexpr inline bool > + is_constant_evaluated () noexcept > + { > +#if __cpp_if_consteval >=3D 202106L > + if consteval { return true; } else { return false; } > +#else > + return __builtin_is_constant_evaluated (); > +#endif > + } > +} > + > +constexpr bool > +baz () > +{ > + return !std::is_constant_evaluated (); > +} > +#endif > + > +void > +bar (int x) > +{ > + switch (x) > + { > + case 0: > + while (foo ()) ++y; > + break; > + case 1: > + while (foo ()) { ++y; } > + break; > + case 2: > + do ++y; while (foo ()); > + break; > + case 3: > + do { ++y; } while (foo ()); > + break; > + case 4: > + for (v =3D 42; foo (); ) ++y; > + break; > + case 5: > + for (v =3D 42; foo (); ) { ++y; } > + break; > + case 6: > + for (int w =3D 42; foo (); ) ++y; > + break; > + case 7: > + for (int w =3D 42; foo (); ) { ++y; } > + break; > + case 10: > + while (S {}) ++y; > + break; > + case 11: > + while (S {}) { ++y; } > + break; > + case 12: > + do ++y; while (S {}); > + break; > + case 13: > + do { ++y; } while (S {}); > + break; > + case 14: > + for (v =3D 42; S {}; ) ++y; > + break; > + case 15: > + for (v =3D 42; S {}; ) { ++y; } > + break; > + case 16: > + for (int w =3D 42; S {}; ) ++y; > + break; > + case 17: > + for (int w =3D 42; S {}; ) { ++y; } > + break; > +#if __cplusplus >=3D 202002L > + case 20: > + while (baz ()) ++y; > + break; > + case 21: > + while (baz ()) { ++y; } > + break; > + case 22: > + do ++y; while (baz ()); > + break; > + case 23: > + do { ++y; } while (baz ()); > + break; > + case 24: > + for (v =3D 42; baz (); ) ++y; > + break; > + case 25: > + for (v =3D 42; baz (); ) { ++y; } > + break; > + case 26: > + for (int w =3D 42; baz (); ) ++y; > + break; > + case 27: > + for (int w =3D 42; baz (); ) { ++y; } > + break; > + case 30: > + while (!std::is_constant_evaluated ()) ++y; > + break; > + case 31: > + while (!std::is_constant_evaluated ()) { ++y; } > + break; > + case 32: > + do ++y; while (!std::is_constant_evaluated ()); > + break; > + case 33: > + do { ++y; } while (!std::is_constant_evaluated ()); > + break; > + case 34: > + for (v =3D 42; !std::is_constant_evaluated (); ) ++y; > + break; > + case 35: > + for (v =3D 42; !std::is_constant_evaluated (); ) { ++y; } > + break; > + case 36: > + for (int w =3D 42; !std::is_constant_evaluated (); ) ++y; > + break; > + case 37: > + for (int w =3D 42; !std::is_constant_evaluated (); ) { ++y; } > + break; > +#endif > + default: > + break; > + } > +} > > Jakub >