Re: [PATCH v2] analyzer: Move gcc.dg/analyzer tests to c-c++-common (1) [PR96395]

2023-08-26 Thread David Malcolm via Gcc-patches
On Sat, 2023-08-26 at 14:22 +0200, priour...@gmail.com wrote:


> From: benjamin priour 
> 
> Hi,
> 
> Updated version of the patch, regstrapping the changes described in
> https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628455.html.
> 
> Regstrapped off trunk 66be6ed81f369573824f1a8f5a3538a63472292f
> on x86_64-linux-gnu.
> 
> OK for trunk ?

Thanks for the v2 patch.

This is almost ready, some minor nits below...

[...snip...]

> 
> gcc/analyzer/ChangeLog:
> 
>   analyzer/PR 96395

This should be PR analyzer/96395.

>   * analyzer.h (class known_function): Add virtual casts
>   to builtin_known_function.
>   (class builtin_known_function): New subclass of known_function
>   for builtins.

[...snip...]
 
> 
> gcc/testsuite/ChangeLog:
> 
>   analyzer/PR 96395

Likewise here.

>   * gcc.dg/analyzer/aliasing-3.c: Moved to...
>   * c-c++-common/analyzer/aliasing-3.c: ...here.
>   * gcc.dg/analyzer/aliasing-pr106473.c: Moved to...
>   * c-c++-common/analyzer/aliasing-pr106473.c: ...here.

[...snip...]
 
> diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
> index 93a28b4b5cf..d42771f1e20 100644
> --- a/gcc/analyzer/analyzer.h
> +++ b/gcc/analyzer/analyzer.h

[...snip...]

> @@ -279,6 +283,26 @@ public:
>{
>  return;
>}
> +
> +  virtual const builtin_known_function *
> +  dyn_cast_builtin_kf () const { return NULL; }
> +  virtual builtin_known_function *
> +  dyn_cast_builtin_kf () { return NULL; }

As noted in the review of v1, I don't think we ever work with non-const
known_function pointers, so we don't need the non-const version of the
vfunc.

[...snip...]

> diff --git a/gcc/testsuite/c-c++-common/analyzer/pr61861.c 
> b/gcc/testsuite/c-c++-common/analyzer/pr61861.c
> new file mode 100644
> index 000..bb9e039ebd5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/analyzer/pr61861.c
> @@ -0,0 +1,3 @@
> +/* { dg-additional-options "-Wno-int-conversion" } */
> +/* { dg-skip-if "-Wno-int-conversion for C++" { c++ } } */
> +#include "../../gcc.dg/pr61861.c"

For tests like this that aren't going to be portable to C++, let's keep
it in the gcc.dg subdirectory, with a suitable comment, rather than
moving them and having a dg-skip-if on it.

Perhaps:

/* C only: -Wno-int-conversion is not valid for C++.  */

That way we can easily grep for the absence of "C only" when checking
to see which analyzer tests below gcc.dg still need considering for
moving below c-c++-common.  The string "C only" is conveniently short.

[...snip...]

> diff --git a/gcc/testsuite/gcc.dg/analyzer/pr95152-4.c 
> b/gcc/testsuite/c-c++-common/analyzer/pr95152-4.c
> similarity index 55%
> rename from gcc/testsuite/gcc.dg/analyzer/pr95152-4.c
> rename to gcc/testsuite/c-c++-common/analyzer/pr95152-4.c
> index f2a72cad01c..5ebbae85aee 100644
> --- a/gcc/testsuite/gcc.dg/analyzer/pr95152-4.c
> +++ b/gcc/testsuite/c-c++-common/analyzer/pr95152-4.c
> @@ -1,4 +1,6 @@
> +/* { dg-skip-if "'-Wno-pointer-to-int-cast' invalid for C++" { c++ } } */
>  /* { dg-additional-options "-Wno-pointer-to-int-cast" } */

Likewise here.

[...snip...]

> diff --git a/gcc/testsuite/gcc.dg/analyzer/pr95152-5.c 
> b/gcc/testsuite/c-c++-common/analyzer/pr95152-5.c
> similarity index 61%
> rename from gcc/testsuite/gcc.dg/analyzer/pr95152-5.c
> rename to gcc/testsuite/c-c++-common/analyzer/pr95152-5.c
> index 604b78458c7..fbc4753e0b4 100644
> --- a/gcc/testsuite/gcc.dg/analyzer/pr95152-5.c
> +++ b/gcc/testsuite/c-c++-common/analyzer/pr95152-5.c
> @@ -1,3 +1,4 @@
> +/* { dg-skip-if "'-Wno-incompatible-pointer-types' invalid for C++" { c++ } 
> } */
>  /* { dg-additional-options "-Wno-incompatible-pointer-types" } */
>  void foo(void)
>  {

Likewise here.

[...snip...]

> diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c 
> b/gcc/testsuite/c-c++-common/analyzer/write-to-function-1.c
> similarity index 81%
> rename from gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
> rename to gcc/testsuite/c-c++-common/analyzer/write-to-function-1.c
> index c1bece632ce..dd4adc13141 100644
> --- a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
> +++ b/gcc/testsuite/c-c++-common/analyzer/write-to-function-1.c
> @@ -1,3 +1,5 @@
> +/* { dg-skip-if "c++ does not allow for conversion from function pointer to 
> 'void *'" { c++ } } */
> +

Likewise here.

[...snip...]

> diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c 
> b/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c
> index c05137bb219..788a2059013 100644
> --- a/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c
> +++ b/gcc/testsuite/gcc.dg/analyzer/pr104369-1.c
> @@ -1,5 +1,8 @@
>  /* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-fd-leak" 
> } */
>  // TODO: remove need for these options
> +/* This test needs not be moved to c-c++-common/analyzer as C++
> +   does not support transparent_union. */
> +

Perhaps update this comment to:

/* C only: C++ does not support transparent_union.*/

so that we can grep for (the 

[C PATCH] c: flag for tag compatibility rules

2023-08-26 Thread Martin Uecker via Gcc-patches


Add a flag to turn tag compatibility rules on or off
independent from the language version.

gcc/c-family:
* c.opt (flag_tag_compat): New flag.

gcc/c:
* c-decl.cc (diagnose_mismatched_decls, start_struct,
finish_struct, start_enum, finish_enum): Support flag.
* c-typeck.cc (composite_type_internal): Support flag.

gcc/doc:
* invoke.texi: Document flag.

gcc/testsuite:
* gcc.dg/asan/pr81470.c: Turn off tag compatibility.
* gcc.dg/c99-tag-1.c: Turn off tag compatibility.
* gcc.dg/c99-tag-2.c: Turn off tag compatibility.
* gcc.dg/decl-3.c: Turn off tag compatibility.
* gcc.dg/enum-redef-1.c: Turn off tag compatibility.
* gcc.dg/pr17188-1.c: Turn off tag compatibility.
* gcc.dg/pr18809-1.c: Turn off tag compatibility.
* gcc.dg/pr39084.c: Turn off tag compatibility.
* gcc.dg/pr79983.c: Turn off tag compatibility.
---
 gcc/c-family/c.opt  |  3 +++
 gcc/c/c-decl.cc | 12 ++--
 gcc/c/c-typeck.cc   |  2 +-
 gcc/doc/invoke.texi |  5 +
 gcc/testsuite/gcc.dg/asan/pr81460.c |  1 +
 gcc/testsuite/gcc.dg/c99-tag-1.c|  2 +-
 gcc/testsuite/gcc.dg/c99-tag-2.c|  2 +-
 gcc/testsuite/gcc.dg/decl-3.c   |  1 +
 gcc/testsuite/gcc.dg/enum-redef-1.c |  2 ++
 gcc/testsuite/gcc.dg/pr17188-1.c|  2 +-
 gcc/testsuite/gcc.dg/pr18809-1.c|  1 +
 gcc/testsuite/gcc.dg/pr39084.c  |  2 +-
 gcc/testsuite/gcc.dg/pr79983.c  |  2 +-
 13 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 2242524cd3e..f95f12ba249 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2214,6 +2214,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 2137ba8b845..6d1e0d5c382 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2094,7 +2094,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  if (flag_isoc2x
+  if ((flag_isoc2x || flag_tag_compat)
  && TYPE_NAME (DECL_CONTEXT (newdecl))
  && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
  && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
@@ -8723,7 +8723,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 
   /* For C2X, even if we already have a completed definition,
  we do not use it. We will check for consistency later.  */
-  if (flag_isoc2x && ref && TYPE_SIZE (ref))
+  if ((flag_isoc2x || flag_tag_compat) && ref && TYPE_SIZE (ref))
 ref = NULL_TREE;
 
   if (ref && TREE_CODE (ref) == code)
@@ -9515,7 +9515,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 }
 
   /* Check for consistency with previous definition */
-  if (flag_isoc2x)
+  if (flag_isoc2x || flag_tag_compat)
 {
   tree vistype = previous_tag (t);
   if (vistype
@@ -9534,7 +9534,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   C_TYPE_BEING_DEFINED (t) = 0;
 
   /* Set type canonical based on equivalence class.  */
-  if (flag_isoc2x)
+  if (flag_isoc2x || flag_tag_compat)
 {
   if (NULL == c_struct_htab)
c_struct_htab = hash_table::create_ggc (61);
@@ -9672,7 +9672,7 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, );
 
-  if (flag_isoc2x && enumtype != NULL_TREE
+  if ((flag_isoc2x || flag_tag_compat) && enumtype != NULL_TREE
   && TREE_CODE (enumtype) == ENUMERAL_TYPE
   && TYPE_VALUES (enumtype) != NULL_TREE)
 enumtype = NULL_TREE;
@@ -9941,7 +9941,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
 struct_parse_info->struct_types.safe_push (enumtype);
 
   /* Check for consistency with previous definition */
-  if (flag_isoc2x)
+  if (flag_isoc2x || flag_tag_compat)
 {
   tree vistype = previous_tag (enumtype);
   if (vistype
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 357367eab09..b99f0c3e2fd 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -512,7 +512,7 @@ composite_type_internal (tree t1, tree t2, struct 
composite_cache* cache)
 
 case RECORD_TYPE:
 case UNION_TYPE:
-  if (flag_isoc2x && !comptypes_same_p (t1, t2))
+  if ((flag_isoc2x || flag_tag_compat) && !comptypes_same_p (t1, t2))
{
  gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
  gcc_checking_assert (comptypes (t1, t2));
diff --git a/gcc/doc/invoke.texi 

[C PATCH 6/6] c23: construct composite type for tagged types

2023-08-26 Thread Martin Uecker via Gcc-patches



Support for constructing composite type for structs and unions
in C23.

gcc/c:
* c-typeck.cc (composite_type_internal): Adapted from
composite_type to support structs and unions.
(composite_type): New wrapper function.
(build_conditional_operator): Return composite type.

gcc/testsuite:
* gcc.dg/c2x-tag-composite-1.c: New test.
* gcc.dg/c2x-tag-composite-2.c: New test.
* gcc.dg/c2x-tag-composite-3.c: New test.
* gcc.dg/c2x-tag-composite-4.c: New test.
---
 gcc/c/c-typeck.cc  | 114 +
 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c |  26 +
 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c |  16 +++
 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c |  17 +++
 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c |  21 
 5 files changed, 176 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2489fa1e3d1..357367eab09 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, 
tree attrs)
nonzero; if that isn't so, this may crash.  In particular, we
assume that qualifiers match.  */
 
+struct composite_cache {
+  tree t1;
+  tree t2;
+  tree composite;
+  struct composite_cache* next;
+};
+
 tree
-composite_type (tree t1, tree t2)
+composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -425,7 +432,8 @@ composite_type (tree t1, tree t2)
   {
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
-   tree target = composite_type (pointed_to_1, pointed_to_2);
+   tree target = composite_type_internal (pointed_to_1,
+  pointed_to_2, cache);
 t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
t1 = build_type_attribute_variant (t1, attributes);
return qualify_type (t1, t2);
@@ -433,7 +441,8 @@ composite_type (tree t1, tree t2)
 
 case ARRAY_TYPE:
   {
-   tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+   tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+   cache);
int quals;
tree unqual_elt;
tree d1 = TYPE_DOMAIN (t1);
@@ -501,9 +510,61 @@ composite_type (tree t1, tree t2)
return build_type_attribute_variant (t1, attributes);
   }
 
-case ENUMERAL_TYPE:
 case RECORD_TYPE:
 case UNION_TYPE:
+  if (flag_isoc2x && !comptypes_same_p (t1, t2))
+   {
+ gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
+ gcc_checking_assert (comptypes (t1, t2));
+
+ /* If a composite type for these two types is already under
+construction, return it.  */
+
+ for (struct composite_cache *c = cache; c != NULL; c = c->next)
+   if (c->t1 == t1 && c->t2 == t2)
+  return c->composite;
+
+ /* Otherwise, create a new type node and link it into the cache.  */
+
+ tree n = make_node (code1);
+ struct composite_cache cache2 = { t1, t2, n, cache };
+ cache = 
+
+ tree f1 = TYPE_FIELDS (t1);
+ tree f2 = TYPE_FIELDS (t2);
+ tree fields = NULL_TREE;
+
+ for (tree a = f1, b = f2; a && b;
+  a = DECL_CHAIN (a), b = DECL_CHAIN (b))
+   {
+ tree ta = TREE_TYPE (a);
+ tree tb = TREE_TYPE (b);
+
+ gcc_assert (DECL_NAME (a) == DECL_NAME (b));
+ gcc_assert (comptypes (ta, tb));
+
+ tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a),
+  composite_type_internal (ta, tb, cache));
+
+ DECL_FIELD_CONTEXT (f) = n;
+ DECL_CHAIN (f) = fields;
+ fields = f;
+   }
+
+ TYPE_NAME (n) = TYPE_NAME (t1);
+ TYPE_FIELDS (n) = nreverse (fields);
+ TYPE_ATTRIBUTES (n) = attributes;
+ layout_type (n);
+ n = build_type_attribute_variant (n, attributes);
+ n = qualify_type (n, t1);
+
+ gcc_checking_assert (comptypes (n, t1));
+ gcc_checking_assert (comptypes (n, t2));
+
+ return n;
+   }
+  /* FALLTHRU */
+case ENUMERAL_TYPE:
   if (attributes != NULL)
{
  /* Try harder not to create a new aggregate type.  */
@@ -518,7 +579,8 @@ composite_type (tree t1, tree t2)
   /* Function types: prefer the one that specified arg types.
 If both do, merge the arg types.  Also merge the return types.  */
   {
-   tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE 

[C PATCH 5/6] c23: aliasing of compatible tagged types

2023-08-26 Thread Martin Uecker via Gcc-patches



Tell the backend which types are equivalent by setting
TYPE_CANONICAL to one struct in the set of equivalent
structs. Structs are considered equivalent by ignoring
all sizes of arrays nested in types below field level.

gcc/c:
* c-decl.cc (c_struct_hasher): Hash stable for struct
types.
(c_struct_hasher::hash, c_struct_hasher::equal): New functions.
(finish_struct): Set TYPE_CANONICAL to first struct in
equivalence class.
* c-objc-common.cc (c_get_alias_set): Let structs or
unions with variable size alias anything.
* c-tree.h (comptypes_equiv): New prototype.
* c-typeck.cc (comptypes_equiv): New function.
(comptypes_internal): Implement equivalence mode.
(tagged_types_tu_compatible): Implement equivalence mode.

gcc/testsuite:
* gcc.dg/c2x-tag-2.c: Remove xfail.
* gcc.dg/c2x-tag-6.c: Remove xfail.
* gcc.dg/c2x-tag-alias-1.c: New test.
* gcc.dg/c2x-tag-alias-2.c: New test.
* gcc.dg/c2x-tag-alias-3.c: New test.
* gcc.dg/c2x-tag-alias-4.c: New test.
* gcc.dg/c2x-tag-alias-5.c: New test.
* gcc.dg/c2x-tag-alias-6.c: New test.
* gcc.dg/c2x-tag-alias-7.c: New test.
* gcc.dg/c2x-tag-alias-8.c: New test.
---
 gcc/c/c-decl.cc| 48 +
 gcc/c/c-objc-common.cc |  5 ++
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 31 
 gcc/testsuite/gcc.dg/c2x-tag-2.c   |  2 +-
 gcc/testsuite/gcc.dg/c2x-tag-6.c   |  2 +-
 gcc/testsuite/gcc.dg/c2x-tag-alias-1.c | 48 +
 gcc/testsuite/gcc.dg/c2x-tag-alias-2.c | 73 +++
 gcc/testsuite/gcc.dg/c2x-tag-alias-3.c | 48 +
 gcc/testsuite/gcc.dg/c2x-tag-alias-4.c | 73 +++
 gcc/testsuite/gcc.dg/c2x-tag-alias-5.c | 30 
 gcc/testsuite/gcc.dg/c2x-tag-alias-6.c | 77 
 gcc/testsuite/gcc.dg/c2x-tag-alias-7.c | 98 ++
 gcc/testsuite/gcc.dg/c2x-tag-alias-8.c | 90 +++
 14 files changed, 624 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-8.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b514e8a35ee..2137ba8b845 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -603,6 +603,36 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* Hash table for structs and unions.  */
+struct c_struct_hasher : ggc_ptr_hash
+{
+  static hashval_t hash (tree t);
+  static bool equal (tree, tree);
+};
+
+/* Hash an RECORD OR UNION.  */
+hashval_t
+c_struct_hasher::hash (tree type)
+{
+  inchash::hash hstate;
+
+  hstate.add_int (TREE_CODE (type));
+  hstate.add_object (TYPE_NAME (type));
+
+  return hstate.end ();
+}
+
+/* Compare two RECORD or UNION types.  */
+bool
+c_struct_hasher::equal (tree t1,  tree t2)
+{
+  return comptypes_equiv_p (t1, t2);
+}
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static GTY (()) hash_table *c_struct_htab;
+
 /* 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;
@@ -9503,6 +9533,24 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   C_TYPE_BEING_DEFINED (t) = 0;
 
+  /* Set type canonical based on equivalence class.  */
+  if (flag_isoc2x)
+{
+  if (NULL == c_struct_htab)
+   c_struct_htab = hash_table::create_ggc (61);
+
+  hashval_t hash = c_struct_hasher::hash (t);
+
+  tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT);
+  if (*e)
+   TYPE_CANONICAL (t) = *e;
+  else
+   {
+ TYPE_CANONICAL (t) = t;
+ *e = t;
+   }
+}
+
   tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
   for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
 {
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index e4aed61ed00..992225bbb29 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -389,6 +389,11 @@ c_get_alias_set (tree t)
   if (TREE_CODE (t) == ENUMERAL_TYPE)
 return get_alias_set (ENUM_UNDERLYING_TYPE (t));
 
+  /* Structs with variable size can alias different incompatible
+ structs.  Let them alias anything.   */
+  if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t))
+return 0;
+
   return c_common_get_alias_set (t);
 }
 
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 511fd9ee0e5..1a8e8f072bd 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h

[C PATCH 4/6] c23: tag compatibility rules for enums

2023-08-26 Thread Martin Uecker via Gcc-patches



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, );
 
+  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 

[C PATCH 3/6] c23: tag compatibility rules for struct and unions

2023-08-26 Thread Martin Uecker via Gcc-patches



Implement redeclaration and compatibility rules for
structures and unions in C23.

gcc/c/:
* c-decl.cc (previous_tag): New function.
(get_parm_info): Turn off warning for C2X.
(start_struct): Allow redefinitons.
(finish_struct): Diagnose conflicts.
* c-tree.h (comptypes_same_p): Add prototype.
* c-typeck.cc (comptypes_same_p): New function
(comptypes_internal): Activate comparison of tagged
types (convert_for_assignment): Ingore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c2x-enum-7.c: Remove warning.
* gcc.dg/c2x-tag-1.c: New test.
* gcc.dg/c2x-tag-2.c: New test.
* gcc.dg/c2x-tag-3.c: New test.
* gcc.dg/c2x-tag-4.c: New test.
* gcc.dg/c2x-tag-5.c: New test.
* gcc.dg/c2x-tag-6.c: New test.
* gcc.dg/c2x-tag-7.c: New test.
* gcc.dg/c2x-tag-8.c: New test.
* gcc.dg/c2x-tag-9.c: New test.
* gcc.dg/c2x-tag-10.c: New test.
---
 gcc/c/c-decl.cc   | 56 ++---
 gcc/c/c-tree.h|  1 +
 gcc/c/c-typeck.cc | 38 +
 gcc/testsuite/gcc.dg/c2x-enum-7.c |  6 +--
 gcc/testsuite/gcc.dg/c2x-tag-1.c  | 68 +++
 gcc/testsuite/gcc.dg/c2x-tag-10.c | 31 ++
 gcc/testsuite/gcc.dg/c2x-tag-2.c  | 43 +++
 gcc/testsuite/gcc.dg/c2x-tag-3.c  | 16 
 gcc/testsuite/gcc.dg/c2x-tag-4.c  | 19 +
 gcc/testsuite/gcc.dg/c2x-tag-5.c  | 26 
 gcc/testsuite/gcc.dg/c2x-tag-6.c  | 34 
 gcc/testsuite/gcc.dg/c2x-tag-7.c  | 28 +
 gcc/testsuite/gcc.dg/c2x-tag-8.c  | 25 
 gcc/testsuite/gcc.dg/c2x-tag-9.c  | 12 ++
 14 files changed, 387 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-10.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-9.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 1f9eb44dbaa..c5c6a853fa9 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -1993,6 +1993,24 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+static tree
+previous_tag (tree type)
+{
+  struct c_binding *b = NULL;
+  tree name = TYPE_NAME (type);
+
+  if (name)
+b = I_TAG_BINDING (name);
+
+  if (b)
+b = b->shadowed;
+
+  if (b && B_IN_CURRENT_SCOPE (b))
+return b->decl;
+
+  return NULL_TREE;
+}
+
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
Returns true if the caller should proceed to merge the two, false
if OLDDECL should simply be discarded.  As a side effect, issues
@@ -8442,11 +8460,14 @@ get_parm_info (bool ellipsis, tree expr)
  if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
{
  if (b->id)
-   /* The %s will be one of 'struct', 'union', or 'enum'.  */
-   warning_at (b->locus, 0,
-   "%<%s %E%> declared inside parameter list"
-   " will not be visible outside of this definition or"
-   " declaration", keyword, b->id);
+   {
+ /* The %s will be one of 'struct', 'union', or 'enum'.  */
+ if (!flag_isoc2x)
+   warning_at (b->locus, 0,
+   "%<%s %E%> declared inside parameter list"
+   " will not be visible outside of this 
definition or"
+   " declaration", keyword, b->id);
+   }
  else
/* The %s will be one of 'struct', 'union', or 'enum'.  */
warning_at (b->locus, 0,
@@ -8651,6 +8672,12 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 
   if (name != NULL_TREE)
 ref = lookup_tag (code, name, true, );
+
+  /* For C2X, even if we already have a completed definition,
+ we do not use it. We will check for consistency later.  */
+  if (flag_isoc2x && ref && TYPE_SIZE (ref))
+ref = NULL_TREE;
+
   if (ref && TREE_CODE (ref) == code)
 {
   if (TYPE_STUB_DECL (ref))
@@ -9439,6 +9466,25 @@ 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_isoc2x)
+{
+  tree vistype = previous_tag (t);
+  if (vistype
+ && TREE_CODE (vistype) == TREE_CODE (t)
+ && 

[C PATCH 2/6] c23: recursive type checking of tagged type

2023-08-26 Thread Martin Uecker via Gcc-patches




Adapt the old and unused code for type checking for C23.

gcc/c/:
* c-typeck.c (struct comptypes_data): Add anon_field flag.
(comptypes, comptypes_check_unum_int,
comptypes_check_different_types): Remove old cache.
(tagged_tu_types_compatible_p): Rewrite.
---
 gcc/c/c-typeck.cc | 261 +++---
 1 file changed, 58 insertions(+), 203 deletions(-)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ed1520ed6ba..41ef05f005c 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -190,20 +190,14 @@ remove_c_maybe_const_expr (tree expr)
 return expr;
 }
 
-/* This is a cache to hold if two types are compatible or not.  */
+/* This is a cache to hold if two types are seen.  */
 
 struct tagged_tu_seen_cache {
   const struct tagged_tu_seen_cache * next;
   const_tree t1;
   const_tree t2;
-  /* The return value of tagged_types_tu_compatible_p if we had seen
- these two types already.  */
-  int val;
 };
 
-static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
-static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache 
*);
-
 /* Do `exp = require_complete_type (loc, exp);' to make sure exp
does not have an incomplete type.  (That includes void types.)
LOC is the location of the use.  */
@@ -1043,10 +1037,12 @@ common_type (tree t1, tree t2)
 }
 
 struct comptypes_data {
-
   bool enum_and_int_p;
   bool different_types_p;
   bool warning_needed;
+  bool anon_field;
+
+  const struct tagged_tu_seen_cache* cache;
 };
 
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
@@ -1056,13 +1052,9 @@ struct comptypes_data {
 int
 comptypes (tree type1, tree type2)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, );
 
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
-
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1072,14 +1064,10 @@ comptypes (tree type1, tree type2)
 int
 comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, );
   *enum_and_int_p = data.enum_and_int_p;
 
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
-
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1090,14 +1078,10 @@ int
 comptypes_check_different_types (tree type1, tree type2,
 bool *different_types_p)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, );
   *different_types_p = data.different_types_p;
 
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
-
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1334,53 +1318,7 @@ comp_target_types (location_t location, tree ttl, tree 
ttr)
 
 /* Subroutines of `comptypes'.  */
 
-
-
-/* Allocate the seen two types, assuming that they are compatible. */
-
-static struct tagged_tu_seen_cache *
-alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2)
-{
-  struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache);
-  tu->next = tagged_tu_seen_base;
-  tu->t1 = t1;
-  tu->t2 = t2;
-
-  tagged_tu_seen_base = tu;
-
-  /* The C standard says that two structures in different translation
- units are compatible with each other only if the types of their
- fields are compatible (among other things).  We assume that they
- are compatible until proven otherwise when building the cache.
- An example where this can occur is:
- struct a
- {
-   struct a *next;
- };
- If we are comparing this against a similar struct in another TU,
- and did not assume they were compatible, we end up with an infinite
- loop.  */
-  tu->val = 1;
-  return tu;
-}
-
-/* Free the seen types until we get to TU_TIL. */
-
-static void
-free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til)
-{
-  const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base;
-  while (tu != tu_til)
-{
-  const struct tagged_tu_seen_cache *const tu1
-   = (const struct tagged_tu_seen_cache *) tu;
-  tu = tu1->next;
-  XDELETE (CONST_CAST (struct tagged_tu_seen_cache *, tu1));
-}
-  tagged_tu_seen_base = tu_til;
-}
-
-/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
+/* Return true if two 'struct', 'union', or 'enum' types T1 and T2 are
compatible.  If the two types are not the same (which has been
checked earlier).  */
 
@@ -1406,189 +1344,106 @@ tagged_types_tu_compatible_p (const_tree t1, 
const_tree t2,
 && DECL_ORIGINAL_TYPE (TYPE_NAME (t2)))
 t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2));
 
-  /* C90 didn't have the requirement that the two tags be the same.  */
-  if 

[C PATCH 1/6] c: reorganize recursive type checking

2023-08-26 Thread Martin Uecker via Gcc-patches




Reorganize recursive type checking to use a structure to
store information collected during the recursion and
returned to the caller (warning_needed, enum_and_init_p,
different_types_p).

gcc/c:
* c-typeck.cc (struct comptypes_data): Add structure.
(tagged_types_tu_compatible_p,
function_types_compatible_p, type_lists_compatible_p,
comptypes_internal): Add structure to interface, change
return type to bool, and adapt calls.
(comptarget_types): Change return type too bool.
(comptypes, comptypes_check_enum_int,
comptypes_check_different_types): Adapt calls.
---
 gcc/c/c-typeck.cc | 266 --
 1 file changed, 114 insertions(+), 152 deletions(-)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e6ddf37d412..ed1520ed6ba 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -90,12 +90,14 @@ static bool require_constant_elements;
 static bool require_constexpr_value;
 
 static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
-bool *);
-static int comp_target_types (location_t, tree, tree);
-static int function_types_compatible_p (const_tree, const_tree, bool *,
-   bool *);
-static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
+struct comptypes_data;
+static bool tagged_types_tu_compatible_p (const_tree, const_tree,
+ struct comptypes_data *);
+static bool comp_target_types (location_t, tree, tree);
+static bool function_types_compatible_p (const_tree, const_tree,
+struct comptypes_data *);
+static bool type_lists_compatible_p (const_tree, const_tree,
+struct comptypes_data *);
 static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec, tree,
  vec *, vec *, tree,
@@ -125,7 +127,8 @@ static tree find_init_member (tree, struct obstack *);
 static void readonly_warning (tree, enum lvalue_use);
 static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *, bool *);
+static bool comptypes_internal (const_tree, const_tree,
+   struct comptypes_data *data);
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -1039,6 +1042,13 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+struct comptypes_data {
+
+  bool enum_and_int_p;
+  bool different_types_p;
+  bool warning_needed;
+};
+
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations.  Return 2 if they are compatible
but a warning may be needed if you use them together.  */
@@ -1047,12 +1057,13 @@ int
 comptypes (tree type1, tree type2)
 {
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-  int val;
 
-  val = comptypes_internal (type1, type2, NULL, NULL);
+  struct comptypes_data data = { };
+  bool ret = comptypes_internal (type1, type2, );
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
-  return val;
+  return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
 /* Like comptypes, but if it returns non-zero because enum and int are
@@ -1062,12 +1073,14 @@ int
 comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
 {
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-  int val;
 
-  val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
+  struct comptypes_data data = { };
+  bool ret = comptypes_internal (type1, type2, );
+  *enum_and_int_p = data.enum_and_int_p;
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
-  return val;
+  return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
 /* Like comptypes, but if it returns nonzero for different types, it
@@ -1078,40 +1091,40 @@ comptypes_check_different_types (tree type1, tree type2,
 bool *different_types_p)
 {
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-  int val;
 
-  val = comptypes_internal (type1, type2, NULL, different_types_p);
+  struct comptypes_data data = { };
+  bool ret = comptypes_internal (type1, type2, );
+  *different_types_p = data.different_types_p;
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
-  return val;
+  return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
-/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
-   or various other operations.  Return 2 if they are compatible
-   but a warning may be needed if you use them together.  If
-   ENUM_AND_INT_P is not NULL, and one type is an enum and the other a
-   compatible integer type, then this sets *ENUM_AND_INT_P to true;
-   *ENUM_AND_INT_P is 

c23 type compatibility rules, v2

2023-08-26 Thread Martin Uecker via Gcc-patches



This is a revised series for the C23 rules for type
compatibility.

1/6 c: reorganize recursive type checking
2/6 c23: recursive type checking of tagged type
3/6 c23: tag compatibility rules for struct and unions
4/6 c23: tag compatibility rules for enums
5/6 c23: aliasing of compatible tagged types
6/6 c23: construct composite type for tagged types
x/x c: flag for tag compatibility rules


1. simplifies type checking without functionality changes
as a preparation step. (This is based on a similar preparatory
patch I posted before for checking size expressions).

2. implements the new rules in comptypes for tagged types but 
the code still remains unused. This removes a lot of old
code because we now require union members to have the same
order and merges the code for structs and unions.

3. implements the rules for structs and unions.

4. does the same for enum types and enumerators. 

5. sets TYPE_CANONICAL based on a equivalence class of types
which makes aliasing work correctly. For this there is a new
comptypes_equiv_p that does relaxed checking (ignoring size
expressions in nested types but not for fields).

6. adds support for the composite type.

There is an extra patch that adds the a flag to activate
the compatibility rules independently from language mode
and activates it by default.

1-2 should cause no change in function. 3-6 implement the
new semantics for C23.

Bootstrapped and regression tested on x86_64 (also with the
extra patch).

Martin







[Patch, fortran] PR92586 - ICE in gimplify_expr, at gimplify.c:13479 with nested allocatable derived types

2023-08-26 Thread Paul Richard Thomas via Gcc-patches
Committed as 'obvious'. 13-branch to follow.

commit r14-3501-g44bcb51eb0d5cac6eb2de54541ca8e6c2d738160
Author: Paul Thomas 
Date:   Sat Aug 26 14:37:49 2023 +0100

Fortran: Supply a missing dereference [PR92586]

2023-08-26  Paul Thomas  

gcc/fortran
PR fortran/92586
* trans-expr.cc (gfc_trans_arrayfunc_assign): Supply a missing
dereference for the call to gfc_deallocate_alloc_comp_no_caf.

gcc/testsuite/
PR fortran/92586
* gfortran.dg/pr92586.f90 : New test

Paul


[PATCH v2] Mode-Switching: Add optional EMIT_AFTER hook

2023-08-26 Thread Pan Li via Gcc-patches
From: Pan Li 

Update in v2:

* Remove control flow check in BB_END.
* Passed x86 bootstrap and regression test.

Original log:

We have EMIT hook in mode switching already, which will insert the
insn before in most cases. However, in some arch like RISC-V, it
requires the additional insn to be inserted after when meet a call.

   |
   | <- EMIT HOOK, insert the insn before.
 +---+
 | ptr->insn |
 +---+
   | <- EMIT_AFTER HOOK, insert the insn after.
   |

Thus, this patch would like to add one optional EMIT_AFTER hook, which
will try to insert the emitted insn after. The end-user can either
implement this HOOK or leave it NULL as is.

If the backend ignore this optinal hook, there is no impact to the
original mode switching stuff. If the backend implement this optional
hook, the mode switching will try to insert the insn after. Please note
the EMIT_AFTER doen't have any impact to EMIT hook.

Signed-off-by: Pan Li 

gcc/ChangeLog:

* doc/tm.texi: Add hook def and update the description.
* doc/tm.texi.in: Ditto.
* mode-switching.cc (optimize_mode_switching): Insert the
emitted insn after ptr->insn.
* target.def (insn): Define emit_after hook.
---
 gcc/doc/tm.texi   | 12 ++--
 gcc/doc/tm.texi.in|  6 --
 gcc/mode-switching.cc | 43 +++
 gcc/target.def|  9 +
 4 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index d0d47b0d471..9b93a85f634 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -10334,8 +10334,8 @@ return nonzero for any @var{entity} that needs 
mode-switching.
 If you define this macro, you also have to define
 @code{NUM_MODES_FOR_MODE_SWITCHING}, @code{TARGET_MODE_NEEDED},
 @code{TARGET_MODE_PRIORITY} and @code{TARGET_MODE_EMIT}.
-@code{TARGET_MODE_AFTER}, @code{TARGET_MODE_ENTRY}, and @code{TARGET_MODE_EXIT}
-are optional.
+@code{TARGET_MODE_AFTER}, @code{TARGET_MODE_ENTRY}, 
@code{TARGET_MODE_EMIT_AFTER},
+and @code{TARGET_MODE_EXIT} are optional.
 @end defmac
 
 @defmac NUM_MODES_FOR_MODE_SWITCHING
@@ -10359,6 +10359,14 @@ to switch from. Sets of a lower numbered entity will 
be emitted before
 sets of a higher numbered entity to a mode of the same or lower priority.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_MODE_EMIT_AFTER (int @var{entity}, int 
@var{mode}, int @var{prev_mode}, HARD_REG_SET @var{regs_live})
+Generate one or more insns to set @var{entity} to @var{mode}.
+@var{hard_reg_live} is the set of hard registers live at the point where
+the insn(s) are to be inserted after. @var{prev_moxde} indicates the mode
+to switch from. Sets of a lower numbered entity will be emitted before
+sets of a higher numbered entity to a mode of the same or lower priority.
+@end deftypefn
+
 @deftypefn {Target Hook} int TARGET_MODE_NEEDED (int @var{entity}, rtx_insn 
*@var{insn})
 @var{entity} is an integer specifying a mode-switched entity.
 If @code{OPTIMIZE_MODE_SWITCHING} is defined, you must define this macro
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 4ac96dc357d..2942ce0be3b 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -6911,8 +6911,8 @@ return nonzero for any @var{entity} that needs 
mode-switching.
 If you define this macro, you also have to define
 @code{NUM_MODES_FOR_MODE_SWITCHING}, @code{TARGET_MODE_NEEDED},
 @code{TARGET_MODE_PRIORITY} and @code{TARGET_MODE_EMIT}.
-@code{TARGET_MODE_AFTER}, @code{TARGET_MODE_ENTRY}, and @code{TARGET_MODE_EXIT}
-are optional.
+@code{TARGET_MODE_AFTER}, @code{TARGET_MODE_ENTRY}, 
@code{TARGET_MODE_EMIT_AFTER},
+and @code{TARGET_MODE_EXIT} are optional.
 @end defmac
 
 @defmac NUM_MODES_FOR_MODE_SWITCHING
@@ -6930,6 +6930,8 @@ switch is needed / supplied.
 
 @hook TARGET_MODE_EMIT
 
+@hook TARGET_MODE_EMIT_AFTER
+
 @hook TARGET_MODE_NEEDED
 
 @hook TARGET_MODE_AFTER
diff --git a/gcc/mode-switching.cc b/gcc/mode-switching.cc
index f483c831c35..0127fb42330 100644
--- a/gcc/mode-switching.cc
+++ b/gcc/mode-switching.cc
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lcm.h"
 #include "cfgcleanup.h"
 #include "tree-pass.h"
+#include "gcse.h"
 
 /* We want target macros for the mode switching code to be able to refer
to instruction attribute values.  */
@@ -831,6 +832,48 @@ optimize_mode_switching (void)
emit_insn_before (mode_set, ptr->insn_ptr);
}
 
+ if (targetm.mode_switching.emit_after)
+   {
+ if (ptr->insn_ptr != BB_END (bb))
+   {
+ start_sequence ();
+ targetm.mode_switching.emit_after (entity_map[j],
+   ptr->mode, cur_mode, ptr->regs_live);
+ mode_set = get_insns ();
+ end_sequence ();
+
+ if (mode_set != NULL_RTX)
+ 

[PATCH] libcpp: Small incremental patch for P1854R4 [PR110341]

2023-08-26 Thread Jakub Jelinek via Gcc-patches
Hi!

The following incremental patch to the PR110341 posted patch uses
a special conversion callback instead of conversion from host charset
(UTF-8/UTF-EBCDIC) to UTF-32, and also ignores all diagnostics from the
second cpp_interpret_string which should just count chars.  The UTF-EBCDIC
is untested, but simple enough that it should just work.

2023-08-26  Jakub Jelinek  

PR c++/110341
* charset.cc (one_count_chars, convert_count_chars): New functions.
(narrow_str_to_charconst): Call cpp_interpret_string with type
rather than CPP_STRING32, temporarily override for that call
pfile->cb.diagnostic to noop_diagnostic_cb and
pfile->narrow_cset_desc.func to convert_count_chars and just compare
str.len against str2.len.

--- libcpp/charset.cc.jj2023-08-25 17:14:14.098733396 +0200
+++ libcpp/charset.cc   2023-08-26 12:57:44.858858994 +0200
@@ -446,6 +446,74 @@ one_utf16_to_utf8 (iconv_t bigend, const
   return 0;
 }
 
+
+/* Special routine which just counts number of characters in the
+   string, what exactly is stored into the output doesn't matter
+   as long as it is one uchar per character.  */
+
+static inline int
+one_count_chars (iconv_t, const uchar **inbufp, size_t *inbytesleftp,
+uchar **outbufp, size_t *outbytesleftp)
+{
+  uchar *outbuf;
+  cppchar_t s = 0;
+  int rval;
+
+  /* Check for space first, since we know exactly how much we need.  */
+  if (*outbytesleftp < 1)
+return E2BIG;
+
+#if HOST_CHARSET == HOST_CHARSET_ASCII
+  rval = one_utf8_to_cppchar (inbufp, inbytesleftp, );
+  if (rval)
+return rval;
+#else
+  if (*inbytesleftp < 1)
+return EINVAL;
+  static const uchar utf_ebcdic_map[256] = {
+/* See table 4 in http://unicode.org/reports/tr16/tr16-7.2.html  */
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1,
+1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1,
+1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1,
+9, 9, 9, 9, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2,
+2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 1, 3, 3,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 4,
+1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 5, 5, 5,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 6, 7, 7, 0
+  };
+  rval = utf_ebcdic_map[**inbufp];
+  if (rval == 9)
+return EILSEQ;
+  if (rval == 0)
+rval = 1;
+  if (rval >= 2)
+{
+  if (*inbytesleftp < rval)
+   return EINVAL;
+  for (int i = 1; i < rval; ++i)
+   if (utf_ebcdic_map[(*inbufp)[i]] != 9)
+ return EILSEQ;
+}
+  *inbytesleftp -= rval;
+  *inbufp += rval;
+#endif
+
+  **outbufp = ' ';
+
+  *outbufp += 1;
+  *outbytesleftp -= 1;
+  return 0;
+}
+
+
 /* Helper routine for the next few functions.  The 'const' on
one_conversion means that we promise not to modify what function is
pointed to, which lets the inliner see through it.  */
@@ -529,6 +597,15 @@ convert_utf32_utf8 (iconv_t cd, const uc
   return conversion_loop (one_utf32_to_utf8, cd, from, flen, to);
 }
 
+/* Magic conversion which just counts characters from input, so
+   only to->len is significant.  */
+static bool
+convert_count_chars (iconv_t cd, const uchar *from,
+size_t flen, struct _cpp_strbuf *to)
+{
+  return conversion_loop (one_count_chars, cd, from, flen, to);
+}
+
 /* Identity conversion, used when we have no alternative.  */
 static bool
 convert_no_conversion (iconv_t cd ATTRIBUTE_UNUSED,
@@ -2613,15 +2690,22 @@ narrow_str_to_charconst (cpp_reader *pfi
 ill-formed.  We need to count the number of c-chars and compare
 that to str.len.  */
   cpp_string str2 = { 0, 0 };
-  if (cpp_interpret_string (pfile, >val.str, 1, ,
-   CPP_STRING32))
+  bool (*saved_diagnostic_handler) (cpp_reader *, enum 
cpp_diagnostic_level,
+   enum cpp_warning_reason, rich_location 
*,
+   const char *, va_list *)
+   ATTRIBUTE_FPTR_PRINTF(5,0);
+  saved_diagnostic_handler = pfile->cb.diagnostic;
+  pfile->cb.diagnostic = noop_diagnostic_cb;
+  convert_f save_func = pfile->narrow_cset_desc.func;
+  pfile->narrow_cset_desc.func = convert_count_chars;
+  bool ret = cpp_interpret_string (pfile, >val.str, 1, , type);
+  pfile->narrow_cset_desc.func = save_func;
+  pfile->cb.diagnostic = saved_diagnostic_handler;
+  if (ret)
{
- size_t width32 = converter_for_type (pfile, CPP_STRING32).width;
- size_t nbwc = width32 / width;
- size_t len = str2.len / 

Re: [PATCH] rs6000: Fix issue in specifying PTImode as an attribute [PR106895]

2023-08-26 Thread Michael Meissner via Gcc-patches
On Thu, Aug 24, 2023 at 09:19:51PM -0500, Peter Bergner wrote:
> On 8/24/23 12:35 PM, Michael Meissner wrote:
> > On Thu, Jul 20, 2023 at 10:05:28AM +0530, jeevitha wrote:
> >> gcc/
> >>PR target/110411
> >>* config/rs6000/rs6000.h (enum rs6000_builtin_type_index): Add fields
> >>to hold PTImode type.
> >>* config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Add node
> >>for PTImode type.
> > 
> > It is good as far as it goes, but I suspect we will eventually need to 
> > extend
> > it.  In particular, the reason people need PTImode is they need the even/odd
> > register layout.  What you've done enables users to declare this value.
> 
> Sure, it could be extended, but that is not what this patch is about.
> It's purely to allow the kernel team access to the guaranteed even/odd
> register layout for some inline asm code.  Any extension would be a
> follow-on patch to this.

I think we need to get the intended users to try the compiler out, and see if
something else happens down the road that we didn't think of.

I tend to think of these things like the children's story "If you give a mouse
a cookie", which in turn leads to another thing and then another.

As I said, I would expect it would be temptimg to start use these types with
either 8 byte atomic built-ins, or do masks, etc.

In a way, it sort of reminds me of OOmode, where we have this opaque type to
load two vectors, but when you start trying to access the two separate
registers, you get all sorts of moves, because the compiler underneath the
covers doesn't really know it is two registers.

In general, I tend that people don't tend to have a full 128-bit integer, but
instead you have a structure with two fields, one is the lock and one is the
data.  So you want to load things together (or do compare/swap, etc.) and then
you want to split the parts into 2 pieces, and then later, combine them back
into the PTImode container.

I really wish we had a constraint that matched the 2nd register in a multi-word
register (not an output operation, a constraint so that the register allocator
could know that you want to overlap a register).

-- 
Michael Meissner, IBM
PO Box 98, Ayer, Massachusetts, USA, 01432
email: meiss...@linux.ibm.com