Hi! SRA creates a VCE from integer to bool and that VCE then prevents other optimizations or e.g. prevents the uninit pass from avoiding a false positive warning.
In the PR using NOP_EXPR has been discussed as one possibility and has been rejected because at expansion it will emit a superfluous & 1 operation. I still think it is a good idea to use NOP_EXPR and so have changed expansion to not emit that & 1 operation in that case. Both spots are done with tight conditions (bool only etc.), as I'd like to fix just that case and not introduce a wider general optimization, but perhaps later we could lift it and do a general range of arbitrary type_has_mode_precision_p to non-type_has_mode_precision_p with same TYPE_MODE case. On this particular case, the expr.c part isn't really needed, because we have an unsigned char SSA_NAME with values 0 or 1, VCE to bool and comparison of that bool against false in a condition, and with the match.pd change the VCE is simplified into NOP_EXPR and that is later folded into just comparison of the unsigned char value against 0. If I under the debugger without the match.pd change the VCE into NOP_EXPR at the start of TER, then without the expr.c change indeed & 1 is emitted but then combine removes it again (non-zero bits logic makes that possible), with the expr.c change we don't emit it at all, which is good because we can't rely on the combine managing to do it in all cases. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2021-02-24 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/80635 * match.pd (view_convert<bool> (A) -> (bool) (A)): Simplify VCE of ssa_name_has_boolean_range with integral type to bool. * expr.c (expand_expr_real_2): Avoid REDUCE_BIT_FIELD for cast to boolean if operand is ssa_name_has_boolean_range. * g++.dg/warn/pr80635-1.C: New test. * g++.dg/warn/pr80635-2.C: New test. --- gcc/match.pd.jj 2021-02-18 16:21:01.000000000 +0100 +++ gcc/match.pd 2021-02-23 13:16:15.095416289 +0100 @@ -3316,7 +3316,13 @@ (define_operator_list COND_TERNARY (view_convert @0) (if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)) && (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0))) - && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0))) + && (TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0)) + || (TREE_CODE (type) == BOOLEAN_TYPE + && TREE_CODE (@0) == SSA_NAME + && TREE_CODE (TREE_TYPE (@0)) != BOOLEAN_TYPE + && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (@0)) + && type_has_mode_precision_p (TREE_TYPE (@0)) + && ssa_name_has_boolean_range (@0)))) (convert @0))) /* Strip inner integral conversions that do not change precision or size, or --- gcc/expr.c.jj 2021-02-02 10:01:26.483903572 +0100 +++ gcc/expr.c 2021-02-23 13:10:26.400323532 +0100 @@ -8790,6 +8790,15 @@ expand_expr_real_2 (sepops ops, rtx targ && GET_CODE (op0) == SUBREG) SUBREG_PROMOTED_VAR_P (op0) = 0; + /* Don't reduce to boolean range if we know the operand + already has a boolean range. */ + if (reduce_bit_field + && TREE_CODE (type) == BOOLEAN_TYPE + && TREE_CODE (treeop0) == SSA_NAME + && TREE_CODE (TREE_TYPE (treeop0)) != BOOLEAN_TYPE + && type_has_mode_precision_p (TREE_TYPE (treeop0)) + && ssa_name_has_boolean_range (treeop0)) + return op0; return REDUCE_BIT_FIELD (op0); } --- gcc/testsuite/g++.dg/warn/pr80635-1.C.jj 2021-02-23 13:17:35.398516088 +0100 +++ gcc/testsuite/g++.dg/warn/pr80635-1.C 2021-02-23 13:19:21.712324315 +0100 @@ -0,0 +1,46 @@ +// PR tree-optimization/80635 +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -Wmaybe-uninitialized" } + +using size_t = decltype (sizeof (1)); +inline void *operator new (size_t, void *p) { return p; } +template<typename T> +struct optional +{ + optional () : m_dummy (), live (false) {} + void emplace () { new (&m_item) T (); live = true; } + ~optional () { if (live) m_item.~T (); } + + union + { + struct {} m_dummy; + T m_item; + }; + bool live; +}; + +extern int get (); +extern void set (int); + +struct A +{ + A () : m (get ()) {} + ~A () { set (m); } // { dg-bogus "may be used uninitialized in this function" } + + int m; +}; + +struct B +{ + B (); + ~B (); +}; + +void func () +{ + optional<A> maybe_a; + optional<B> maybe_b; + + maybe_a.emplace (); + maybe_b.emplace (); +} --- gcc/testsuite/g++.dg/warn/pr80635-2.C.jj 2021-02-23 13:17:38.426482145 +0100 +++ gcc/testsuite/g++.dg/warn/pr80635-2.C 2021-02-23 13:27:34.215803360 +0100 @@ -0,0 +1,31 @@ +// PR tree-optimization/80635 +// { dg-do compile { target c++17 } } +// { dg-options "-O2 -Wmaybe-uninitialized" } + +#include <optional> + +extern int get (); +extern void set (int); + +struct A +{ + A () : m (get ()) {} + ~A () { set (m); } // { dg-bogus "may be used uninitialized in this function" } + + int m; +}; + +struct B +{ + B (); + ~B (); +}; + +void func () +{ + std::optional<A> maybe_a; + std::optional<B> maybe_b; + + maybe_a.emplace (); + maybe_b.emplace (); +} Jakub