public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, CFE] N2863: Improved Rules for Tag Compatibility
@ 2022-06-07  9:26 Martin Uecker
  2022-06-07 14:22 ` Joseph Myers
  0 siblings, 1 reply; 3+ messages in thread
From: Martin Uecker @ 2022-06-07  9:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Joseph Myers


Hello Joseph and all,


here is a preliminary patch the implements the proposed
tag compatibility rules for C23 in GCC (N2863). It works
by tweaking the diagnostics in the FE and by recording
structs/union types to be able to set TYPE_CANONICAL to
a canonical definition (as per previous discussions).

 
Overall, this seems to work very well when testing
on my own projects. There are still some issues
left that I want to point out:

- at the moment, all struct/union types are collected
in a vector. This needs to be replaced by a hash table.

- the feature has a flag (-ftag-compat) which is now turned
on by default in all language modes to facilitate testing
and to identify backwards compatibility problems. Turned on,
it survives bootstrapping and regression testing with
only a few cases that test for diagnostics that go
away changed to turn it off.

- The new rules are not applied to structs with variable
sized members (which are a GNU extension).

- In contrast to the published proposal, structs without
tags are now treated as incompatible as requested by WG14.

- There is still one assertion in ipa-free-lang-data I had
to conditionally turn off and did not have time to 
investigate.  Otherwise, there are only C FE changes.
LTO may still need some more testing.

- It fixes some bugs in (formerly) unused FE code
and removes some other dead code. This could be
moved into its own patch.

- If adopted into C, I assume we need some
compatibility warnings. From testing, I could
not identify any backwards compatibility problems.

- There are certainly some issues I may have
overlooked.


Martin


gcc/
* c-family/c.opt: Add -ftag-compat flag.
* c/c-decl.cc (pop_scope): Remove dead code. 
(diagnose_mismatched_decls): Support for 
new tag compatibility rules.
(start_struct): Dito.
(finish_struct): Dito.
(start_enum): Dito.
(finish_enum): Dito.
(build_enumerator): Pass enumtype to build_decl.
(c_simulate_enum_decl): Pass enumtype to 
build_enumerator.
* c/c-parser.cc (c_parser_enum_specifier): Dito.
* c/c-tree.h (build_enumerator): Add enumtype 
argument.
* c/c-typeck.cc (comptypes_internal): Support
for new tag compatibility rules.
(same_translation_unit_p): Removed.
(tagged_types_tu_compatible_p): Bug fixes and
support for new tag compatibility rules.
(convert_for_assignment): Support for new tag
compatibility rules
(digest_init): Dito.
* ipa-free-lang-data.cc (fld_incomplete_type_of):
Conditionally turn of assertion related to
TYPE_CANONICAL if -ftag-compat is on.
doc/
* invoke.texi: Document -ftag-compat flag.
testsuite/
* gcc.dg/asan/pr81460.c: Add -fno-tag-compat.
* gcc.dg/c99-tag-1.c: Add -fno-tag-compat.
* gcc.dg/c99-tag-2.c: Add -fno-tag-compat. 
* gcc.dg/decl-3.c: Add -fno-tag-compat.
* gcc.dg/enum-redef-1.c: Add -fno-tag-compat.
* gcc.dg/parm-incomplete-1.c: Add -fno-tag-compat.
* gcc.dg/pr17188-1.c: Add -fno-tag-compat.
* gcc.dg/pr18809-1.c: Add -pedantic-errors and
-fno-tag-compat.
* gcc.dg/pr27953.c: Add -fno-tag-compat.
* gcc.dg/pr39084.c: Add -fno-tag-compat.
* gcc.dg/pr68533.c: Add -fno-tag-compat.
* gcc.dg/pr79983.c: Add -fno-tag-compat.
* gcc.dg/pr89211.c: Add -fno-tag-compat.
* gcc.dg/tag-compat.c: New test.
* gcc.dg/tag-compat10.c: New test.
* gcc.dg/tag-compat11.c: New test.
* gcc.dg/tag-compat12.c: New test.
* gcc.dg/tag-compat2.c: New test.
* gcc.dg/tag-compat3.c: New test.
* gcc.dg/tag-compat4.c: New test.
* gcc.dg/tag-compat5.c: New test.
* gcc.dg/tag-compat6.c: New test.
* gcc.dg/tag-compat7.c: New test.
* gcc.dg/tag-compat8.c: New test.
* gcc.dg/tag-compat9.c: New test.
* gcc.dg/vla-11.c: Add -fno-tag-compat.
* gcc.dg/vla-stexp-2.c: Add -fno-tag-compat.



diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 41a20bc625e..cd3164018f2 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2108,6 +2108,9 @@ Enum(strong_eval_order) String(some) Value(1)
 EnumValue
 Enum(strong_eval_order) String(all) Value(2)
 
+ftag-compat
+C Var(flag_tag_compat) Init(1)
+
 ftemplate-backtrace-limit=
 C++ ObjC++ Joined RejectNegative UInteger
Var(template_backtrace_limit) Init(10)
 Set the maximum number of template instantiation notes for a single
warning or error.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 5266a61b859..df208a310f9 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -599,6 +599,10 @@ public:
   auto_vec<tree> typedefs_seen;
 };
 
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static auto_vec<tree> all_structs;
+
 /* Information for the struct or union currently being parsed, or
    NULL if not parsing a struct or union.  */
 static class c_struct_parse_info *struct_parse_info;
@@ -1354,8 +1358,8 @@ pop_scope (void)
 	      BLOCK_VARS (block) = extp;
 	    }
 	  /* If this is the file scope set DECL_CONTEXT of each decl
to
-	     the TRANSLATION_UNIT_DECL.  This makes
same_translation_unit_p
-	     work.  */
+	     the TRANSLATION_UNIT_DECL.  */
+
 	  if (scope == file_scope)
 	    {
 	      DECL_CONTEXT (p) = context;
@@ -1985,9 +1989,22 @@ 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_tag_compat && comptypes (TREE_TYPE (olddecl), TREE_TYPE
(newdecl)))
+	{
+	  if (!COMPLETE_TYPE_P (TREE_TYPE (olddecl))
+	      || !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;
     }
 
@@ -2238,7 +2255,7 @@ diagnose_mismatched_decls (tree newdecl, tree
olddecl,
 		 isn't overriding an extern inline reject the new
decl.
 		 In c99, no overriding is allowed in the same
translation
 		 unit.  */
-	      if ((!DECL_EXTERN_INLINE (olddecl)
+	      if (!DECL_EXTERN_INLINE (olddecl)
 		   || DECL_EXTERN_INLINE (newdecl)
 		   || (!flag_gnu89_inline
 		       && (!DECL_DECLARED_INLINE_P (olddecl)
@@ -2248,7 +2265,6 @@ diagnose_mismatched_decls (tree newdecl, tree
olddecl,
 			   || !lookup_attribute ("gnu_inline",
 						 DECL_ATTRIBUTES
(newdecl))))
 		  )
-		  && same_translation_unit_p (newdecl, olddecl))
 		{
 		  auto_diagnostic_group d;
 		  error ("redefinition of %q+D", newdecl);
@@ -3267,18 +3283,11 @@ pushdecl (tree x)
 	 type to the composite of all the types of that declaration.
 	 After the consistency checks, it will be reset to the
 	 composite of the visible types only.  */
-      if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b-
>decl))
-	  && b->u.type)
+      if (b && b->u.type)
 	TREE_TYPE (b->decl) = b->u.type;
 
-      /* The point of the same_translation_unit_p check here is,
-	 we want to detect a duplicate decl for a construct like
-	 foo() { extern bar(); } ... static bar();  but not if
-	 they are in different translation units.  In any case,
-	 the static does not go in the externals scope.  */
-      if (b
-	  && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
-	  && duplicate_decls (x, b->decl))
+      /* The static does not go in the externals scope.  */
+      if (b && duplicate_decls (x, b->decl))
 	{
 	  tree thistype;
 	  if (vistype)
@@ -8088,7 +8097,8 @@ get_parm_info (bool ellipsis, tree expr)
 	     (it's impossible to call such a function with type-
 	     correct arguments).  An anonymous union parm type is
 	     meaningful as a GNU extension, so don't warn for that. 
*/
-	  if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
+	  if (!flag_tag_compat
+	      && (TREE_CODE (decl) != UNION_TYPE || b->id !=
NULL_TREE))
 	    {
 	      if (b->id)
 		/* The %s will be one of 'struct', 'union', or 'enum'. 
*/
@@ -8288,6 +8298,12 @@ start_struct (location_t loc, enum tree_code
code, tree name,
 
   if (name != NULL_TREE)
     ref = lookup_tag (code, name, true, &refloc);
+
+  /* If we already have a completed definition, then
+     do not use it. We will check for consistency later */
+  if (flag_tag_compat && ref && TYPE_SIZE (ref))
+    ref = NULL_TREE;
+
   if (ref && TREE_CODE (ref) == code)
     {
       if (TYPE_STUB_DECL (ref))
@@ -8977,6 +8993,54 @@ finish_struct (location_t loc, tree t, tree
fieldlist, tree attributes,
       warning_at (loc, 0, "union cannot be made transparent");
     }
 
+  /* Check for consistency with previous definition */
+  if (flag_tag_compat)
+    {
+      struct c_binding *b = NULL;
+      tree name = TYPE_NAME (t);
+
+      if (name)
+	b = I_TAG_BINDING (name);
+
+      if (b)
+	b = b->shadowed;
+
+      if (b && B_IN_CURRENT_SCOPE (b))
+	{
+	  tree vistype = b->decl;
+	  bool different_types = false;
+
+	  if ((1 != comptypes_check_different_types(t, vistype,
&different_types))
+	      || different_types)
+	    warning_at(loc, 0, "redefinition of struct or union %qT",
vistype);
+	}
+    }
+
+  if (flag_tag_compat)
+    {
+      gcc_assert (t == TYPE_MAIN_VARIANT (t));
+      /* We treat structs with variable size as
+         incompatible with other structs.  */
+      if (C_TYPE_VARIABLE_SIZE (t))
+	TYPE_CANONICAL (t) = t;
+      else
+	{
+	  unsigned int i;
+	  tree t2 = NULL_TREE;
+	   FOR_EACH_VEC_ELT (all_structs, i, t2)
+	  if (comptypes (t, t2))
+	    break;
+
+	  if (t2 != NULL_TREE)
+	    TYPE_CANONICAL (t) = t2;
+	  else
+	    {
+	      TYPE_CANONICAL (t) = t;
+	      all_structs.safe_push (t);
+	    }
+	 }
+    }
+
   tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT
(t));
   for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
     {
@@ -8987,6 +9051,7 @@ finish_struct (location_t loc, tree t, tree
fieldlist, tree attributes,
       C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
       C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
       C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE;
+      TYPE_CANONICAL (x) = TYPE_CANONICAL (t);
     }
 
   /* Update type location to the one of the definition, instead of
e.g.
@@ -8994,6 +9059,7 @@ finish_struct (location_t loc, tree t, tree
fieldlist, tree attributes,
   if (TYPE_STUB_DECL (t))
     DECL_SOURCE_LOCATION (TYPE_STUB_DECL (t)) = loc;
 
+
   /* Finish debugging output for this type.  */
   rest_of_type_compilation (t, toplevel);
 
@@ -9100,9 +9166,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_tag_compat && 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);
     }
   /* Update type location to the one of the definition, instead of
e.g.
@@ -9311,6 +9383,31 @@ finish_enum (tree enumtype, tree values, tree
attributes)
 
   C_TYPE_BEING_DEFINED (enumtype) = 0;
 
+  /* Check for consistency with previous definition */
+
+  if (flag_tag_compat)
+    {
+      struct c_binding *b = NULL;
+      tree name = TYPE_NAME (enumtype);
+
+      if (name)
+	b = I_TAG_BINDING (name);
+
+      if (b)
+	b = b->shadowed;
+
+      if (b && B_IN_CURRENT_SCOPE (b))
+	{
+	  tree vistype = b->decl;
+	  bool different_types = false;
+
+	  if ((1 != comptypes_check_different_types(enumtype, vistype,
&different_types))
+	      || different_types)
+	    {
+	       warning(0, "conflicting redefinition of enum %qT",
vistype);
+	    }
+	}
+    }
   return enumtype;
 }
 
@@ -9322,7 +9419,7 @@ finish_enum (tree enumtype, tree values, tree
attributes)
    Assignment of sequential values by default is handled here.  */
 
 tree
-build_enumerator (location_t decl_loc, location_t loc,
+build_enumerator (location_t decl_loc, location_t loc, tree enumtype,
 		  struct c_enum_contents *the_enum, tree name, tree
value)
 {
   tree decl, type;
@@ -9409,7 +9506,7 @@ build_enumerator (location_t decl_loc, location_t
loc,
 				  >= TYPE_PRECISION
(integer_type_node)
 				  && TYPE_UNSIGNED (type)));
 
-  decl = build_decl (decl_loc, CONST_DECL, name, type);
+  decl = build_decl (decl_loc, CONST_DECL, name, enumtype);
   DECL_INITIAL (decl) = convert (type, value);
   pushdecl (decl);
 
@@ -9434,7 +9531,7 @@ c_simulate_enum_decl (location_t loc, const char
*name,
   unsigned int i;
   FOR_EACH_VEC_ELT (values, i, value)
     {
-      tree decl = build_enumerator (loc, loc, &the_enum,
+      tree decl = build_enumerator (loc, loc, enumtype, &the_enum,
 				    get_identifier (value->first),
 				    build_int_cst (integer_type_node,
 						   value->second));
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 8df8f60ef21..40cb5bbbff4 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -3231,7 +3231,7 @@ c_parser_enum_specifier (c_parser *parser)
 	    }
 	  else
 	    enum_value = NULL_TREE;
-	  enum_decl = build_enumerator (decl_loc, value_loc,
+	  enum_decl = build_enumerator (decl_loc, value_loc, type,
 					&the_enum, enum_id,
enum_value);
 	  if (enum_attrs)
 	    decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs,
0);
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 2bcb9662620..e1cd86cfda7 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -578,7 +578,7 @@ extern int quals_from_declspecs (const struct
c_declspecs *);
 extern struct c_declarator *build_array_declarator (location_t, tree,
     						    struct c_declspecs
*,
 						    bool, bool);
-extern tree build_enumerator (location_t, location_t, struct
c_enum_contents *,
+extern tree build_enumerator (location_t, location_t, tree, struct
c_enum_contents *,
 			      tree, tree);
 extern tree check_for_loop_decls (location_t, bool);
 extern void mark_forward_parm_decls (void);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 4f3611f1b89..5c5fede0bdd 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1256,11 +1256,16 @@ comptypes_internal (const_tree type1,
const_tree type2, bool *enum_and_int_p,
     case ENUMERAL_TYPE:
     case RECORD_TYPE:
     case UNION_TYPE:
-      if (val != 1 && !same_translation_unit_p (t1, t2))
+      if (flag_tag_compat)
 	{
 	  tree a1 = TYPE_ATTRIBUTES (t1);
 	  tree a2 = TYPE_ATTRIBUTES (t2);
 
+	  if (ENUMERAL_TYPE != TREE_CODE (t1)
+	      && (TYPE_REVERSE_STORAGE_ORDER (t1)
+		  != TYPE_REVERSE_STORAGE_ORDER (t2)))
+	    return 0;
+
 	  if (! attribute_list_contained (a1, a2)
 	      && ! attribute_list_contained (a2, a1))
 	    break;
@@ -1344,41 +1349,6 @@ comp_target_types (location_t location, tree
ttl, tree ttr)
 \f
 /* Subroutines of `comptypes'.  */
 
-/* Determine whether two trees derive from the same translation unit.
-   If the CONTEXT chain ends in a null, that tree's context is still
-   being parsed, so if two trees have context chains ending in null,
-   they're in the same translation unit.  */
-
-bool
-same_translation_unit_p (const_tree t1, const_tree t2)
-{
-  while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
-    switch (TREE_CODE_CLASS (TREE_CODE (t1)))
-      {
-      case tcc_declaration:
-	t1 = DECL_CONTEXT (t1); break;
-      case tcc_type:
-	t1 = TYPE_CONTEXT (t1); break;
-      case tcc_exceptional:
-	t1 = BLOCK_SUPERCONTEXT (t1); break;  /* assume block */
-      default: gcc_unreachable ();
-      }
-
-  while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL)
-    switch (TREE_CODE_CLASS (TREE_CODE (t2)))
-      {
-      case tcc_declaration:
-	t2 = DECL_CONTEXT (t2); break;
-      case tcc_type:
-	t2 = TYPE_CONTEXT (t2); break;
-      case tcc_exceptional:
-	t2 = BLOCK_SUPERCONTEXT (t2); break;  /* assume block */
-      default: gcc_unreachable ();
-      }
-
-  return t1 == t2;
-}
-
 /* Allocate the seen two types, assuming that they are compatible. */
 
 static struct tagged_tu_seen_cache *
@@ -1457,6 +1427,12 @@ tagged_types_tu_compatible_p (const_tree t1,
const_tree t2,
   if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2))
     return 0;
 
+  if (flag_tag_compat
+      && (NULL_TREE == TYPE_NAME (t1)
+	  || NULL_TREE == TYPE_NAME (t2)
+	  || TYPE_NAME (t1) != TYPE_NAME (t2)))
+     return 0;
+
   /* C90 didn't say what happened if one or both of the types were
      incomplete; we choose to follow C99 rules here, which is that
they
      are compatible.  */
@@ -1606,7 +1582,7 @@ tagged_types_tu_compatible_p (const_tree t1,
const_tree t2,
 		return 0;
 	      }
 	  }
-	tu->val = needs_warning ? 2 : 10;
+	tu->val = needs_warning ? 2 : 1;
 	return tu->val;
       }
 
@@ -1614,6 +1590,12 @@ tagged_types_tu_compatible_p (const_tree t1,
const_tree t2,
       {
 	struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache
(t1, t2);
 
+	if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS
(t2)))
+	  {
+	    tu->val = 0;
+	    return 0;
+	  }
+
 	for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
 	     s1 && s2;
 	     s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
@@ -7046,10 +7028,12 @@ convert_for_assignment (location_t location,
location_t expr_loc, tree type,
 
   /* Aggregates in different TUs might need conversion.  */
   if ((codel == RECORD_TYPE || codel == UNION_TYPE)
-      && codel == coder
-      && comptypes (type, rhstype))
-    return convert_and_check (expr_loc != UNKNOWN_LOCATION
+      && codel == coder)
+    {
+      if (comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT
(rhstype)))
+	return convert_and_check (expr_loc != UNKNOWN_LOCATION
 			      ? expr_loc : location, type, rhs);
+    }
 
   /* Conversion to a transparent union or record from its member
types.
      This applies only to function arguments.  */
@@ -8159,6 +8143,15 @@ digest_init (location_t init_loc, tree type,
tree init, tree origtype,
 	   conversion.  */
 	inside_init = convert (type, inside_init);
 
+      if (code == RECORD_TYPE || code == UNION_TYPE)
+	{
+	  if (!comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT
(TREE_TYPE (inside_init))))
+	    {
+	      error_init (init_loc, "invalid initializer %qT %qT",
type, TREE_TYPE (inside_init));
+	      return error_mark_node;
+	    }
+	}
+
       if (require_constant
 	  && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
 	{
@@ -10190,7 +10183,7 @@ initialize_elementwise_p (tree type, tree
value)
     return !VECTOR_TYPE_P (value_type);
 
   if (AGGREGATE_TYPE_P (type))
-    return type != TYPE_MAIN_VARIANT (value_type);
+      return !comptypes (type, TYPE_MAIN_VARIANT (value_type));
 
   return false;
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d8095e3128f..fdbe625b389 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -2832,6 +2832,11 @@ the target (the default).  This option is not
supported for C++.
 @strong{Warning:} the @option{-fsso-struct} switch causes GCC to
generate
 code that is not binary compatible with code generated without it if
the
 specified endianness is not the native endianness of the target.
+
+@item -ftag-compat
+@opindex ftag-compat
+This option makes tagged types that are structurally equivalent
compatible
+and allows identical redeclarations of tagged types in the same scope.
 @end table
 
 @node C++ Dialect Options
diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc
index f99f7be1c58..dc533fe43f6 100644
--- a/gcc/ipa-free-lang-data.cc
+++ b/gcc/ipa-free-lang-data.cc
@@ -254,8 +254,9 @@ fld_incomplete_type_of (tree t, class
free_lang_data_d *fld)
 	  else
 	    first = build_reference_type_for_mode (t2, TYPE_MODE (t),
 						  
TYPE_REF_CAN_ALIAS_ALL (t));
-	  gcc_assert (TYPE_CANONICAL (t2) != t2
-		      && TYPE_CANONICAL (t2) == TYPE_CANONICAL
(TREE_TYPE (t)));
+	  gcc_assert (flag_tag_compat
+		      || (TYPE_CANONICAL (t2) != t2
+			  && TYPE_CANONICAL (t2) == TYPE_CANONICAL
(TREE_TYPE (t))));
 	  if (!fld->pset.add (first))
 	    add_tree_to_fld_list (first, fld);
 	  return fld_type_variant (first, t, fld);
diff --git a/gcc/testsuite/gcc.dg/asan/pr81460.c
b/gcc/testsuite/gcc.dg/asan/pr81460.c
index 00c1bb7c9f2..98ea40edb56 100644
--- a/gcc/testsuite/gcc.dg/asan/pr81460.c
+++ b/gcc/testsuite/gcc.dg/asan/pr81460.c
@@ -1,5 +1,6 @@
 /* PR sanitizer/80460 */
 /* { dg-do compile } */
+/* { dg-options "-fno-tag-compat" } */
 
 int
 f (int a, struct { int b[a]; } c) /* { dg-warning "anonymous struct
declared inside parameter list will not be visible outside of this
definition or declaration" } */
diff --git a/gcc/testsuite/gcc.dg/c99-tag-1.c
b/gcc/testsuite/gcc.dg/c99-tag-1.c
index d7011d2cbec..1b52234ee3f 100644
--- a/gcc/testsuite/gcc.dg/c99-tag-1.c
+++ b/gcc/testsuite/gcc.dg/c99-tag-1.c
@@ -1,7 +1,7 @@
 /* Test for handling of tags (6.7.2.3).  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 /* { dg-do compile } */
-/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors -fno-tag-compat" }
*/
 
 void
 foo (void)
diff --git a/gcc/testsuite/gcc.dg/c99-tag-2.c
b/gcc/testsuite/gcc.dg/c99-tag-2.c
index 22cf90e27d3..b12c7bcd964 100644
--- a/gcc/testsuite/gcc.dg/c99-tag-2.c
+++ b/gcc/testsuite/gcc.dg/c99-tag-2.c
@@ -2,7 +2,7 @@
    not match one declared in an outer scope.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors -fno-tag-compat" }
*/
 
 struct s;
 struct t { struct s *p; } x;
diff --git a/gcc/testsuite/gcc.dg/decl-3.c b/gcc/testsuite/gcc.dg/decl-
3.c
index cba0b906db3..66204270337 100644
--- a/gcc/testsuite/gcc.dg/decl-3.c
+++ b/gcc/testsuite/gcc.dg/decl-3.c
@@ -1,5 +1,6 @@
 /* PR c/9928 */
 /* { dg-do compile } */
+/* { dg-options "-fno-tag-compat" } */
 
 enum { CODES }; /* { dg-message "note: previous definition" } */
 enum { CODES }; /* { dg-error "conflicting types|redeclaration of
enumerator" } */
diff --git a/gcc/testsuite/gcc.dg/enum-redef-1.c
b/gcc/testsuite/gcc.dg/enum-redef-1.c
index b3fa6cbf8f1..837992f7441 100644
--- a/gcc/testsuite/gcc.dg/enum-redef-1.c
+++ b/gcc/testsuite/gcc.dg/enum-redef-1.c
@@ -1,3 +1,5 @@
+/* { dg-options "-fno-tag-compat" } */
+
 enum a { A };
 enum a { B }; /* { dg-bogus "nested redefinition" } */
 /* { dg-error "redeclaration of 'enum a'" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/parm-incomplete-1.c
b/gcc/testsuite/gcc.dg/parm-incomplete-1.c
index 02d97b933f4..fa001d16662 100644
--- a/gcc/testsuite/gcc.dg/parm-incomplete-1.c
+++ b/gcc/testsuite/gcc.dg/parm-incomplete-1.c
@@ -6,7 +6,7 @@
    C99 6.7.5.3); the precise rules are unclear.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-fno-tag-compat" } */
 
 struct s;
 void f (struct s);
diff --git a/gcc/testsuite/gcc.dg/pr17188-1.c
b/gcc/testsuite/gcc.dg/pr17188-1.c
index 522a14f7d75..bb31ba30b5d 100644
--- a/gcc/testsuite/gcc.dg/pr17188-1.c
+++ b/gcc/testsuite/gcc.dg/pr17188-1.c
@@ -3,7 +3,7 @@
    diagnosed.  Bug 17188.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-fno-tag-compat" } */
 
 struct s0 { }; /* { dg-message "note: originally defined here" } */
 struct s0;
diff --git a/gcc/testsuite/gcc.dg/pr18809-1.c
b/gcc/testsuite/gcc.dg/pr18809-1.c
index 5be41809da6..d7f55feae61 100644
--- a/gcc/testsuite/gcc.dg/pr18809-1.c
+++ b/gcc/testsuite/gcc.dg/pr18809-1.c
@@ -1,6 +1,7 @@
 /* PR c/18809 */
 /* Origin: Andrew Pinski <pinskia@gcc.gnu.org> */
 
+/* { dg-options "-pedantic-errors -fno-tag-compat" } */
 /* { dg-do compile } */
 
 void foo(enum E e) {}   /* { dg-error "forward ref" "forward" } */
diff --git a/gcc/testsuite/gcc.dg/pr27953.c
b/gcc/testsuite/gcc.dg/pr27953.c
index 99ae0a3aa83..45710f722ab 100644
--- a/gcc/testsuite/gcc.dg/pr27953.c
+++ b/gcc/testsuite/gcc.dg/pr27953.c
@@ -1,4 +1,5 @@
 /* PR c/27953 */
+/* { dg-options "-fno-tag-compat" } */
 
 void foo(struct A a) {} /* { dg-line foo_first } */
 /* { dg-warning "declared inside parameter list" "inside" { target *-
*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr39084.c
b/gcc/testsuite/gcc.dg/pr39084.c
index ff731492154..776fbea6750 100644
--- a/gcc/testsuite/gcc.dg/pr39084.c
+++ b/gcc/testsuite/gcc.dg/pr39084.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fno-tag-compat" } */
 
 struct color { int i; }; /* { dg-message "note: originally defined
here" } */
 static const struct color col;
diff --git a/gcc/testsuite/gcc.dg/pr68533.c
b/gcc/testsuite/gcc.dg/pr68533.c
index 49e67a96168..89c03998fdf 100644
--- a/gcc/testsuite/gcc.dg/pr68533.c
+++ b/gcc/testsuite/gcc.dg/pr68533.c
@@ -1,6 +1,6 @@
 /* PR c/68533 */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-fno-tag-compat" } */
 
 struct T { int t; };
 
diff --git a/gcc/testsuite/gcc.dg/pr79983.c
b/gcc/testsuite/gcc.dg/pr79983.c
index 1e292d42108..c9fe72f9169 100644
--- a/gcc/testsuite/gcc.dg/pr79983.c
+++ b/gcc/testsuite/gcc.dg/pr79983.c
@@ -1,6 +1,6 @@
 /* PR c/79983 */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-fno-tag-compat" } */
 
 struct S;
 struct S { int i; }; /* { dg-message "originally defined here" } */
diff --git a/gcc/testsuite/gcc.dg/pr89211.c
b/gcc/testsuite/gcc.dg/pr89211.c
index cf721aa5f62..e2d40aaaf91 100644
--- a/gcc/testsuite/gcc.dg/pr89211.c
+++ b/gcc/testsuite/gcc.dg/pr89211.c
@@ -1,5 +1,6 @@
 /* PR c/89211 */
 /* { dg-do compile } */
+/* { dg-options "-fno-tag-compat" } */
 
 void foo ();
 void foo ()
diff --git a/gcc/testsuite/gcc.dg/tag-compat.c
b/gcc/testsuite/gcc.dg/tag-compat.c
new file mode 100644
index 00000000000..54869ea189f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat.c
@@ -0,0 +1,32 @@
+/*
+ * { dg-do run }
+ * { dg-options "-ftag-compat" }
+ */
+
+#define product_type(T, A, B) \
+struct product_ ## T { A a ; B b ; }
+#define sum_type(T, A, B) \
+struct sum_ ## T { _Bool flag ; union { A a ; B b ; } ; }
+
+float foo1(product_type(iSfd_, int, sum_type(fd, float, double)) x) 
+{
+	return x.b.a;
+}
+
+static void test1(void)
+{
+	product_type(iSfd_, int, sum_type(fd, float, double)) y = { 3,
{ 1, { .a = 1. } } };
+	product_type(iSfd_, int, sum_type(fd, float, double)) z = y;
+	product_type(iSfd_, int, sum_type(fd, float, double)) *zp =
&y;
+	float a = foo1(y);
+	product_type(iSid_, int, sum_type(id, int, double)) *wp = &y;
/* { dg-warning "incompatible pointer type" } */
+	float b = foo1(y);
+	product_type(iSid_, int, sum_type(id, int, double)) w = *wp;
+	(void)a; (void)b; (void)z; (void)zp; (void)w; (void)wp;
+}
+
+int main()
+{
+	test1();
+}
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat10.c
b/gcc/testsuite/gcc.dg/tag-compat10.c
new file mode 100644
index 00000000000..535793f6f6c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat10.c
@@ -0,0 +1,15 @@
+/*
+ * { dg-do compile }
+ * { dg-options "-ftag-compat" }
+ */
+
+
+extern struct __attribute__(( aligned (16) )) foo { int x; } x;
+extern struct bar { float x; } y;
+
+void test(void)
+{
+  extern struct __attribute__(( aligned (8) )) foo { int x; }
x;	/* { dg-error "conflicting types" } */
+  extern struct bar { int x; }
y;					/* { dg-error "conflicting types" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat11.c
b/gcc/testsuite/gcc.dg/tag-compat11.c
new file mode 100644
index 00000000000..a83e6efb699
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat11.c
@@ -0,0 +1,10 @@
+/*
+ * { dg-do compile }
+ * { dg-options "-ftag-compat" }
+ */
+
+
+extern struct { int x; } a;
+extern struct { int x; } a;	/* { dg-error "conflicting types" } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat12.c
b/gcc/testsuite/gcc.dg/tag-compat12.c
new file mode 100644
index 00000000000..f605b24267a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat12.c
@@ -0,0 +1,76 @@
+/*
+ * { dg-do run }
+ * { dg-options "-ftag-compat -O2" }
+ */
+
+
+typedef struct { int x; } foo_t;
+
+int test_foo(foo_t* a, void* b)
+{
+	a->x = 1;
+
+	struct { int x; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+
+struct bar { int x; int f[]; };
+
+int test_bar1(struct bar* a, void* b)
+{
+	a->x = 1;
+
+	struct bar { int x; int f[]; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+int test_bar2(struct bar* a, void* b)
+{
+	a->x = 1;
+
+	struct bar { int x; int f[0]; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+int test_bar3(struct bar* a, void* b)
+{
+	a->x = 1;
+
+	struct bar { int x; int f[1]; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+
+
+int main()
+{
+	foo_t y;
+
+	// this works, but is not guaranteed by C
+	if (2 == test_foo(&y, &y))
+		__builtin_abort();
+
+	struct bar z;
+
+	if (2 != test_bar1(&z, &z))
+		__builtin_abort();
+
+	if (2 != test_bar2(&z, &z))
+		__builtin_abort();
+
+	if (2 == test_bar3(&z, &z))
+		__builtin_abort();
+	
+	return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat2.c
b/gcc/testsuite/gcc.dg/tag-compat2.c
new file mode 100644
index 00000000000..20dc1a9c894
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat2.c
@@ -0,0 +1,47 @@
+/*
+ * { dg-do compile }
+ * { dg-options "-ftag-compat" }
+ */
+
+typedef struct bar { int x; } X;
+typedef struct bar { float x; } Y; /* { dg-warning "redefinition of
struct or union" } */
+
+void test(void)
+{
+	struct foo { int x; };
+	struct foo { float x; }; /* { dg-warning "redefinition of
struct or union" } */
+}
+
+struct aa { int a; };
+
+void f(void)
+{
+	typedef struct aa A;
+	struct bb { struct aa a; } x;
+	struct aa { int a; };
+	typedef struct aa A;
+	struct bb { struct aa a; } y;
+	(void)x; (void)y;
+}
+
+
+union cc { int x; float y; } z;
+union cc { int x; float y; } z1;
+union cc { float y; int x; } z2;
+
+
+
+
+
+void g(void)
+{
+	struct s { int a; };
+	struct s { int a; } x0;
+	struct p { struct s c; } y1 = { x0 };
+	struct p { struct s { int a; } c; } y = { x0 };
+}
+
+
+
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat3.c
b/gcc/testsuite/gcc.dg/tag-compat3.c
new file mode 100644
index 00000000000..5cbee4c9f38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat3.c
@@ -0,0 +1,49 @@
+/*
+ * { dg-do compile }
+ * { dg-options "-ftag-compat" }
+ */
+
+
+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-warning "conflicting
redefinition" } */	
+
+enum dd { E = 1 };
+enum dd { E = 2 };		/* { dg-warning "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*: 2, default: 0)
+};
+
+
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat4.c
b/gcc/testsuite/gcc.dg/tag-compat4.c
new file mode 100644
index 00000000000..3d48767d7e0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat4.c
@@ -0,0 +1,29 @@
+/*
+ * { dg-do compile }
+ * { dg-options "-ftag-compat" }
+ */
+
+
+typedef struct p { int a; } pd_t;
+typedef struct p { int a; } pd_t;
+
+
+void test1(void)
+{
+  pd_t y0;
+  struct p { int a; } x;
+  y0 = x;
+}
+
+void test2(void)
+{
+  struct p { int a; } x;
+  struct p y0 = x;
+}
+
+void test3(void)
+{
+  struct p { int a; } x;
+  pd_t y0 = x;
+}
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat5.c
b/gcc/testsuite/gcc.dg/tag-compat5.c
new file mode 100644
index 00000000000..feeaeb78f57
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat5.c
@@ -0,0 +1,15 @@
+/*
+ * { dg-do compile }
+ * { dg-options "-ftag-compat" }
+ */
+
+
+extern struct foo { int x; } x;
+extern struct bar { float x; } y;
+
+void test(void)
+{
+  extern struct foo { int x; } x;
+  extern struct bar { int x; } y;	/* { dg-error "conflicting
types" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat6.c
b/gcc/testsuite/gcc.dg/tag-compat6.c
new file mode 100644
index 00000000000..98ebab7f33d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat6.c
@@ -0,0 +1,48 @@
+/*
+ * { dg-do run }
+ * { dg-options "-ftag-compat -O2" }
+ */
+
+
+struct foo { int x; };
+
+int test_foo(struct foo* a, void* b)
+{
+	a->x = 1;
+
+	struct foo { int x; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+
+enum bar { A = 1, B = 3 };
+
+int test_bar(enum bar* a, void* b)
+{
+	*a = A;
+
+	enum bar { A = 1, B = 3 }* p = b;
+	*p = B;
+
+	return *a;
+}
+
+
+int main()
+{
+	struct foo y;
+
+	if (2 != test_foo(&y, &y))
+		__builtin_abort();
+
+	enum bar z;
+
+	if (A == test_bar(&z, &z))
+		__builtin_abort();
+
+	return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat7.c
b/gcc/testsuite/gcc.dg/tag-compat7.c
new file mode 100644
index 00000000000..e3550fcfee7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat7.c
@@ -0,0 +1,73 @@
+/*
+ * { dg-do run }
+ * { dg-options "-ftag-compat -O2" }
+ */
+
+
+struct foo { int x; };
+
+int test_foo1(struct foo* a, void* b)
+{
+	a->x = 1;
+
+	struct foo { int x; int y; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+int test_foo2(struct foo* a, void* b)
+{
+	a->x = 1;
+
+	struct fox { int x; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+enum bar { A = 1, B = 3, C = 5, D = 9 };
+
+int test_bar1(enum bar* a, void* b)
+{
+	*a = A;
+
+	enum bar { A = 1, B = 3, C = 6, D = 9 }* p = b;
+	*p = B;
+
+	return *a;
+}
+
+int test_bar2(enum bar* a, void* b)
+{
+	*a = A;
+
+	enum baX { A = 1, B = 3, C = 5, D = 9 }* p = b;
+	*p = B;
+
+	return *a;
+}
+
+
+int main()
+{
+	struct foo y;
+
+	if (1 != test_foo1(&y, &y))
+		__builtin_abort();
+
+	if (1 != test_foo2(&y, &y))
+		__builtin_abort();
+
+	enum bar z;
+
+	if (A == test_bar1(&z, &z))
+		__builtin_abort();
+
+	if (A == test_bar2(&z, &z))
+		__builtin_abort();
+
+	return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat8.c
b/gcc/testsuite/gcc.dg/tag-compat8.c
new file mode 100644
index 00000000000..210cb39839a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat8.c
@@ -0,0 +1,48 @@
+/*
+ * { dg-do run }
+ * { dg-options "-ftag-compat -flto -O2" }
+ */
+
+
+struct foo { int x; };
+
+int test_foo(struct foo* a, void* b)
+{
+	a->x = 1;
+
+	struct foo { int x; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+
+enum bar { A = 1, B = 3 };
+
+int test_bar(enum bar* a, void* b)
+{
+	*a = A;
+
+	enum bar { A = 1, B = 3 }* p = b;
+	*p = B;
+
+	return *a;
+}
+
+
+int main()
+{
+	struct foo y;
+
+	if (2 != test_foo(&y, &y))
+		__builtin_abort();
+
+	enum bar z;
+
+	if (A == test_bar(&z, &z))
+		__builtin_abort();
+
+	return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/tag-compat9.c
b/gcc/testsuite/gcc.dg/tag-compat9.c
new file mode 100644
index 00000000000..5bf5dd5fe4f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tag-compat9.c
@@ -0,0 +1,73 @@
+/*
+ * { dg-do run }
+ * { dg-options "-ftag-compat -flto -O2" }
+ */
+
+
+struct foo { int x; };
+
+int test_foo1(struct foo* a, void* b)
+{
+	a->x = 1;
+
+	struct foo { int x; int y; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+int test_foo2(struct foo* a, void* b)
+{
+	a->x = 1;
+
+	struct fox { int x; }* p = b;
+	p->x = 2;
+
+	return a->x;
+}
+
+enum bar { A = 1, B = 3, C = 5, D = 9 };
+
+int test_bar1(enum bar* a, void* b)
+{
+	*a = A;
+
+	enum bar { A = 1, B = 3, C = 6, D = 9 }* p = b;
+	*p = B;
+
+	return *a;
+}
+
+int test_bar2(enum bar* a, void* b)
+{
+	*a = A;
+
+	enum baX { A = 1, B = 3, C = 5, D = 9 }* p = b;
+	*p = B;
+
+	return *a;
+}
+
+
+int main()
+{
+	struct foo y;
+
+	if (1 != test_foo1(&y, &y))
+		__builtin_abort();
+
+	if (1 != test_foo2(&y, &y))
+		__builtin_abort();
+
+	enum bar z;
+
+	if (A == test_bar1(&z, &z))
+		__builtin_abort();
+
+	if (A == test_bar2(&z, &z))
+		__builtin_abort();
+
+	return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/vla-11.c b/gcc/testsuite/gcc.dg/vla-
11.c
index 1504853a55a..982383a980a 100644
--- a/gcc/testsuite/gcc.dg/vla-11.c
+++ b/gcc/testsuite/gcc.dg/vla-11.c
@@ -4,7 +4,7 @@
    these cases).  */
 /* Origin: Joseph Myers <joseph@codesourcery.com> */
 /* { dg-do compile } */
-/* { dg-options "-std=c99 -pedantic-errors" } */
+/* { dg-options "-std=c99 -pedantic-errors -fno-tag-compat" } */
 
 void foo11a(int x[sizeof(int *(*)[*])]);	/* { dg-warning "not
in a declaration" } */
 void foo11b(__SIZE_TYPE__ x, int y[(__UINTPTR_TYPE__)(int
(*)[*])x]);	/* { dg-warning "not in a declaration" } */
diff --git a/gcc/testsuite/gcc.dg/vla-stexp-2.c
b/gcc/testsuite/gcc.dg/vla-stexp-2.c
index 9f1512567f0..555c31d2a47 100644
--- a/gcc/testsuite/gcc.dg/vla-stexp-2.c
+++ b/gcc/testsuite/gcc.dg/vla-stexp-2.c
@@ -1,6 +1,6 @@
 /* PR101838 */
 /* { dg-do run } */
-/* { dg-options "-Wpedantic -O0" } */
+/* { dg-options "-Wpedantic -O0 -fno-tag-compat" } */
 /* { dg-require-effective-target alloca } */
 
 





^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH, CFE] N2863: Improved Rules for Tag Compatibility
  2022-06-07  9:26 [PATCH, CFE] N2863: Improved Rules for Tag Compatibility Martin Uecker
@ 2022-06-07 14:22 ` Joseph Myers
  2022-06-07 14:59   ` Martin Uecker
  0 siblings, 1 reply; 3+ messages in thread
From: Joseph Myers @ 2022-06-07 14:22 UTC (permalink / raw)
  To: Martin Uecker; +Cc: gcc-patches

On Tue, 7 Jun 2022, Martin Uecker wrote:

> here is a preliminary patch the implements the proposed
> tag compatibility rules for C23 in GCC (N2863). It works

I don't see any response on the reflector to my comments on that proposal 
(message 21374, Fri, 14 Jan 2022 23:32:47 +0000).  Nor do I see any tests 
in this patch dealing with the questions of exactly when struct and union 
types are complete or incomplete, as in my first comment there (if there 
are any tests concerning that, it's not apparent for lack of comments 
explaining what exactly the tests are trying to test).  I think we'll need 
a version of the proposal without known issues before the patch is fully 
reviewable.

> - the feature has a flag (-ftag-compat) which is now turned
> on by default in all language modes to facilitate testing
> and to identify backwards compatibility problems. Turned on,
> it survives bootstrapping and regression testing with
> only a few cases that test for diagnostics that go
> away changed to turn it off.

Turning on by default in past language modes seems questionable other than 
for this sort of preliminary testing (in any case, incompatible with 
previous standard requirements so can't be enabled for strict conformance 
modes).  (And in general I'd discourage adding options for individual 
language feature like that, with the resulting proliferation of dialects 
with different combinations of features - again, it may be useful for 
testing purposes, especially before we know whether the feature gets into 
C23, and it may be useful within the compiler sources to distinguish in 
some way which places are checking for this feature rather than just 
testing flag_isoc2x, but actually releasing with a command-line option for 
it is more problematic.)

> diff --git a/gcc/testsuite/gcc.dg/tag-compat2.c
> b/gcc/testsuite/gcc.dg/tag-compat2.c
> new file mode 100644
> index 00000000000..20dc1a9c894
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tag-compat2.c
> @@ -0,0 +1,47 @@
> +/*
> + * { dg-do compile }
> + * { dg-options "-ftag-compat" }
> + */
> +
> +typedef struct bar { int x; } X;
> +typedef struct bar { float x; } Y; /* { dg-warning "redefinition of
> struct or union" } */

I'd expect conflicting definitions of a type in the same scope to remain 
errors, not warnings, regardless of this feature.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH, CFE] N2863: Improved Rules for Tag Compatibility
  2022-06-07 14:22 ` Joseph Myers
@ 2022-06-07 14:59   ` Martin Uecker
  0 siblings, 0 replies; 3+ messages in thread
From: Martin Uecker @ 2022-06-07 14:59 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches

Am Dienstag, den 07.06.2022, 14:22 +0000 schrieb Joseph Myers:
> On Tue, 7 Jun 2022, Martin Uecker wrote:
> 
> > here is a preliminary patch the implements the proposed
> > tag compatibility rules for C23 in GCC (N2863). It works
> 
> I don't see any response on the reflector to my comments on that proposal 
> (message 21374, Fri, 14 Jan 2022 23:32:47 +0000).  Nor do I see any tests 
> in this patch dealing with the questions of exactly when struct and union 
> types are complete or incomplete, as in my first comment there (if there 
> are any tests concerning that, it's not apparent for lack of comments 
> explaining what exactly the tests are trying to test).  I think we'll need 
> a version of the proposal without known issues before the patch is fully 
> reviewable.

Thanks Joseph! I will revisit the wording next and then resend
the patch with the corresponing tests.

Martin


> 
> > - the feature has a flag (-ftag-compat) which is now turned
> > on by default in all language modes to facilitate testing
> > and to identify backwards compatibility problems. Turned on,
> > it survives bootstrapping and regression testing with
> > only a few cases that test for diagnostics that go
> > away changed to turn it off.
> 
> Turning on by default in past language modes seems questionable other than 
> for this sort of preliminary testing (in any case, incompatible with 
> previous standard requirements so can't be enabled for strict conformance 
> modes). 
> (And in general I'd discourage adding options for individual 
> language feature like that, with the resulting proliferation of dialects 
> with different combinations of features - again, it may be useful for 
> testing purposes, especially before we know whether the feature gets into 
> C23, and it may be useful within the compiler sources to distinguish in 
> some way which places are checking for this feature rather than just 
> testing flag_isoc2x, but actually releasing with a command-line option for 
> it is more problematic.)
> 
> > diff --git a/gcc/testsuite/gcc.dg/tag-compat2.c
> > b/gcc/testsuite/gcc.dg/tag-compat2.c
> > new file mode 100644
> > index 00000000000..20dc1a9c894
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tag-compat2.c
> > @@ -0,0 +1,47 @@
> > +/*
> > + * { dg-do compile }
> > + * { dg-options "-ftag-compat" }
> > + */
> > +
> > +typedef struct bar { int x; } X;
> > +typedef struct bar { float x; } Y; /* { dg-warning "redefinition of
> > struct or union" } */
> 
> I'd expect conflicting definitions of a type in the same scope to remain 
> errors, not warnings, regardless of this feature.
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-06-07 14:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-07  9:26 [PATCH, CFE] N2863: Improved Rules for Tag Compatibility Martin Uecker
2022-06-07 14:22 ` Joseph Myers
2022-06-07 14:59   ` Martin Uecker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).