@@ -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);
@@ -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,
new file mode 100644
@@ -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" } */
+
+
+
new file mode 100644
@@ -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 };
+
+
+
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile }
+ * { dg-options "-std=c2x" }
+ */
+
+enum A { N = 0 * sizeof(enum A { M = 1 }) }; /* { dg-error "nested" } */
+
+
new file mode 100644
@@ -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;
+}
+