Allow redefinition of enum types and enumerators. gcc/c: * c-decl.cc (start_num): Allow redefinition. (finish_enum): Diagnose conflicts. (build_enumerator): Set context. (diagnose_mismatched_decls): Diagnose conflicting enumerators. (push_decl): Preserve context for enumerators. gcc/testsuide/: * gcc.dg/c2x-tag-enum-1.c: New test. * gcc.dg/c2x-tag-enum-2.c: New test. * gcc.dg/c2x-tag-enum-3.c: New test. * gcc.dg/c2x-tag-enum-4.c: New test. --- gcc/c/c-decl.cc | 47 ++++++++++++++++++++-- gcc/c/c-typeck.cc | 5 ++- gcc/testsuite/gcc.dg/c2x-tag-enum-1.c | 56 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-enum-2.c | 23 +++++++++++ gcc/testsuite/gcc.dg/c2x-tag-enum-3.c | 7 ++++ gcc/testsuite/gcc.dg/c2x-tag-enum-4.c | 22 +++++++++++ 6 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-4.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index c5c6a853fa9..b514e8a35ee 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -2064,9 +2064,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, given scope. */ if (TREE_CODE (olddecl) == CONST_DECL) { - auto_diagnostic_group d; - error ("redeclaration of enumerator %q+D", newdecl); - locate_old_decl (olddecl); + if (flag_isoc2x + && TYPE_NAME (DECL_CONTEXT (newdecl)) + && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl) + && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT (olddecl))) + { + if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL (newdecl))) + { + auto_diagnostic_group d; + error ("conflicting redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + } + } + else + { + auto_diagnostic_group d; + error ("redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + } return false; } @@ -3227,8 +3242,11 @@ pushdecl (tree x) /* Must set DECL_CONTEXT for everything not at file scope or DECL_FILE_SCOPE_P won't work. Local externs don't count - unless they have initializers (which generate code). */ + unless they have initializers (which generate code). We + also exclude CONST_DECLs because enumerators will get the + type of the enum as context. */ if (current_function_decl + && TREE_CODE (x) != CONST_DECL && (!VAR_OR_FUNCTION_DECL_P (x) || DECL_INITIAL (x) || !TREE_PUBLIC (x))) DECL_CONTEXT (x) = current_function_decl; @@ -9606,9 +9624,15 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, if (name != NULL_TREE) enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc); + if (flag_isoc2x && enumtype != NULL_TREE + && TREE_CODE (enumtype) == ENUMERAL_TYPE + && TYPE_VALUES (enumtype) != NULL_TREE) + enumtype = NULL_TREE; + if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) { enumtype = make_node (ENUMERAL_TYPE); + TYPE_SIZE (enumtype) = NULL_TREE; pushtag (loc, name, enumtype); if (fixed_underlying_type != NULL_TREE) { @@ -9868,6 +9892,20 @@ finish_enum (tree enumtype, tree values, tree attributes) && !in_sizeof && !in_typeof && !in_alignof) struct_parse_info->struct_types.safe_push (enumtype); + /* Check for consistency with previous definition */ + if (flag_isoc2x) + { + tree vistype = previous_tag (enumtype); + if (vistype + && TREE_CODE (vistype) == TREE_CODE (enumtype) + && !C_TYPE_BEING_DEFINED (vistype)) + { + TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype); + if (!comptypes_same_p (enumtype, vistype)) + error("conflicting redefinition of enum %qT", enumtype); + } + } + C_TYPE_BEING_DEFINED (enumtype) = 0; return enumtype; @@ -10047,6 +10085,7 @@ build_enumerator (location_t decl_loc, location_t loc, decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value)); DECL_INITIAL (decl) = value; + DECL_CONTEXT (decl) = the_enum->enum_type; pushdecl (decl); return tree_cons (decl, value, NULL_TREE); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 802c727d9d3..2b79cbba950 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1396,6 +1396,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, { case ENUMERAL_TYPE: { + if (!comptypes (ENUM_UNDERLYING_TYPE (t1), ENUM_UNDERLYING_TYPE (t2))) + return false; + /* Speed up the case where the type values are in the same order. */ tree tv1 = TYPE_VALUES (t1); tree tv2 = TYPE_VALUES (t2); @@ -6895,7 +6898,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (checktype != error_mark_node && TREE_CODE (checktype) == ENUMERAL_TYPE && TREE_CODE (type) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + && !comptypes (TYPE_MAIN_VARIANT (checktype), TYPE_MAIN_VARIANT (type))) { gcc_rich_location loc (location); warning_at (&loc, OPT_Wenum_conversion, diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-1.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-1.c new file mode 100644 index 00000000000..d66d30d356f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-1.c @@ -0,0 +1,56 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// incompatible redeclarations, conflicing redefinitions + + +enum aa { A = 1 } *a; +enum bb { B = 1 } *b; + +void test(void) +{ + enum aa { A = 1 } *c = a; + enum bb { B = 2 } *d = b; /* { dg-warning "incompatible pointer type" } */ +} + +enum cc { C = 1 }; +enum cc { D = 1 }; /* { dg-error "conflicting redefinition" } */ + +enum dd { E = 1 }; +enum dd { E = 2 }; /* { dg-error "conflicting redefinition" } */ + /* { dg-error "redeclaration of enumerator" "" { target *-*-* } .-1 } */ + + + +void test2(void) +{ + enum ee *a; + enum ee { F = 2 } *b; + b = a; +} + + +enum ff { G = 2 }; +enum gg { G = 2 }; /* { dg-error "redeclaration of enumerator" } */ +enum g2 { G = 3 }; /* { dg-error "redeclaration of enumerator" } */ + +enum hh { H = 1, H = 1 }; /* { dg-error "redeclaration of enumerator" } */ + +enum ss { K = 2 }; +enum ss { K = 2 }; + +enum tt { R = 2 } TT; +enum tt { + R = _Generic(&TT, enum tt*: 0, default: 2) +}; + +enum { U = 1 }; +enum { U = 1 }; /* { dg-error "redeclaration of enumerator" } */ + +enum { V = 1 }; +enum { V = 2 }; /* { dg-error "redeclaration of enumerator" } */ + + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-2.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-2.c new file mode 100644 index 00000000000..bbe872c1480 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-2.c @@ -0,0 +1,23 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// incomplete during construction + +enum A { B = 7 } y; +enum A { B = 7 }; + +enum A { B = _Generic(&y, enum A*: 1, default: 7) }; + +void g(void) +{ + enum A { B = _Generic(&y, enum A*: 1, default: 7) }; + _Static_assert(7 == B, ""); +} + +enum X { E = 1, F = 1 + 1 }; +enum X { F = 2, E = 1 }; + + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-3.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-3.c new file mode 100644 index 00000000000..6f65bb73ef6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-3.c @@ -0,0 +1,7 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } + */ + +enum A { N = 0 * sizeof(enum A { M = 1 }) }; /* { dg-error "nested" } */ + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-4.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-4.c new file mode 100644 index 00000000000..413b1fe8110 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-4.c @@ -0,0 +1,22 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// fixed underlying types + +enum A : int { N = 1 } x1 = { }; +enum B : int { M = 1 } x2 = { }; +enum C { U = 1 } x3 = { }; + +void f(void) +{ + enum A : int { N = 1 } y1 = x1; + enum B : short { M = 1 } y2; + y2 = x2; + enum B : short { M = 1 } y2b; + enum Bb : short { V = 1 } y2d = x2; + enum B : short { M = 1 } *y2e = &x2; /* { dg-warning "incompatible" } */ + enum B : short { M = 1 } y2c = x2; + enum C { U = 1 } y3 = x3; +} + -- 2.30.2
[C PATCH 4/6] c23: tag compatibility rules for enums
Martin Uecker via Gcc-patches Sat, 26 Aug 2023 09:24:17 -0700
- c23 type compatibility rules, v2 Martin Uecker via Gcc-patches
- [C PATCH 1/6] c: reorganize recursive ... Martin Uecker via Gcc-patches
- [C PATCH 2/6] c23: recursive type check... Martin Uecker via Gcc-patches
- [C PATCH 3/6] c23: tag compatibility ru... Martin Uecker via Gcc-patches
- [C PATCH 4/6] c23: tag compatibility ru... Martin Uecker via Gcc-patches
- [C PATCH 5/6] c23: aliasing of compatib... Martin Uecker via Gcc-patches
- [C PATCH 6/6] c23: construct composite ... Martin Uecker via Gcc-patches
- [C PATCH] c: flag for tag compatibility... Martin Uecker via Gcc-patches