New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 707288 link

Starred by 1 user

Issue metadata

Status: WontFix
Owner: ----
Closed: Apr 2017
Cc:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 3
Type: Bug



Sign in to add a comment

clang and msvc don't agree on sizeof(enum) in presence of a static_cast

Project Member Reported by primiano@chromium.org, Mar 31 2017

Issue description

Found this while trying to understand redness in https://codereview.chromium.org/2784783003/

Given:
-----
#include <stdio.h>
#include <type_traits>
#include <inttypes.h>

enum { kInvalidKVIndex = static_cast<uint64_t>(-1) };
int main() {
  uint32_t foo = static_cast<uint32_t>(-1);
  uint64_t fool = static_cast<uint64_t>(foo);
  printf("fool(64 bit): %llx\n", fool);  // So if I cast u32 to u64, the 64 is not sign extended, right?

  printf("sizeof(size_t):%lu sizeof(kV):%lu is_signed:%d  val:%llx\n", sizeof(size_t), sizeof(kInvalidKVIndex), std::is_signed<decltype(kInvalidKVIndex)>::value, (uint64_t) kInvalidKVIndex);

}
-----

Clang prints:
-----
fool(64 bit): ffffffff
sizeof(size_t):8 sizeof(kV):8 is_signed:0  val:ffffffffffffffff
-----

MSVC 2015:
-----
fool(64 bit): ffffffff
sizeof(size_t):8 sizeof(kV):4 is_signed:0  val:ffffffffffffffff
-----

there are two things here:
1. apparently that static_cast static_cast<uint64_t> confuses one of the two compilers. I don't know who is wrong or right, but as a matter of facts they don't agree on the size of the enum.
2. (this is just about not knowing enough) Honestly, I can't understand why the 2nd value printed by printf is sign-extended by both compiler. I would have expected val to be just 0xffffffff (like fool above). What am I doing wrong here?
 

Comment 1 by h...@chromium.org, Apr 4 2017

Status: WontFix (was: Untriaged)
Summary: clang and msvc don't agree on sizeof(enum) in presence of a static_cast (was: clang ang gcc don't agree on sizeof(enum) in presence of a static_cast)
(I assume you mean Clang and MSVC don't agree.)

> 1. apparently that static_cast static_cast<uint64_t> confuses one of the two compilers. I don't know who is wrong or right, but as a matter of facts they don't agree on the size of the enum.

The case is not significant; the issue boils down to what is the underlying type of the enumeration. This is pretty confusing in general; C++11 allows setting the underlying type to avoid this kind of issues.

Since you have a static_cast<uint64_t>(-1) value in there, one would expect the underlying type of the enumeration to be uint64_t, but that's not the case.

C++11 says [dcl.enum p6]:
"For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can
represent all the enumerator values defined in the enumeration. If no integral type can represent all the
enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used
as the underlying type except that the underlying type shall not be larger than int unless the value of an
enumerator cannot fit in an int or unsigned int."

So with Clang the underlying type is int64_t because that's the smallest type where your value fits. Note that the unsignedness is lost, but the value fits.

MSVC, probably for legacy reasons, always uses 'int' as the underlying type (unless the user sets the type explicitly).

clang-cl warns about this:

/tmp/a.cc:3:8: warning: enumerator value is not representable in the underlying type 'int'
      [-Wmicrosoft-enum-value]
enum { kInvalidKVIndex = static_cast<uint64_t>(-1) };


> 2. (this is just about not knowing enough) Honestly, I can't understand why the 2nd value printed by printf is sign-extended by both compiler. I would have expected val to be just 0xffffffff (like fool above). What am I doing wrong here?

The value is sign-extended because the underlying type of the enumeration is a signed int in both compilers.

Sign in to add a comment