Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/class_decl.c
Original file line number Diff line number Diff line change
Expand Up @@ -20662,7 +20662,13 @@ must be unsigned.
a_constant_ptr smallest, largest;
size_t bits_needed, bits_needed_largest, bits_needed_smallest;
a_constant_ptr enum_con;
a_boolean fixed_scoped_base =
integer_type_is_scoped_enum(bit_field_type);

if (fixed_scoped_base) {
use_signed = !enum_has_bool_underlying_type(bit_field_type) &&
int_kind_is_signed[bit_field_type->variant.integer.int_kind];
} /* if */
enum_con = enum_constants(bit_field_type);
if (enum_con == NULL) {
/* There are no enumeration constants, so no bits are needed to
Expand All @@ -20689,7 +20695,7 @@ must be unsigned.
bits_required_to_represent_integer_constant(largest);
/* See if the smallest value is negative. */
smallest_is_negative = (sign_of_integer_constant(smallest) < 0);
if (targ_enum_bit_fields_are_always_unsigned) {
if (targ_enum_bit_fields_are_always_unsigned && !fixed_scoped_base) {
/* Enum bit fields are always unsigned (many ABIs require this). */
use_signed = FALSE;
bits_needed = bits_needed_largest;
Expand All @@ -20699,7 +20705,9 @@ must be unsigned.
for efficiency reasons: if the enum values just fit in the bit
field size, an unsigned field might be necessary even though a
signed type was a good choice for the enum type. */
if (smallest_is_negative) {
if (fixed_scoped_base) {
/* Scoped enum bit fields retain their fixed underlying signedness. */
} else if (smallest_is_negative) {
/* Some enum values are negative, so a signed type is required.
The enum type must already be signed. */
use_signed = TRUE;
Expand Down Expand Up @@ -20734,6 +20742,7 @@ must be unsigned.
pos_warning(ec_enum_bit_field_too_small, &error_position);
} /* if */
if (targ_enum_bit_fields_are_always_unsigned && smallest_is_negative &&
!fixed_scoped_base &&
!bit_field_type->variant.integer.has_explicit_enum_base) {
type_warning(ec_unsigned_enum_bit_field_with_signed_enumerator,
bit_field_type);
Expand Down
2 changes: 2 additions & 0 deletions src/il_to_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -2391,11 +2391,13 @@ by octl.
back end. Specifically:
- don't generate enums when generating pcc mode
- don't generate enums with an explicit underlying type
- don't generate scoped enums with a fixed int underlying type
- don't generate empty enums (valid in C++, but not in C)
In these cases, the underlying integer type is used instead. */
!(is_for_c_gen_be(octl) &&
(octl->gen_pcc_code ||
type->variant.integer.has_explicit_enum_base ||
type->variant.integer.is_scoped_enum ||
enum_constants(type) == NULL))) {
/* Output a reference to the enum type. */
form_tag_reference(type, octl);
Expand Down
6 changes: 6 additions & 0 deletions src/pending_changes/edg-28934-scoped-enum-signedness.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[GH #456]
Preserve scoped enum underlying signedness

The C-generating back end now uses the underlying integer type for scoped
enumerations. Scoped enumeration bit fields retain their fixed underlying
signedness.
20 changes: 20 additions & 0 deletions tests/tests/regressions/edg-28934.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//type:rp
//options_all:--c++20
//options:--g++ --gnu_version=130300:--strict
// Test the emitted C representation as well as the front-end type.
enum class Signed { zero = 0 };
enum struct Empty {};
enum class Unsigned : unsigned { zero = 0 };
enum class Boolean : bool { zero = false, one = true };
struct Fields { Signed s : 3; Unsigned u : 3; Boolean b : 1; };
static_assert(__is_same(__underlying_type(Signed), int), "signed base");
static_assert(__is_same(__underlying_type(Empty), int), "empty base");
volatile int minus_one = -1;
int main() {
Signed s = static_cast<Signed>(minus_one);
Empty e = static_cast<Empty>(minus_one);
Fields f{static_cast<Signed>(minus_one), Unsigned::zero, Boolean::one};
return static_cast<long>(s) != -1 || static_cast<long>(e) != -1 ||
static_cast<int>(f.s) != -1 || static_cast<unsigned>(f.u) != 0 ||
!static_cast<bool>(f.b);
}