On 4/22/21 9:41 AM, Jonathan Wakely wrote:
On Thu, 22 Apr 2021 at 15:59, Martin Sebor <mse...@gmail.com> wrote:

On 4/22/21 2:52 AM, Jonathan Wakely wrote:
On Thu, 22 Apr 2021, 08:47 Martin Liška, wrote:

     On 4/21/21 6:11 PM, Martin Sebor wrote:
      > On 4/21/21 2:15 AM, Martin Liška wrote:
      >> Hello.
      >>
      >> It's addressing the following Clang warning:
      >> cp/lex.c:170:45: warning: result of comparison of constant 64
     with expression of type 'enum ovl_op_code' is always true
     [-Wtautological-constant-out-of-range-compare]
      >>
      >> Patch can bootstrap on x86_64-linux-gnu and survives regression
     tests.
      >>
      >> Ready to be installed?
      >> Thanks,
      >> Martin
      >>
      >> gcc/cp/ChangeLog:
      >>
      >>     * cp-tree.h (STATIC_ASSERT): Prefer static assert.
      >>     * lex.c (init_operators): Remove run-time check.
      >> ---
      >>   gcc/cp/cp-tree.h | 3 +++
      >>   gcc/cp/lex.c     | 2 --
      >>   2 files changed, 3 insertions(+), 2 deletions(-)
      >>
      >> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
      >> index 81ff375f8a5..a8f72448ea9 100644
      >> --- a/gcc/cp/cp-tree.h
      >> +++ b/gcc/cp/cp-tree.h
      >> @@ -5916,6 +5916,9 @@ enum ovl_op_code {
      >>     OVL_OP_MAX
      >>   };
      >>   +/* Make sure it fits in lang_decl_fn::operator_code. */
      >> +STATIC_ASSERT (OVL_OP_MAX < (1 << 6));
      >> +
      >
      > I wonder if there's a way to test this directly by something like
      >
      >   static_assert (number-of-bits (ovl_op_info_t::ovl_op_code)
      >                  <= number-of-bits (lang_decl_fn::operator_code));

     Good point, but I'm not aware of it. Maybe C++ people can chime in?


ovl_op_code is an unscoped enumeration (meaning "enum" not "enum class")
with no fixed underlying type (i.e. no enum-base like ": int" or ":
long" is specified) which means that the number of bits in is value
representation is the number of bits needed to represent the minimum and
maximum enumerators:

"the values of the enumeration are the values representable by a
hypothetical integer type with minimal width M such that all enumerators
can be represented."

There is no function/utility like number-of-bits that can tell you that
from the type though.You could use
std::underlying_type<ovl_op_code>::type to get the integral type that
the compiler used to represent it, but that will probably be 'int' in
this case and so all it tells you is an upper bound of no more than 32
bits, which is not useful for this purpose.

I suspected there wasn't a function like that.  Thanks for confirming
it.  I wrote the one below just to see if it could be done.  It works
for one bit-field but I can't think of a way to generalize it.  We'd
probably need a built-in for that.  Perhaps one might be useful.

enum E { e = 5 };
struct A { E e: 3; };

constexpr int number_of_bits ()
{
    A a = { };
    a.e = (E)-1;
    int n = 0;
    for (; a.e; ++n)
      a.e = (E)((unsigned)a.e ^ (1 << n));
    return n;
}

Martin

Or:

enum E { e = 5 };
struct A { E e: 3; };

constexpr int number_of_bits ()
{
    A a = { };
    a.e = (E)-1;
    return 32 - __builtin_clz(a.e);
}


I had the same thought about using clz.  It works in this case but
not in if one of the enumerators is negative, or if the underlying
type is signed.


But you can't get the number-of-bits needed for all the values of the
enum E, which is what I was referring to.

If you know the enumerators go from 0 to MAX (as is the case for
ovl_op_code) you can use (32 - __builtin_clz(MAX)) there too, but in
the general case you don't always know the maximum enumerator without
checking, and it depends whether the enumeration has a fixed
underlying type.

That might be another useful query to add a built-in or trait
for to improve introspection: get the min and max enumerator (or
even all of them, e.g., as an initializer_list or something like
that).

Martin

Reply via email to