https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92002
--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Reduced testcase: extern void fancy_abort(const char *, int, const char *) __attribute__((__noreturn__)) __attribute__((__cold__)); typedef union tree_node *tree; typedef const union tree_node *const_tree; enum signop { SIGNED, }; template <typename T> class generic_wide_int; class wide_int_storage; typedef generic_wide_int<wide_int_storage> wide_int; namespace wi { template <typename T> struct int_traits; } namespace wi { template <typename T> unsigned int get_precision(const T &); template <typename T1, typename T2> void copy(T1 &, const T2 &); template <typename T1, typename T2> bool eq_p(const T1 &, const T2 &); struct storage_ref { storage_ref(const long *, unsigned int, unsigned int); const long *val; unsigned int len; unsigned int precision; unsigned int get_len() const; const long *get_val() const; }; } inline ::wi::storage_ref::storage_ref(const long *val_in, unsigned int len_in, unsigned int precision_in) : val(val_in), len(len_in), precision(precision_in) {} inline unsigned int wi::storage_ref::get_len() const { return len; } inline const long *wi::storage_ref::get_val() const { return val; } template <typename storage> struct generic_wide_int : public storage { template <typename T> generic_wide_int(const T &); static const bool is_sign_extended = wi::int_traits<generic_wide_int<storage>>::is_sign_extended; }; template <typename storage> template <typename T> inline generic_wide_int<storage>::generic_wide_int(const T &x) : storage(x) {} namespace wi { template <typename storage> struct int_traits<generic_wide_int<storage>> : public wi::int_traits<storage> { }; } template <bool SE, bool HDP> struct wide_int_ref_storage : public wi::storage_ref { long scratch[2]; template <typename T> wide_int_ref_storage(const T &); }; template <bool SE, bool HDP> template <typename T> inline wide_int_ref_storage<SE, HDP>::wide_int_ref_storage(const T &x) : storage_ref(wi::int_traits<T>::decompose(scratch, 0, x)) {} namespace wi { template <bool SE, bool HDP> struct int_traits<wide_int_ref_storage<SE, HDP>> { static const bool host_dependent_precision = HDP; static const bool is_sign_extended = SE; }; } struct wide_int_storage { long val[(((16 * (8)) + 64) / 64)]; unsigned int len; unsigned int precision; template <typename T> wide_int_storage(const T &); long *write_val(); void set_len(unsigned int, bool = false); }; template <typename T> inline wide_int_storage::wide_int_storage(const T &x) { generic_wide_int<wide_int_ref_storage<wi::int_traits<T>::is_sign_extended, wi::int_traits<T>::host_dependent_precision>> xi(x); precision = xi.precision; wi::copy(*this, xi); } inline long *wide_int_storage::write_val() { return val; } inline void wide_int_storage::set_len(unsigned int l, bool is_sign_extended) { len = l; } namespace wi { struct hwi_with_prec { long val; unsigned int precision; signop sgn; }; hwi_with_prec shwi(long, unsigned int); template <> struct int_traits<wi::hwi_with_prec> { static const bool host_dependent_precision = false; static const bool is_sign_extended = true; static wi::storage_ref decompose(long *, unsigned int, const wi::hwi_with_prec &); }; } inline wi::storage_ref wi::int_traits<wi::hwi_with_prec>::decompose( long *scratch, unsigned int precision, const wi::hwi_with_prec &x) { ((void)(!(precision == x.precision) ? fancy_abort("/vol/gcc/src/hg/trunk/local/gcc/wide-int.h", 1700, __FUNCTION__), 0 : 0)); scratch[0] = x.val; return wi::storage_ref(scratch, 1, precision); } template <typename T1, typename T2> inline void wi::copy(T1 &x, const T2 &y) { long *xval = x.write_val(); const long *yval = y.get_val(); unsigned int len = y.get_len(); unsigned int i = 0; do xval[i] = yval[i]; while (++i < len); x.set_len(len, y.is_sign_extended); }; enum tree_code { ENUMERAL_TYPE, BOOLEAN_TYPE, INTEGER_TYPE, INTEGER_CST, }; struct tree_base { enum tree_code code : 16; }; struct tree_typed { tree type; }; struct tree_type_common { unsigned int precision : 10; }; union tree_node { struct tree_base base; struct tree_typed typed; struct tree_type_common type_common; }; namespace wi { typedef const generic_wide_int<wide_int_ref_storage<false, false>> tree_to_wide_ref; tree_to_wide_ref to_wide(const_tree); } extern unsigned int element_precision(const_tree); wide_int get_nonzero_bits(const_tree name) { if (((enum tree_code)(name)->base.code) == INTEGER_CST) return wi::to_wide(name); unsigned int precision = element_precision(name->typed.type); return wi::shwi(0, precision); } bool ssa_name_has_boolean_range(tree op) { if ((op->typed.type->base.code == ENUMERAL_TYPE || op->typed.type->base.code == BOOLEAN_TYPE || op->typed.type->base.code == INTEGER_TYPE) && op->typed.type->type_common.precision > 1 && wi::eq_p(get_nonzero_bits(op), 1)) return true; return false; } Doesn't warn on x86_64-linux, I guess there are different SRA decisions.