[C PATCH] C: Error message for incorrect use of static in array declarations

2024-06-23 Thread Martin Uecker


This adds an explicit error message for [static] and [static*] 
(the same as clang has) instead of the generic "error: expected
expression before ']' token", which is not entirely accurate.
For function definitions the subsequent error "[*] can not be
used outside function prototype scope" is then suppressed.


Bootstrapped and regression tested on x86_64.



commit 1157d04764eeeb51fa1098727813dbc092e11dd2
Author: Martin Uecker 
Date:   Sat Nov 4 14:39:19 2023 +0100

C: Error message for incorrect use of static in array declarations.

Add an explicit error messages when c99's static is
used without a size expression in an array declarator.

gcc/:
c/c-parser.cc (c_parser_direct_declarator_inner): Add
error message.

gcc/testsuite:
gcc.dg/c99-arraydecl-4.c: New test.

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index e83e9c683f7..91b8d24ca78 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -4732,41 +4732,29 @@ c_parser_direct_declarator_inner (c_parser *parser, 
bool id_present,
false, false, false, false, cla_prefer_id);
   if (!quals_attrs->declspecs_seen_p)
quals_attrs = NULL;
-  /* If "static" is present, there must be an array dimension.
-Otherwise, there may be a dimension, "*", or no
-dimension.  */
-  if (static_seen)
+
+  star_seen = false;
+  if (c_parser_next_token_is (parser, CPP_MULT)
+ && c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
{
- star_seen = false;
- dimen = c_parser_expr_no_commas (parser, NULL);
+ star_seen = true;
+ c_parser_consume_token (parser);
}
-  else
+  else if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+   dimen = c_parser_expr_no_commas (parser, NULL);
+
+  if (static_seen && star_seen)
{
- if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
-   {
- dimen.value = NULL_TREE;
- star_seen = false;
-   }
- else if (c_parser_next_token_is (parser, CPP_MULT))
-   {
- if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
-   {
- dimen.value = NULL_TREE;
- star_seen = true;
- c_parser_consume_token (parser);
-   }
- else
-   {
- star_seen = false;
- dimen = c_parser_expr_no_commas (parser, NULL);
-   }
-   }
- else
-   {
- star_seen = false;
- dimen = c_parser_expr_no_commas (parser, NULL);
-   }
+ error_at (c_parser_peek_token (parser)->location,
+   "% may not be used with an unspecified "
+   "variable length array size");
+ /* Prevent further errors. */
+ star_seen = false;
}
+  else if (static_seen && NULL_TREE == dimen.value)
+   error_at (c_parser_peek_token (parser)->location,
+ "% may not be used without an array size");
+
   if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
c_parser_consume_token (parser);
   else
diff --git a/gcc/testsuite/gcc.dg/c99-arraydecl-4.c 
b/gcc/testsuite/gcc.dg/c99-arraydecl-4.c
new file mode 100644
index 000..bfc26196433
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-arraydecl-4.c
@@ -0,0 +1,15 @@
+/* { dg-do "compile" } */
+/* { dg-options "-std=c99 -pedantic-errors" } */
+
+void fo(char buf[static]); /* { dg-error "'static' may not be used without 
an array size" } */
+void fo(char buf[static]) { }  /* { dg-error "'static' may not be used without 
an array size" } */
+
+void fu(char buf[static *]);   /* { dg-error "'static' may not be used with an 
unspecified variable length array size" } */
+void fu(char buf[static *]) { }/* { dg-error "'static' may not be used 
with an unspecified variable length array size" } */
+
+void fe(int n, char buf[static n]);
+void fe(int n, char buf[static *]) { } /* { dg-error "'static' may not be used 
with an unspecified variable length array size" } */
+
+void fa(int *n, char buf[static *n]);
+void fa(int *n, char buf[static *n]) { }
+







[PATCH] Fix test errors introduced with fix for PR115157

2024-06-23 Thread Martin Uecker


This should fix the test failures introduced by the fix for PR115157.

Tested on x86_64 and also tested with -m32.


Fix test errors introduced with fix for PR115157.

Fix tests introduced when fixing PR115157 that assume 
sizeof(enum)==sizeof(int)
by adding the flag -fno-short-enums.

gcc/testsuite/Changelog:
* gcc.dg/enum-alias-1.c: Add flag.
* gcc.dg/enum-alias-2.c: Add flag.
* gcc.dg/enum-alias-3.c: Add flag.
* gcc.dg/enum-alias-4.c: Add flag.

diff --git a/gcc/testsuite/gcc.dg/enum-alias-1.c 
b/gcc/testsuite/gcc.dg/enum-alias-1.c
index 8fa30eb7897..725d88580b8 100644
--- a/gcc/testsuite/gcc.dg/enum-alias-1.c
+++ b/gcc/testsuite/gcc.dg/enum-alias-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fno-short-enums" } */
 
 enum E { E1 = -1, E2 = 0, E3 = 1 };
 
diff --git a/gcc/testsuite/gcc.dg/enum-alias-2.c 
b/gcc/testsuite/gcc.dg/enum-alias-2.c
index 7ca3f3b2db8..d988c5ee698 100644
--- a/gcc/testsuite/gcc.dg/enum-alias-2.c
+++ b/gcc/testsuite/gcc.dg/enum-alias-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fno-short-enums" } */
 
 typedef int A;
 
diff --git a/gcc/testsuite/gcc.dg/enum-alias-3.c 
b/gcc/testsuite/gcc.dg/enum-alias-3.c
index 36a4f02a455..4dbf0c9293a 100644
--- a/gcc/testsuite/gcc.dg/enum-alias-3.c
+++ b/gcc/testsuite/gcc.dg/enum-alias-3.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -flto" } */
+/* { dg-options "-O2 -flto -fno-short-enums" } */
 
 typedef int *A;
 
diff --git a/gcc/testsuite/gcc.dg/enum-alias-4.c 
b/gcc/testsuite/gcc.dg/enum-alias-4.c
index b78d0451e3e..a1a8613fca0 100644
--- a/gcc/testsuite/gcc.dg/enum-alias-4.c
+++ b/gcc/testsuite/gcc.dg/enum-alias-4.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -fno-short-enums" } */
 
 typedef int A;
 typedef int __attribute__ (( hardbool(0, 1) )) B;






[PATCH] Fix test errors after r15-1394 for sizeof(int)==sizeof(long) [PR115545]

2024-06-23 Thread Martin Uecker


This fixes the test failures introduced by the fix for PR115109.

Tested on x86_64 and also tested with -m32.



Fix test errors after r15-1394 for sizeof(int)==sizeof(long) [PR115545]

Some tests added to test the type of redeclarations of enumerators
in r15-1394 fail on architectures where sizeof(long) == sizeof(int).
Adapt tests to use long long and/or accept that long long is selected
as type for the enumerator.

gcc/testsuite/Changelog:
PR testsuite/115545
* gcc.dg/pr115109.c: Adapt test.
* gcc.dg/c23-tag-enum-6.c: Adapt test.
* gcc.dg/c23-tag-enum-7.c: Adapt test.

diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
index 29aef7ee3fd..d8d304d9b3d 100644
--- a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -7,10 +7,10 @@ enum E : int { a = 1, b = 2 };
 enum E : int { b = _Generic(a, enum E: 2), a = 1 };
 
 enum H { x = 1 };
-enum H { x = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */
+enum H { x = 2ULL + UINT_MAX };/* { dg-error "outside the range" } */
 
 enum K : int { z = 1 };
-enum K : int { z = 2UL + UINT_MAX };   /* { dg-error "outside the range" } */
+enum K : int { z = 2ULL + UINT_MAX };  /* { dg-error "outside the range" } */
 
 enum F { A = 0, B = UINT_MAX };
 enum F { B = UINT_MAX, A };/* { dg-error "outside the range" } */
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
index d4c787c8f71..974735bf2ef 100644
--- a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
@@ -4,23 +4,23 @@
 #include 
 
 // enumerators are all representable in int
-enum E { a = 1UL, b = _Generic(a, int: 2) };
+enum E { a = 1ULL, b = _Generic(a, int: 2) };
 static_assert(_Generic(a, int: 1));
 static_assert(_Generic(b, int: 1));
-enum E { a = 1UL, b = _Generic(a, int: 2) };
+enum E { a = 1ULL, b = _Generic(a, int: 2) };
 static_assert(_Generic(a, int: 1));
 static_assert(_Generic(b, int: 1));
 
 // enumerators are not representable in int
-enum H { c = 1UL << (UINT_WIDTH + 1), d = 2 };
+enum H { c = 1ULL << (UINT_WIDTH + 1), d = 2 };
 static_assert(_Generic(c, enum H: 1));
 static_assert(_Generic(d, enum H: 1));
-enum H { c = 1UL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) };
+enum H { c = 1ULL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) };
 static_assert(_Generic(c, enum H: 1));
 static_assert(_Generic(d, enum H: 1));
 
 // there is an overflow in the first declaration
-enum K { e = UINT_MAX, f, g = _Generic(e, unsigned int: 0) + _Generic(f, 
unsigned long: 1) };
+enum K { e = UINT_MAX, f, g = _Generic(e, unsigned int: 0) + _Generic(f, 
unsigned long: 1, unsigned long long: 1) };
 static_assert(_Generic(e, enum K: 1));
 static_assert(_Generic(f, enum K: 1));
 static_assert(_Generic(g, enum K: 1));
@@ -30,7 +30,7 @@ static_assert(_Generic(f, enum K: 1));
 static_assert(_Generic(g, enum K: 1));
 
 // there is an overflow in the first declaration
-enum U { k = INT_MAX, l, m = _Generic(k, int: 0) + _Generic(l, long: 1) };
+enum U { k = INT_MAX, l, m = _Generic(k, int: 0) + _Generic(l, long: 1, long 
long: 1) };
 static_assert(_Generic(k, enum U: 1));
 static_assert(_Generic(l, enum U: 1));
 static_assert(_Generic(m, enum U: 1));
diff --git a/gcc/testsuite/gcc.dg/pr115109.c b/gcc/testsuite/gcc.dg/pr115109.c
index 4baee0f3445..8245ff7fadb 100644
--- a/gcc/testsuite/gcc.dg/pr115109.c
+++ b/gcc/testsuite/gcc.dg/pr115109.c
@@ -3,6 +3,6 @@
 
 #include 
 
-enum E { a = 1UL << (ULONG_WIDTH - 5), b = 2 };
-enum E { a = 1ULL << (ULONG_WIDTH - 5), b = _Generic(a, enum E: 2) };
+enum E { a = 1ULL << (ULLONG_WIDTH - 5), b = 2 };
+enum E { a = 1ULL << (ULLONG_WIDTH - 5), b = _Generic(a, enum E: 2) };
 



Re: [C PATCH] Fix ICE related to incomplete structures in C23 [PR114930,PR115502].

2024-06-19 Thread Martin Uecker
Am Mittwoch, dem 19.06.2024 um 08:57 +0200 schrieb Richard Biener:
> On Wed, 19 Jun 2024, Martin Uecker wrote:
> 
> > Am Mittwoch, dem 19.06.2024 um 08:04 +0200 schrieb Richard Biener:
> > > 
> > > > Am 18.06.2024 um 20:18 schrieb Martin Uecker :
> > > > 
> > > > Am Dienstag, dem 18.06.2024 um 17:27 +0200 schrieb Richard Biener:
> > > > > 
> > > > > > > Am 18.06.2024 um 17:20 schrieb Martin Uecker :
> > > > > > 
> > > > > > 
> > > > > > As discussed this replaces the use of check_qualified_type with
> > > > > > a simple check for qualifiers as suggested by Jakub in
> > > > > > c_update_type_canonical.
> > > > > 
> > > > > Note a canonical type should always be unqualified (for
> > > > > classical qualifiers, not address space or atomic qualification)
> > > > 
> > > > The logic in build_qualified_type is the same as in this patch,
> > > > it constructs TYPE_CANONICAL with qualifiers.  Or what am I
> > > > missing?
> > > 
> > > Nothing if you chose to do TYPE_QUALS (canonical) by copy-pasting.
> > 
> > I would rather like to undertand how this work. Is the following
> > correct?
> > 
> > For a type T with TYPE_CANONICAL (T) == S, if we construct a qualified
> > type "const" T it would get a const qualified version Q of S as 
> > canonical type.  S has TYPE_CANONICAL (S) == S and Q has
> > TYPE_CANONICAL (Q) == Q.
> 
> I think this is a misunderstanding - TYPE_CANONICAL of both T and Q
> should be the same (S).

Ok. Then should it, instead of

TYPE_CANONICAL (x)
= build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));

be

tree c = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
TYPE_CANONICAL (x) = TREE_CANONICAL (c);

in the patch below?

Martin

> 
> > But the middle end would then ignore this for regular qualifiers
> > and use the TYPE_CANONICAL of the main variant for computing
> > the aliasing set?
> 
> The middle end uses the canonical type for alias set purposes.
> The indirection via TYPE_MAIN_VARIANT shouldn't be necessary.
> 
> > Setting it differently for qualified types would still be important
> > so that derived types get their own different TYPE_CANONICAL
> > during construction.
> > 
> > 
> > The other thing I would like to confirm?  The alias set is
> > initialized to -1 so set later in the middle end based on
> > TYPE_CANONICAL (if not set to zero before).   This is never
> > done before the FE is finished or do we need to worry that
> > this may become inconsistent?
> 
> It used to be that -Wstrict-aliasing calls get_alias_set so
> TYPE_ALIAS_SET can become set, I don't remember this being
> avoided so yes, you'd have to worry about this.  Note
> TYPE_ALIAS_SET is only ever considered on the canonical type
> (but IIRC we have checking code looking at other type alias set).
> 
> Richard.
> 
> > Martin
> > 
> > > Richard 
> > > 
> > > > Martin
> > > > 
> > > > > 
> > > > > Richard
> > > > > 
> > > > > > Martin
> > > > > > 
> > > > > > 
> > > > > > Bootstrapped and regression tested on x86_64.
> > > > > > 
> > > > > > 
> > > > > >   C23: Fix ICE related to incomplete structures [PR114930,PR115502].
> > > > > > 
> > > > > >   The fix for PR114574 needs to be further revised because 
> > > > > > check_qualified_type
> > > > > >   makes decision based on TYPE_NAME which can be incorrect for C 
> > > > > > when there
> > > > > >   are TYPE_DECLS involved.
> > > > > > 
> > > > > >   gcc/c/:
> > > > > >   * c-decl.c (c_update_type_canonical): Do not use 
> > > > > > check_qualified_type.
> > > > > > 
> > > > > >   gcc/testsuite/:
> > > > > >   * gcc.dg/pr114930.c: New test.
> > > > > >   * gcc.dg/pr115502.c: New test.
> > > > > > 
> > > > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > > > > > index 01326570e2b..610061a07f8 100644
> > > > > > --- a/gcc/c/c-decl.cc
> > > > > > +++ b/gcc/c/c-decl.cc
> > > > > > @@ -9374,7 +9374,7 @@ c_update_type_canonical (tree t)
> > > > > &

Re: [C PATCH] Fix ICE related to incomplete structures in C23 [PR114930,PR115502].

2024-06-19 Thread Martin Uecker
Am Mittwoch, dem 19.06.2024 um 08:29 +0200 schrieb Jakub Jelinek:
> On Wed, Jun 19, 2024 at 08:04:55AM +0200, Richard Biener wrote:
> > > > Note a canonical type should always be unqualified (for
> > > > classical qualifiers, not address space or atomic qualification)
> > > 
> > > The logic in build_qualified_type is the same as in this patch,
> > > it constructs TYPE_CANONICAL with qualifiers.  Or what am I
> > > missing?
> > 
> > Nothing if you chose to do TYPE_QUALS (canonical) by copy-pasting.
> 
> As I mentioned earlier, I'd prefer the following version and I have
> already tested it on the testcases (note, some changes to the tests,
> e.g. using lto effective target), just haven't bootstrapped/regtested it
> fully yet.

Ok, thanks, I wasn't sure about the conclusion of the discussion.

Martin

> 
> gcc/c/
>   * c-decl.cc (c_update_type_canonical): Assert t is main variant
>   with 0 TYPE_QUALS.  Simplify and don't use check_qualified_type.
> gcc/testsuite/
>   * gcc.dg/pr114930.c: New test.
>   * gcc.dg/pr115502.c: New test.
> 
> --- gcc/c/c-decl.cc.jj2024-06-07 12:17:09.582969919 +0200
> +++ gcc/c/c-decl.cc   2024-06-18 21:30:22.881904947 +0200
> @@ -9367,18 +9367,16 @@ is_flexible_array_member_p (bool is_last
>  static void
>  c_update_type_canonical (tree t)
>  {
> -  for (tree x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
> +  gcc_checking_assert (TYPE_MAIN_VARIANT (t) == t && !TYPE_QUALS (t));
> +  for (tree x = t; x; x = TYPE_NEXT_VARIANT (x))
>  {
>if (x != t && TYPE_STRUCTURAL_EQUALITY_P (x))
>   {
> -   if (TYPE_QUALS (x) == TYPE_QUALS (t))
> +   if (!TYPE_QUALS (x))
>   TYPE_CANONICAL (x) = TYPE_CANONICAL (t);
> -   else if (TYPE_CANONICAL (t) != t
> -|| check_qualified_type (x, t, TYPE_QUALS (x)))
> +   else
>   TYPE_CANONICAL (x)
> = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
> -   else
> - TYPE_CANONICAL (x) = x;
>   }
>else if (x != t)
>   continue;
> --- gcc/testsuite/gcc.dg/pr114930.c.jj2024-06-18 21:27:53.782729543 
> +0200
> +++ gcc/testsuite/gcc.dg/pr114930.c   2024-06-18 21:27:53.782729543 +0200
> @@ -0,0 +1,9 @@
> +/* PR c/114930 */
> +/* { dg-do compile { target lto } } */
> +/* { dg-options "-std=c23 -flto" } */
> +
> +typedef struct WebPPicture WebPPicture;
> +typedef int (*WebPProgressHook)(const WebPPicture *);
> +WebPProgressHook progress_hook;
> +struct WebPPicture {
> +} WebPGetColorPalette(const struct WebPPicture *);
> --- gcc/testsuite/gcc.dg/pr115502.c.jj2024-06-18 21:27:53.793729408 
> +0200
> +++ gcc/testsuite/gcc.dg/pr115502.c   2024-06-18 21:27:53.793729408 +0200
> @@ -0,0 +1,9 @@
> +/* PR c/115502 */
> +/* { dg-do compile { target lto } } */
> +/* { dg-options "-std=c23 -flto" } */
> +
> +typedef struct _OSet OSet;
> +typedef OSet AvlTree;
> +void vgPlain_OSetGen_Lookup(const OSet *);
> +struct _OSet {};
> +void vgPlain_OSetGen_Lookup(const AvlTree *);
> 
>   Jakub
> 



Re: [C PATCH] Fix ICE related to incomplete structures in C23 [PR114930,PR115502].

2024-06-19 Thread Martin Uecker
Am Mittwoch, dem 19.06.2024 um 08:04 +0200 schrieb Richard Biener:
> 
> > Am 18.06.2024 um 20:18 schrieb Martin Uecker :
> > 
> > Am Dienstag, dem 18.06.2024 um 17:27 +0200 schrieb Richard Biener:
> > > 
> > > > > Am 18.06.2024 um 17:20 schrieb Martin Uecker :
> > > > 
> > > > 
> > > > As discussed this replaces the use of check_qualified_type with
> > > > a simple check for qualifiers as suggested by Jakub in
> > > > c_update_type_canonical.
> > > 
> > > Note a canonical type should always be unqualified (for
> > > classical qualifiers, not address space or atomic qualification)
> > 
> > The logic in build_qualified_type is the same as in this patch,
> > it constructs TYPE_CANONICAL with qualifiers.  Or what am I
> > missing?
> 
> Nothing if you chose to do TYPE_QUALS (canonical) by copy-pasting.

I would rather like to undertand how this work. Is the following
correct?

For a type T with TYPE_CANONICAL (T) == S, if we construct a qualified
type "const" T it would get a const qualified version Q of S as 
canonical type.  S has TYPE_CANONICAL (S) == S and Q has
TYPE_CANONICAL (Q) == Q.

But the middle end would then ignore this for regular qualifiers
and use the TYPE_CANONICAL of the main variant for computing
the aliasing set?

Setting it differently for qualified types would still be important
so that derived types get their own different TYPE_CANONICAL
during construction.


The other thing I would like to confirm?  The alias set is
initialized to -1 so set later in the middle end based on
TYPE_CANONICAL (if not set to zero before).   This is never
done before the FE is finished or do we need to worry that
this may become inconsistent?

Martin

> Richard 
> 
> > Martin
> > 
> > > 
> > > Richard
> > > 
> > > > Martin
> > > > 
> > > > 
> > > > Bootstrapped and regression tested on x86_64.
> > > > 
> > > > 
> > > >   C23: Fix ICE related to incomplete structures [PR114930,PR115502].
> > > > 
> > > >   The fix for PR114574 needs to be further revised because 
> > > > check_qualified_type
> > > >   makes decision based on TYPE_NAME which can be incorrect for C when 
> > > > there
> > > >   are TYPE_DECLS involved.
> > > > 
> > > >   gcc/c/:
> > > >   * c-decl.c (c_update_type_canonical): Do not use 
> > > > check_qualified_type.
> > > > 
> > > >   gcc/testsuite/:
> > > >   * gcc.dg/pr114930.c: New test.
> > > >   * gcc.dg/pr115502.c: New test.
> > > > 
> > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > > > index 01326570e2b..610061a07f8 100644
> > > > --- a/gcc/c/c-decl.cc
> > > > +++ b/gcc/c/c-decl.cc
> > > > @@ -9374,7 +9374,7 @@ c_update_type_canonical (tree t)
> > > > if (TYPE_QUALS (x) == TYPE_QUALS (t))
> > > >   TYPE_CANONICAL (x) = TYPE_CANONICAL (t);
> > > > else if (TYPE_CANONICAL (t) != t
> > > > -   || check_qualified_type (x, t, TYPE_QUALS (x)))
> > > > +   || TYPE_QUALS (x) != TYPE_QUALS (TYPE_CANONICAL (t)))
> > > >   TYPE_CANONICAL (x)
> > > > = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
> > > > else
> > > > diff --git a/gcc/testsuite/gcc.dg/pr114930.c 
> > > > b/gcc/testsuite/gcc.dg/pr114930.c
> > > > new file mode 100644
> > > > index 000..5e982fb8929
> > > > --- /dev/null
> > > > +++ b/gcc/testsuite/gcc.dg/pr114930.c
> > > > @@ -0,0 +1,9 @@
> > > > +/* { dg-do compile }
> > > > + * { dg-options "-std=c23 -flto" } */
> > > > +
> > > > +typedef struct WebPPicture WebPPicture;
> > > > +typedef int (*WebPProgressHook)(const WebPPicture *);
> > > > +WebPProgressHook progress_hook;
> > > > +struct WebPPicture {
> > > > +} WebPGetColorPalette(const struct WebPPicture *);
> > > > +
> > > > diff --git a/gcc/testsuite/gcc.dg/pr115502.c 
> > > > b/gcc/testsuite/gcc.dg/pr115502.c
> > > > new file mode 100644
> > > > index 000..02b52622c5a
> > > > --- /dev/null
> > > > +++ b/gcc/testsuite/gcc.dg/pr115502.c
> > > > @@ -0,0 +1,9 @@
> > > > +/* { dg-do compile }
> > > > + * { dg-options "-std=c23 -flto" } */
> > > > +
> > > > +typedef struct _OSet OSet;
> > > > +typedef OSet AvlTree;
> > > > +void vgPlain_OSetGen_Lookup(const OSet *);
> > > > +struct _OSet {};
> > > > +void vgPlain_OSetGen_Lookup(const AvlTree *);
> > > > +
> > > > 
> > 



assumed size

2024-06-18 Thread Martin Uecker


Hi all,

I am working paper for the following syntax extension

int a[10];
int (*a)[*] = 


This would not be a wide pointer, it will just initialize
the size of the type from the initializer.  This would
also work for VM type.  So the result is a conventional
pointer to an arrays and either a regular or a variably
modified type.

I am not so sure how to best integrate it.  Maybe we
could just say the type becomes the composite type.


Martin


Re: [C PATCH] Fix ICE related to incomplete structures in C23 [PR114930,PR115502].

2024-06-18 Thread Martin Uecker
Am Dienstag, dem 18.06.2024 um 17:27 +0200 schrieb Richard Biener:
> 
> > Am 18.06.2024 um 17:20 schrieb Martin Uecker :
> > 
> > 
> > As discussed this replaces the use of check_qualified_type with
> > a simple check for qualifiers as suggested by Jakub in
> > c_update_type_canonical.
> 
> Note a canonical type should always be unqualified (for
> classical qualifiers, not address space or atomic qualification)

The logic in build_qualified_type is the same as in this patch,
it constructs TYPE_CANONICAL with qualifiers.  Or what am I
missing?

Martin

> 
> Richard 
> 
> > Martin
> > 
> > 
> > Bootstrapped and regression tested on x86_64.
> > 
> > 
> >C23: Fix ICE related to incomplete structures [PR114930,PR115502].
> > 
> >The fix for PR114574 needs to be further revised because 
> > check_qualified_type
> >makes decision based on TYPE_NAME which can be incorrect for C when there
> >are TYPE_DECLS involved.
> > 
> >gcc/c/:
> >* c-decl.c (c_update_type_canonical): Do not use 
> > check_qualified_type.
> > 
> >gcc/testsuite/:
> >* gcc.dg/pr114930.c: New test.
> >* gcc.dg/pr115502.c: New test.
> > 
> > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > index 01326570e2b..610061a07f8 100644
> > --- a/gcc/c/c-decl.cc
> > +++ b/gcc/c/c-decl.cc
> > @@ -9374,7 +9374,7 @@ c_update_type_canonical (tree t)
> >  if (TYPE_QUALS (x) == TYPE_QUALS (t))
> >TYPE_CANONICAL (x) = TYPE_CANONICAL (t);
> >  else if (TYPE_CANONICAL (t) != t
> > -   || check_qualified_type (x, t, TYPE_QUALS (x)))
> > +   || TYPE_QUALS (x) != TYPE_QUALS (TYPE_CANONICAL (t)))
> >TYPE_CANONICAL (x)
> >  = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
> >  else
> > diff --git a/gcc/testsuite/gcc.dg/pr114930.c 
> > b/gcc/testsuite/gcc.dg/pr114930.c
> > new file mode 100644
> > index 000..5e982fb8929
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr114930.c
> > @@ -0,0 +1,9 @@
> > +/* { dg-do compile }
> > + * { dg-options "-std=c23 -flto" } */
> > +
> > +typedef struct WebPPicture WebPPicture;
> > +typedef int (*WebPProgressHook)(const WebPPicture *);
> > +WebPProgressHook progress_hook;
> > +struct WebPPicture {
> > +} WebPGetColorPalette(const struct WebPPicture *);
> > +
> > diff --git a/gcc/testsuite/gcc.dg/pr115502.c 
> > b/gcc/testsuite/gcc.dg/pr115502.c
> > new file mode 100644
> > index 000..02b52622c5a
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr115502.c
> > @@ -0,0 +1,9 @@
> > +/* { dg-do compile }
> > + * { dg-options "-std=c23 -flto" } */
> > +
> > +typedef struct _OSet OSet;
> > +typedef OSet AvlTree;
> > +void vgPlain_OSetGen_Lookup(const OSet *);
> > +struct _OSet {};
> > +void vgPlain_OSetGen_Lookup(const AvlTree *);
> > +
> > 



[C PATCH] Fix ICE related to incomplete structures in C23 [PR114930,PR115502].

2024-06-18 Thread Martin Uecker


As discussed this replaces the use of check_qualified_type with
a simple check for qualifiers as suggested by Jakub in
c_update_type_canonical.

Martin


Bootstrapped and regression tested on x86_64.


C23: Fix ICE related to incomplete structures [PR114930,PR115502].

The fix for PR114574 needs to be further revised because 
check_qualified_type
makes decision based on TYPE_NAME which can be incorrect for C when there
are TYPE_DECLS involved.

gcc/c/:
* c-decl.c (c_update_type_canonical): Do not use 
check_qualified_type.

gcc/testsuite/:
* gcc.dg/pr114930.c: New test.
* gcc.dg/pr115502.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 01326570e2b..610061a07f8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9374,7 +9374,7 @@ c_update_type_canonical (tree t)
  if (TYPE_QUALS (x) == TYPE_QUALS (t))
TYPE_CANONICAL (x) = TYPE_CANONICAL (t);
  else if (TYPE_CANONICAL (t) != t
-  || check_qualified_type (x, t, TYPE_QUALS (x)))
+  || TYPE_QUALS (x) != TYPE_QUALS (TYPE_CANONICAL (t)))
TYPE_CANONICAL (x)
  = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
  else
diff --git a/gcc/testsuite/gcc.dg/pr114930.c b/gcc/testsuite/gcc.dg/pr114930.c
new file mode 100644
index 000..5e982fb8929
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114930.c
@@ -0,0 +1,9 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23 -flto" } */
+
+typedef struct WebPPicture WebPPicture;
+typedef int (*WebPProgressHook)(const WebPPicture *);
+WebPProgressHook progress_hook;
+struct WebPPicture {
+} WebPGetColorPalette(const struct WebPPicture *);
+
diff --git a/gcc/testsuite/gcc.dg/pr115502.c b/gcc/testsuite/gcc.dg/pr115502.c
new file mode 100644
index 000..02b52622c5a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr115502.c
@@ -0,0 +1,9 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23 -flto" } */
+
+typedef struct _OSet OSet;
+typedef OSet AvlTree;
+void vgPlain_OSetGen_Lookup(const OSet *);
+struct _OSet {};
+void vgPlain_OSetGen_Lookup(const AvlTree *);
+



[C PATCH, v4] Fix for redeclared enumerator initialized with different type [PR115109]

2024-06-17 Thread Martin Uecker


This is a new version of the patch.  This adds the -fno-short-enums flag 
to the tests. I will commit it if the CI for am does not claim this time.

Bootstrapped and regression tested on x86_64.


c23: Fix for redeclared enumerator initialized with different type 
[PR115109]

c23 specifies that the type of a redeclared enumerator is the one of the
previous declaration.  Convert initializers with different type accordingly
and emit an error when the value does not fit.

2024-06-01 Martin Uecker  

PR c/115109

gcc/c/
* c-decl.cc (build_enumerator): When redeclaring an
enumerator convert value to previous type.  For redeclared
enumerators use underlying type for computing the next value.

gcc/testsuite/
* gcc.dg/pr115109.c: New test.
* gcc.dg/c23-tag-enum-6.c: New test.
* gcc.dg/c23-tag-enum-7.c: New test.

commit c8a0ec5150299689e6e36b0044ea811b82d90b2f
Author: Martin Uecker 
Date:   Sat May 18 22:00:04 2024 +0200

c23: Fix for redeclared enumerator initialized with different type 
[PR115109]

c23 specifies that the type of a redeclared enumerator is the one of the
previous declaration.  Convert initializers with different type accordingly
and emit an error when the value does not fit.

2024-06-01 Martin Uecker  

PR c/115109

gcc/c/
* c-decl.cc (build_enumerator): When redeclaring an
enumerator convert value to previous type.  For redeclared
enumerators use underlying type for computing the next value.

gcc/testsuite/
* gcc.dg/pr115109.c: New test.
* gcc.dg/c23-tag-enum-6.c: New test.
* gcc.dg/c23-tag-enum-7.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6c09eb73128..01326570e2b 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10277,6 +10277,7 @@ build_enumerator (location_t decl_loc, location_t loc,
  struct c_enum_contents *the_enum, tree name, tree value)
 {
   tree decl;
+  tree old_decl;
 
   /* Validate and default VALUE.  */
 
@@ -10336,6 +10337,23 @@ build_enumerator (location_t decl_loc, location_t loc,
 definition.  */
   value = convert (the_enum->enum_type, value);
 }
+  else if (flag_isoc23
+  && (old_decl = lookup_name_in_scope (name, current_scope))
+  && old_decl != error_mark_node
+  && TREE_TYPE (old_decl)
+  && TREE_TYPE (TREE_TYPE (old_decl))
+  && TREE_CODE (old_decl) == CONST_DECL)
+{
+  /* Enumeration constants in a redeclaration have the previous type.  */
+  tree previous_type = TREE_TYPE (DECL_INITIAL (old_decl));
+  if (!int_fits_type_p (value, previous_type))
+   {
+ error_at (loc, "value of redeclared enumerator outside the range "
+"of %qT", previous_type);
+ locate_old_decl (old_decl);
+   }
+  value = convert (previous_type, value);
+}
   else
 {
   /* Even though the underlying type of an enum is unspecified, the
@@ -10402,9 +10420,14 @@ build_enumerator (location_t decl_loc, location_t loc,
 false);
 }
   else
-the_enum->enum_next_value
-  = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
-PLUS_EXPR, value, integer_one_node, false);
+{
+  /* In a redeclaration the type can already be the enumeral type.  */
+  if (TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE)
+   value = convert (ENUM_UNDERLYING_TYPE (TREE_TYPE (value)), value);
+  the_enum->enum_next_value
+   = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
+  PLUS_EXPR, value, integer_one_node, false);
+}
   the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value);
   if (the_enum->enum_overflow
   && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type))
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
new file mode 100644
index 000..29aef7ee3fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -fno-short-enums" } */
+
+#include 
+
+enum E : int { a = 1, b = 2 };
+enum E : int { b = _Generic(a, enum E: 2), a = 1 };
+
+enum H { x = 1 };
+enum H { x = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */
+
+enum K : int { z = 1 };
+enum K : int { z = 2UL + UINT_MAX };   /* { dg-error "outside the range" } */
+
+enum F { A = 0, B = UINT_MAX };
+enum F { B = UINT_MAX, A };/* { dg-error "outside the range" } */
+
+enum G : unsigned int { C = 0, D = UINT_MAX };
+enum G : unsigned int { D = UINT_MAX, C }; /* { dg-error 
"overflow" } */
+
diff --git a/

Re: [C PATCH, v3] Fix for redeclared enumerator initialized with different type [PR115109]

2024-06-15 Thread Martin Uecker


The patch fails on arm because the tests make assumptions
about enums that are not true everywhere. Should we just 
limit the tests to x86?

Martin

Am Montag, dem 03.06.2024 um 17:37 + schrieb Joseph Myers:
> On Sat, 1 Jun 2024, Martin Uecker wrote:
> 
> > This is a new version of the patch.  I changed the overflow warning to
> > an error and added your other example to the test case.
> > 
> > Bootstrapped and regression tested on x86_64.
> > 
> > 
> > c23: Fix for redeclared enumerator initialized with different type 
> > [PR115109]
> > 
> > c23 specifies that the type of a redeclared enumerator is the one of the
> > previous declaration.  Convert initializers with different type 
> > accordingly
> >     and emit an error when the value does not fit.
> > 
> > 2024-06-01 Martin Uecker  
> > 
> > PR c/115109
> > 
> > gcc/c/
> > * c-decl.cc (build_enumerator): When redeclaring an
> > enumerator convert value to previous type.  For redeclared
> > enumerators use underlying type for computing the next value.
> > 
> > gcc/testsuite/
> > * gcc.dg/pr115109.c: New test.
> > * gcc.dg/c23-tag-enum-6.c: New test.
> > * gcc.dg/c23-tag-enum-7.c: New test.
> 
> OK.
> 



Re: [PATCH] c: Fix up pointer types to may_alias structures [PR114493]

2024-06-05 Thread Martin Uecker
Am Dienstag, dem 04.06.2024 um 08:33 +0200 schrieb Jakub Jelinek:
> Hi!
> 
> The following testcase ICEs in ipa-free-lang, because the
> fld_incomplete_type_of
>   gcc_assert (TYPE_CANONICAL (t2) != t2
>   && TYPE_CANONICAL (t2) == TYPE_CANONICAL (TREE_TYPE 
> (t)));
> assertion doesn't hold.
> This is because t is a struct S * type which was created while struct S
> was still incomplete and without the may_alias attribute (and TYPE_CANONICAL
> of a pointer type is a type created with can_alias_all = false argument),
> while later on on the struct definition may_alias attribute was used.
> fld_incomplete_type_of then creates an incomplete distinct copy of the
> structure (but with the original attributes) but pointers created for it
> are because of the "may_alias" attribute TYPE_REF_CAN_ALIAS_ALL, including
> their TYPE_CANONICAL, because while that is created with !can_alias_all
> argument, we later set it because of the "may_alias" attribute on the
> to_type.
> 
> This doesn't ICE with C++ since PR70512 fix because the C++ FE sets
> TYPE_REF_CAN_ALIAS_ALL on all pointer types to the class type (and its
> variants) when the may_alias is added.
> 
> The following patch does that in the C FE as well.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and
> release branches?

>From my (irrelevant) side this patch looks good.

Martin

> 
> 2024-06-04  Jakub Jelinek  
> 
>   PR c/114493
>   * c-decl.cc (c_fixup_may_alias): New function.
>   (finish_struct): Call it if "may_alias" attribute is
>   specified.
> 
>   * gcc.dg/pr114493-1.c: New test.
>   * gcc.dg/pr114493-2.c: New test.
> 
> --- gcc/c/c-decl.cc.jj2024-05-07 08:47:35.974836903 +0200
> +++ gcc/c/c-decl.cc   2024-06-03 19:55:53.819586291 +0200
> @@ -9446,6 +9446,17 @@ verify_counted_by_attribute (tree struct
>return;
>  }
>  
> +/* TYPE is a struct or union that we're applying may_alias to after the body 
> is
> +   parsed.  Fixup any POINTER_TO types.  */
> +
> +static void
> +c_fixup_may_alias (tree type)
> +{
> +  for (tree t = TYPE_POINTER_TO (type); t; t = TYPE_NEXT_PTR_TO (t))
> +for (tree v = TYPE_MAIN_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
> +  TYPE_REF_CAN_ALIAS_ALL (v) = true;
> +}
> +
>  /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
> LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
> FIELDLIST is a chain of FIELD_DECL nodes for the fields.
> @@ -9791,6 +9802,10 @@ finish_struct (location_t loc, tree t, t
>  
>C_TYPE_BEING_DEFINED (t) = 0;
>  
> +  if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (t)))
> +for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
> +  c_fixup_may_alias (x);
> +
>/* Set type canonical based on equivalence class.  */
>if (flag_isoc23 && !C_TYPE_VARIABLE_SIZE (t))
>  {
> --- gcc/testsuite/gcc.dg/pr114493-1.c.jj  2024-06-03 19:59:58.774336785 
> +0200
> +++ gcc/testsuite/gcc.dg/pr114493-1.c 2024-06-03 19:59:12.931944923 +0200
> @@ -0,0 +1,19 @@
> +/* PR c/114493 */
> +/* { dg-do compile { target lto } } */
> +/* { dg-options "-O2 -flto" } */
> +
> +void foo (void);
> +struct S;
> +struct S bar (struct S **);
> +struct S qux (const struct S **);
> +
> +struct __attribute__((__may_alias__)) S {
> +  int s;
> +};
> +
> +struct S
> +baz (void)
> +{
> +  foo ();
> +  return (struct S) {};
> +}
> --- gcc/testsuite/gcc.dg/pr114493-2.c.jj  2024-06-03 19:59:58.774336785 
> +0200
> +++ gcc/testsuite/gcc.dg/pr114493-2.c 2024-06-03 20:01:00.886512830 +0200
> @@ -0,0 +1,26 @@
> +/* PR c/114493 */
> +/* { dg-do compile { target lto } } */
> +/* { dg-options "-O2 -flto -std=c23" } */
> +
> +void foo (void);
> +struct S;
> +struct S bar (struct S **);
> +struct S qux (const struct S **);
> +
> +void
> +corge (void)
> +{
> +  struct S { int s; } s;
> +  s.s = 0;
> +}
> +
> +struct __attribute__((__may_alias__)) S {
> +  int s;
> +};
> +
> +struct S
> +baz (void)
> +{
> +  foo ();
> +  return (struct S) {};
> +}
> 
>   Jakub
> 



[C PATCH, v3] Fix for redeclared enumerator initialized with different type [PR115109]

2024-06-01 Thread Martin Uecker


This is a new version of the patch.  I changed the overflow warning to
an error and added your other example to the test case.

Bootstrapped and regression tested on x86_64.


c23: Fix for redeclared enumerator initialized with different type 
[PR115109]

c23 specifies that the type of a redeclared enumerator is the one of the
previous declaration.  Convert initializers with different type accordingly
and emit an error when the value does not fit.

2024-06-01 Martin Uecker  

PR c/115109

gcc/c/
* c-decl.cc (build_enumerator): When redeclaring an
enumerator convert value to previous type.  For redeclared
enumerators use underlying type for computing the next value.

gcc/testsuite/
* gcc.dg/pr115109.c: New test.
* gcc.dg/c23-tag-enum-6.c: New test.
* gcc.dg/c23-tag-enum-7.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64924b87a91..38a4e842307 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10262,6 +10262,7 @@ build_enumerator (location_t decl_loc, location_t loc,
  struct c_enum_contents *the_enum, tree name, tree value)
 {
   tree decl;
+  tree old_decl;
 
   /* Validate and default VALUE.  */
 
@@ -10321,6 +10322,23 @@ build_enumerator (location_t decl_loc, location_t loc,
 definition.  */
   value = convert (the_enum->enum_type, value);
 }
+  else if (flag_isoc23
+  && (old_decl = lookup_name_in_scope (name, current_scope))
+  && old_decl != error_mark_node
+  && TREE_TYPE (old_decl)
+  && TREE_TYPE (TREE_TYPE (old_decl))
+  && TREE_CODE (old_decl) == CONST_DECL)
+{
+  /* Enumeration constants in a redeclaration have the previous type.  */
+  tree previous_type = TREE_TYPE (DECL_INITIAL (old_decl));
+  if (!int_fits_type_p (value, previous_type))
+   {
+ error_at (loc, "value of redeclared enumerator outside the range "
+"of %qT", previous_type);
+ locate_old_decl (old_decl);
+   }
+  value = convert (previous_type, value);
+}
   else
 {
   /* Even though the underlying type of an enum is unspecified, the
@@ -10387,9 +10405,14 @@ build_enumerator (location_t decl_loc, location_t loc,
 false);
 }
   else
-the_enum->enum_next_value
-  = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
-PLUS_EXPR, value, integer_one_node, false);
+{
+  /* In a redeclaration the type can already be the enumeral type.  */
+  if (TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE)
+   value = convert (ENUM_UNDERLYING_TYPE (TREE_TYPE (value)), value);
+  the_enum->enum_next_value
+   = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
+  PLUS_EXPR, value, integer_one_node, false);
+}
   the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value);
   if (the_enum->enum_overflow
   && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type))
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
new file mode 100644
index 000..0fa5d7534f3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+#include 
+
+enum E : int { a = 1, b = 2 };
+enum E : int { b = _Generic(a, enum E: 2), a = 1 };
+
+enum H { x = 1 };
+enum H { x = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */
+
+enum K : int { z = 1 };
+enum K : int { z = 2UL + UINT_MAX };   /* { dg-error "outside the range" } */
+
+enum F { A = 0, B = UINT_MAX };
+enum F { B = UINT_MAX, A };/* { dg-error "outside the range" } */
+
+enum G : unsigned int { C = 0, D = UINT_MAX };
+enum G : unsigned int { D = UINT_MAX, C }; /* { dg-error 
"overflow" } */
+
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
new file mode 100644
index 000..0634c0aa698
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
@@ -0,0 +1,41 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23" } */
+
+#include 
+
+// enumerators are all representable in int
+enum E { a = 1UL, b = _Generic(a, int: 2) };
+static_assert(_Generic(a, int: 1));
+static_assert(_Generic(b, int: 1));
+enum E { a = 1UL, b = _Generic(a, int: 2) };
+static_assert(_Generic(a, int: 1));
+static_assert(_Generic(b, int: 1));
+
+// enumerators are not representable in int
+enum H { c = 1UL << (UINT_WIDTH + 1), d = 2 };
+static_assert(_Generic(c, enum H: 1));
+static_assert(_Generic(d, enum H: 1));
+enum H { c = 1UL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) };
+static_assert(_Generic(c, enum H: 1));
+static_assert(_Generi

Re: [C PATCH, v2]: allow aliasing of compatible types derived from enumeral types [PR115157]

2024-05-30 Thread Martin Uecker


Hi Ian,

can you give me a green light for the go changes. The C FE
changes were approved.

The only change with respect to the last version are
the removal of the unneeded null check for the
main variant (as discussed) and that I also removed the

container->decls_seen.add (TREE_TYPE (decl));

and the corresponding check, because I think it is
redundant if we also test for the main variant.
(it wasn't with TYPE_CANONICAL because this was
only added conditionally).

The other code in the file only checks for added
declarations not types, so should not depend on this.

Martin


Am Freitag, dem 24.05.2024 um 17:39 +0200 schrieb Martin Uecker:
> This is another version of this patch with two changes:
> 
> - I added a fix (with test) for PR 115177 which is just the same
> issue for hardbools which are internally implemented as enums.
> 
> - I fixed the golang issue. Since the addition of the main variant
> to the seen decls is unconditional I removed also the addition
> of the type itself which now seems unnecessary.
> 
> Bootstrapped and regression tested on x86_64.
> 
> Martin
> 
> 
> 
> C: allow aliasing of compatible types derived from enumeral types 
> [PR115157]
> 
> Aliasing of enumeral types with the underlying integer is now allowed
> by setting the aliasing set to zero.  But this does not allow aliasing
> of derived types which are compatible as required by ISO C.  Instead,
> initially set structural equality.  Then set TYPE_CANONICAL and update
> pointers and main variants when the type is completed (as done for
> structures and unions in C23).
> 
> PR 115157
> PR 115177
> 
> gcc/c/
> * c-decl.cc (shadow_tag-warned,parse_xref_tag,start_enum,
> finish_enum): Set SET_TYPE_STRUCTURAL_EQUALITY / TYPE_CANONICAL.
> * c-obj-common.cc (get_alias_set): Remove special case.
> (get_aka_type): Add special case.
> 
> gcc/c-family/
> * c-attribs.cc (handle_hardbool_attribute): Set TYPE_CANONICAL
> for hardbools.
> 
> gcc/
> * godump.cc (go_output_typedef): use TYPE_MAIN_VARIANT instead
> of TYPE_CANONICAL.
> 
> gcc/testsuite/
> * gcc.dg/enum-alias-1.c: New test.
> * gcc.dg/enum-alias-2.c: New test.
> * gcc.dg/enum-alias-3.c: New test.
> * gcc.dg/enum-alias-4.c: New test.
> 
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index 04e39b41bdf..033395093b6 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -1074,6 +1074,7 @@ handle_hardbool_attribute (tree *node, tree name, tree 
> args,
>  
>TREE_SET_CODE (*node, ENUMERAL_TYPE);
>ENUM_UNDERLYING_TYPE (*node) = orig;
> +  TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig);
>  
>tree false_value;
>if (args)
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index b691b91b3db..6e6606c9570 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -5051,7 +5051,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, 
> int warned)
> if (t == NULL_TREE)
>   {
> t = make_node (code);
> -   if (flag_isoc23 && code != ENUMERAL_TYPE)
> +   if (flag_isoc23 || code == ENUMERAL_TYPE)
>   SET_TYPE_STRUCTURAL_EQUALITY (t);
> pushtag (input_location, name, t);
>   }
> @@ -8828,7 +8828,7 @@ parser_xref_tag (location_t loc, enum tree_code code, 
> tree name,
>   the forward-reference will be altered into a real type.  */
>  
>ref = make_node (code);
> -  if (flag_isoc23 && code != ENUMERAL_TYPE)
> +  if (flag_isoc23 || code == ENUMERAL_TYPE)
>  SET_TYPE_STRUCTURAL_EQUALITY (ref);
>if (code == ENUMERAL_TYPE)
>  {
> @@ -9919,6 +9919,7 @@ start_enum (location_t loc, struct c_enum_contents 
> *the_enum, tree name,
>  {
>enumtype = make_node (ENUMERAL_TYPE);
>TYPE_SIZE (enumtype) = NULL_TREE;
> +  SET_TYPE_STRUCTURAL_EQUALITY (enumtype);
>pushtag (loc, name, enumtype);
>if (fixed_underlying_type != NULL_TREE)
>   {
> @@ -9935,6 +9936,8 @@ start_enum (location_t loc, struct c_enum_contents 
> *the_enum, tree name,
> TYPE_SIZE (enumtype) = NULL_TREE;
> TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type);
> ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type;
> +   TYPE_CANONICAL (enumtype) = TYPE_CANONICAL (fixed_underlying_type);
> +   c_update_type_canonical (enumtype);
> layout_type (enumtype);
>   }
>  }
> @@ -10094,6 

[C23 PATCH]: allow aliasing for types derived from structs with variable size

2024-05-26 Thread Martin Uecker


This is similar to the enum issue, where setting the alias set to zero
is insufficient because also derived types need to be able to alias.

After this change, it is also possible to add checking assertions that
verify TYPE_CANONICAL for all tagged types at end of each call to the
comptypes family.  At least for the test suite this then shows no
additional issues for tagged types.   

(We still make incorrect aliasing decisions at least for types derived 
from  functions types (PR114959) but this is an ancient issue.  We
probably should set TYPE_CANONICAL in the FE similar to what is done
for tagged types in C23.)


Bootstrapped and regression tested on x86_64.



C23: allow aliasing for types derived from structs with variable size

Previously, we set the aliasing set of structures with variable size

struct foo { int x[n]; char b; };

to zero. The reason is that such types can be compatible to diffrent
structure types which are incompatible.

struct foo { int x[2]; char b; };
struct foo { int x[3]; char b; };

But it is not enough to set the aliasing set to zero, because derived
types would then still end up in different equivalence classes even
though they might be compatible.  Instead those types should be set
to structural equivalency.  We also add checking assertions that
ensure that TYPE_CANONICAL is set correctly for all tagged types

gcc/c/
* c-decl.cc (finish_struct): Do not set TYPE_CANONICAL for
structure or unions with variable size.
* c-objc-common.cc (c_get_alias_set): Do not set alias set to zero.
* c-typeck.cc (comptypes_verify): New function.
(comptypes,comptypes_same_p,comptypes_check_enum_int): Add 
assertion.
(comptypes_equiv_p): Add assertion that ensures that compatible
types have the same equivalence class.
(tagged_types_tu_compatible_p): Remove now unneeded special case.

gcc/testsuite/
* gcc.dg/gnu23-tag-alias-8.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6e6606c9570..9f7d55c0b10 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9749,7 +9749,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_isoc23)
+  if (flag_isoc23 && !C_TYPE_VARIABLE_SIZE (t))
 {
   if (c_struct_htab == NULL)
c_struct_htab = hash_table::create_ggc (61);
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 551ec6f4b65..29127d037e1 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -420,11 +420,6 @@ c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED)
 alias_set_type
 c_get_alias_set (tree 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-typeck.cc b/gcc/c/c-typeck.cc
index 2d092357e0f..c07e2f2b5cf 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1167,6 +1167,28 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+
+
+/* Helper function for comptypes.  For two compatible types, return 1
+   if they pass consistency checks.  In particular we test that
+   TYPE_CANONICAL ist set correctly, i.e. the two types can alias.  */
+
+static bool
+comptypes_verify (tree type1, tree type2)
+{
+  if (TYPE_CANONICAL (type1) != TYPE_CANONICAL (type2)
+  && !TYPE_STRUCTURAL_EQUALITY_P (type1)
+  && !TYPE_STRUCTURAL_EQUALITY_P (type2))
+{
+  /* FIXME: check other types. */
+  if (RECORD_OR_UNION_TYPE_P (type1)
+ || TREE_CODE (type1) == ENUMERAL_TYPE
+ || TREE_CODE (type2) == ENUMERAL_TYPE)
+   return false;
+}
+  return true;
+}
+
 struct comptypes_data {
   bool enum_and_int_p;
   bool different_types_p;
@@ -1187,6 +1209,8 @@ comptypes (tree type1, tree type2)
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, );
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1200,6 +1224,8 @@ comptypes_same_p (tree type1, tree type2)
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, );
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   if (data.different_types_p)
 return false;
 
@@ -1217,6 +1243,8 @@ comptypes_check_enum_int (tree type1, tree type2, bool 
*enum_and_int_p)
   bool ret = comptypes_internal (type1, type2, );
   *enum_and_int_p = data.enum_and_int_p;
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1231,6 +1259,8 @@ comptypes_check_different_types (tree type1, tree type2,
   bool ret = comptypes_internal 

[C23 PATCH, v2] fix aliasing for structures/unions with incomplete types

2024-05-26 Thread Martin Uecker


This is the patch I sent previously, but I tried to improve the
description and added a long comment.  This patch is needed so
that we do not have to update TYPE_CANONICAL of structures / unions
when a tagged type is completed that is (recursively) pointed to 
by a member of the structure / union.

Bootstrapped and regression tested on x86_64.


C23: fix aliasing for structures/unions with incomplete types

When incomplete structure/union types are completed later, compatibility
of struct types that contain pointers to such types changes.  When forming
equivalence classes for TYPE_CANONICAL, we therefor need to be conservative
and treat all structs with the same tag which are pointer targets as
equivalent for purposed of determining equivalency of structure/union
types which contain such types as member. This avoids having to update
TYPE_CANONICAL of such structure/unions recursively. The pointer types
themselves are updated in c_update_type_canonical.

gcc/c/
* c-typeck.cc (comptypes_internal): Add flag to track
whether a struct is the target of a pointer.
(tagged_types_tu_compatible): When forming equivalence
classes, treat nested pointed-to structs as equivalent.

gcc/testsuite/
* gcc.dg/c23-tag-incomplete-alias-1.c: New test.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index c07e2f2b5cf..7a14ef1868f 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1194,6 +1194,7 @@ struct comptypes_data {
   bool different_types_p;
   bool warning_needed;
   bool anon_field;
+  bool pointedto;
   bool equiv;
 
   const struct tagged_tu_seen_cache* cache;
@@ -1265,8 +1266,36 @@ comptypes_check_different_types (tree type1, tree type2,
 }
 
 
-/* Like comptypes, but if it returns nonzero for struct and union
-   types considered equivalent for aliasing purposes.  */
+/* Like comptypes, but if it returns true for struct and union types
+   considered equivalent for aliasing purposes, i.e. for setting
+   TYPE_CANONICAL after completing a struct or union.
+
+   This function must return false only for types which are not
+   compatible according to C language semantics (cf. comptypes),
+   otherwise the middle-end would make incorrect aliasing decisions.
+   It may return true for some similar types that are not compatible
+   according to those stricter rules.
+
+   In particular, we ignore size expression in arrays so that the
+   following structs are in the same equivalence class:
+
+   struct foo { char (*buf)[]; };
+   struct foo { char (*buf)[3]; };
+   struct foo { char (*buf)[4]; };
+
+   We also treat unions / structs with members which are pointers to
+   structures or unions with the same tag as equivalent (if they are not
+   incompatible for other reasons).  Although incomplete structure
+   or union types are not compatible to any other type, they may become
+   compatible to different types when completed.  To avoid having to update
+   TYPE_CANONICAL at this point, we only consider the tag when forming
+   the equivalence classes.  For example, the following types with tag
+   'foo' are all considered equivalent:
+
+   struct bar;
+   struct foo { struct bar *x };
+   struct foo { struct bar { int a; } *x };
+   struct foo { struct bar { char b; } *x };  */
 
 bool
 comptypes_equiv_p (tree type1, tree type2)
@@ -1391,6 +1420,7 @@ comptypes_internal (const_tree type1, const_tree type2,
   /* Do not remove mode information.  */
   if (TYPE_MODE (t1) != TYPE_MODE (t2))
return false;
+  data->pointedto = true;
   return comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data);
 
 case FUNCTION_TYPE:
@@ -1409,7 +1439,7 @@ comptypes_internal (const_tree type1, const_tree type2,
 
if ((d1 == NULL_TREE) != (d2 == NULL_TREE))
  data->different_types_p = true;
-   /* Ignore size mismatches.  */
+   /* Ignore size mismatches when forming equivalence classes.  */
if (data->equiv)
  return true;
/* Sizes must match unless one is missing or variable.  */
@@ -1549,6 +1579,12 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
   if (TYPE_NAME (t1) != TYPE_NAME (t2))
 return false;
 
+  /* When forming equivalence classes for TYPE_CANONICAL in C23, we treat
+ structs with the same tag as equivalent, but only when they are targets
+ of pointers inside other structs.  */
+  if (data->equiv && data->pointedto)
+return true;
+
   if (!data->anon_field && NULL_TREE == TYPE_NAME (t1))
 return false;
 
@@ -1641,6 +1677,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
  return false;
 
data->anon_field = !DECL_NAME (s1);
+   data->pointedto = false;
 
data->cache = 
if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data))
diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-alias-1.c 

[C PATCH, v2]: allow aliasing of compatible types derived from enumeral types [PR115157]

2024-05-24 Thread Martin Uecker


This is another version of this patch with two changes:

- I added a fix (with test) for PR 115177 which is just the same
issue for hardbools which are internally implemented as enums.

- I fixed the golang issue. Since the addition of the main variant
to the seen decls is unconditional I removed also the addition
of the type itself which now seems unnecessary.

Bootstrapped and regression tested on x86_64.

Martin



C: allow aliasing of compatible types derived from enumeral types [PR115157]

Aliasing of enumeral types with the underlying integer is now allowed
by setting the aliasing set to zero.  But this does not allow aliasing
of derived types which are compatible as required by ISO C.  Instead,
initially set structural equality.  Then set TYPE_CANONICAL and update
pointers and main variants when the type is completed (as done for
structures and unions in C23).

PR 115157
PR 115177

gcc/c/
* c-decl.cc (shadow_tag-warned,parse_xref_tag,start_enum,
finish_enum): Set SET_TYPE_STRUCTURAL_EQUALITY / TYPE_CANONICAL.
* c-obj-common.cc (get_alias_set): Remove special case.
(get_aka_type): Add special case.

gcc/c-family/
* c-attribs.cc (handle_hardbool_attribute): Set TYPE_CANONICAL
for hardbools.

gcc/
* godump.cc (go_output_typedef): use TYPE_MAIN_VARIANT instead
of TYPE_CANONICAL.

gcc/testsuite/
* gcc.dg/enum-alias-1.c: New test.
* gcc.dg/enum-alias-2.c: New test.
* gcc.dg/enum-alias-3.c: New test.
* gcc.dg/enum-alias-4.c: New test.

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 04e39b41bdf..033395093b6 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -1074,6 +1074,7 @@ handle_hardbool_attribute (tree *node, tree name, tree 
args,
 
   TREE_SET_CODE (*node, ENUMERAL_TYPE);
   ENUM_UNDERLYING_TYPE (*node) = orig;
+  TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig);
 
   tree false_value;
   if (args)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b691b91b3db..6e6606c9570 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5051,7 +5051,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, 
int warned)
  if (t == NULL_TREE)
{
  t = make_node (code);
- if (flag_isoc23 && code != ENUMERAL_TYPE)
+ if (flag_isoc23 || code == ENUMERAL_TYPE)
SET_TYPE_STRUCTURAL_EQUALITY (t);
  pushtag (input_location, name, t);
}
@@ -8828,7 +8828,7 @@ parser_xref_tag (location_t loc, enum tree_code code, 
tree name,
  the forward-reference will be altered into a real type.  */
 
   ref = make_node (code);
-  if (flag_isoc23 && code != ENUMERAL_TYPE)
+  if (flag_isoc23 || code == ENUMERAL_TYPE)
 SET_TYPE_STRUCTURAL_EQUALITY (ref);
   if (code == ENUMERAL_TYPE)
 {
@@ -9919,6 +9919,7 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
 {
   enumtype = make_node (ENUMERAL_TYPE);
   TYPE_SIZE (enumtype) = NULL_TREE;
+  SET_TYPE_STRUCTURAL_EQUALITY (enumtype);
   pushtag (loc, name, enumtype);
   if (fixed_underlying_type != NULL_TREE)
{
@@ -9935,6 +9936,8 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
  TYPE_SIZE (enumtype) = NULL_TREE;
  TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type);
  ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type;
+ TYPE_CANONICAL (enumtype) = TYPE_CANONICAL (fixed_underlying_type);
+ c_update_type_canonical (enumtype);
  layout_type (enumtype);
}
 }
@@ -10094,6 +10097,10 @@ finish_enum (tree enumtype, tree values, tree 
attributes)
   ENUM_UNDERLYING_TYPE (enumtype) =
c_common_type_for_size (TYPE_PRECISION (tem), TYPE_UNSIGNED (tem));
 
+  TYPE_CANONICAL (enumtype) =
+   TYPE_CANONICAL (ENUM_UNDERLYING_TYPE (enumtype));
+  c_update_type_canonical (enumtype);
+
   layout_type (enumtype);
 }
 
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index b7c72d2609c..551ec6f4b65 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -130,6 +130,8 @@ get_aka_type (tree type)
 
   result = get_aka_type (orig_type);
 }
+  else if (TREE_CODE (type) == ENUMERAL_TYPE)
+return type;
   else
 {
   tree canonical = TYPE_CANONICAL (type);
@@ -418,11 +420,6 @@ c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED)
 alias_set_type
 c_get_alias_set (tree t)
 {
-  /* Allow aliasing between enumeral types and the underlying
- integer type.  This is required since those are compatible types.  */
-  if (TREE_CODE (t) == ENUMERAL_TYPE)
-return get_alias_set (ENUM_UNDERLYING_TYPE (t));
-
   /* Structs with variable size can alias different incompatible
  structs.  Let 

Re: [C PATCH]: allow aliasing of compatible types derived from enumeral types [PR115157]

2024-05-23 Thread Martin Uecker
Am Donnerstag, dem 23.05.2024 um 14:30 -0700 schrieb Ian Lance Taylor:
> On Thu, May 23, 2024 at 2:00 PM Joseph Myers  wrote:
> > 
> > On Tue, 21 May 2024, Martin Uecker wrote:
> > > 
> > > C: allow aliasing of compatible types derived from enumeral types 
> > > [PR115157]
> > > 
> > > Aliasing of enumeral types with the underlying integer is now allowed
> > > by setting the aliasing set to zero.  But this does not allow aliasing
> > > of derived types which are compatible as required by ISO C.  Instead,
> > > initially set structural equality.  Then set TYPE_CANONICAL and update
> > > pointers and main variants when the type is completed (as done for
> > > structures and unions in C23).
> > > 
> > > PR 115157
> > > 
> > > gcc/c/
> > > * c-decl.cc (shadow_tag-warned,parse_xref_tag,start_enum,
> > > finish_enum): Set SET_TYPE_STRUCTURAL_EQUALITY / 
> > > TYPE_CANONICAL.
> > > * c-obj-common.cc (get_alias_set): Remove special case.
> > > (get_aka_type): Add special case.
> > > 
> > > gcc/
> > > * godump.cc (go_output_typedef): use TYPE_MAIN_VARIANT instead
> > > of TYPE_CANONICAL.
> > > 
> > > gcc/testsuite/
> > > * gcc.dg/enum-alias-1.c: New test.
> > > * gcc.dg/enum-alias-2.c: New test.
> > > * gcc.dg/enum-alias-3.c: New test.
> > 
> > OK, in the absence of objections on middle-end or Go grounds within the
> > next week.
> 
> The godump.cc patch is
> 
>&& (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
>   || !container->decls_seen.contains
> -   (TYPE_CANONICAL (TREE_TYPE (decl)
> +   (TYPE_MAIN_VARIANT (TREE_TYPE (decl)
>  {
> 
> What is the problem you are seeing?

Test failures in godump-1.c

> 
> This patch isn't right:
> 
> 1) The code is saying if "X == NULL_TREE || !already_seen(X)".  This
> patch is changing the latter X but not the former.  They should be
> consistent.

Maybe the X == NULL_TREE can be removed if we
add TYPE_MAIN_VARIANTs instead?

> 
> 2) At the bottom of that conditional block is code that adds a value
> to container->decls_seen.  Today that code is adding TYPE_CANONICAL.
> If we change the condition to test TYPE_MAIN_VARIANT, then we need to
> add TYPE_MAIN_VARIANT to decls_seen.

Yes, obviously this is wrong. Thanks!

Martin
> 
> Hope that makes sense.
> 
> I don't know why the patch is required, but it's fine with those
> changes as long as the libgo tests continue to pass.


> 
> Ian



[C PATCH]: allow aliasing of compatible types derived from enumeral types [PR115157]

2024-05-21 Thread Martin Uecker


For enum and integer we allow aliasing by specifically returning
via a langhook the aliasing set of the underlying type.
But this is not sufficient for derived types, i.e. pointers to
enums and pointers to compatible integers also need to have the
same aliasing set.

We also allow forward declarations of enums which is a GNU 
extension, but I think this has to work consistently too, so
we here have the same issue as in C23 with other tagged types.

The solution in this patch is similar to what we do in C23, i.e. 
we start out with structural equality and then set TYPE_CANONICAL 
to the underlying type. The only way to make the TYPE_CANONICAL 
system work with the C rules for type compatility seems to set 
TYPE_CANONICAL to the same type for all types in a compatibility
equivalence class (as compatibility is not transitive this puts
together similar types that are not compatible). This is the
underlying type in this case.  As all types in such an equivalence
class have the same representation, so this should always work 
in my opinion (but maybe there is some middle end aspects I am
still missing).


When testing, I so far only found two minor issues, i.e. when
computing the 'aka' type in diagnostics and an issue with
godump.cc (not sure I fixed this correctly).


Beyond this patch, we need also some change for function types 
in general and there are problably also some other issues related
to incomplete arrays as well  (I added some checking to 'comptypes'
to check that all types ruled compatible by the C FE also have 
either structural equality, or have the same TYPE_CANONICAL, and
this brings up some more inconsistencies).

Thoughts?


Bootstrapped and regression tested on x86_64 (only C, C++ so far).




C: allow aliasing of compatible types derived from enumeral types [PR115157]

Aliasing of enumeral types with the underlying integer is now allowed
by setting the aliasing set to zero.  But this does not allow aliasing
of derived types which are compatible as required by ISO C.  Instead,
initially set structural equality.  Then set TYPE_CANONICAL and update
pointers and main variants when the type is completed (as done for
structures and unions in C23).

PR 115157

gcc/c/
* c-decl.cc (shadow_tag-warned,parse_xref_tag,start_enum,
finish_enum): Set SET_TYPE_STRUCTURAL_EQUALITY / TYPE_CANONICAL.
* c-obj-common.cc (get_alias_set): Remove special case.
(get_aka_type): Add special case.

gcc/
* godump.cc (go_output_typedef): use TYPE_MAIN_VARIANT instead
of TYPE_CANONICAL.

gcc/testsuite/
* gcc.dg/enum-alias-1.c: New test.
* gcc.dg/enum-alias-2.c: New test.
* gcc.dg/enum-alias-3.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b691b91b3db..6e6606c9570 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5051,7 +5051,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, 
int warned)
  if (t == NULL_TREE)
{
  t = make_node (code);
- if (flag_isoc23 && code != ENUMERAL_TYPE)
+ if (flag_isoc23 || code == ENUMERAL_TYPE)
SET_TYPE_STRUCTURAL_EQUALITY (t);
  pushtag (input_location, name, t);
}
@@ -8828,7 +8828,7 @@ parser_xref_tag (location_t loc, enum tree_code code, 
tree name,
  the forward-reference will be altered into a real type.  */
 
   ref = make_node (code);
-  if (flag_isoc23 && code != ENUMERAL_TYPE)
+  if (flag_isoc23 || code == ENUMERAL_TYPE)
 SET_TYPE_STRUCTURAL_EQUALITY (ref);
   if (code == ENUMERAL_TYPE)
 {
@@ -9919,6 +9919,7 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
 {
   enumtype = make_node (ENUMERAL_TYPE);
   TYPE_SIZE (enumtype) = NULL_TREE;
+  SET_TYPE_STRUCTURAL_EQUALITY (enumtype);
   pushtag (loc, name, enumtype);
   if (fixed_underlying_type != NULL_TREE)
{
@@ -9935,6 +9936,8 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
  TYPE_SIZE (enumtype) = NULL_TREE;
  TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type);
  ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type;
+ TYPE_CANONICAL (enumtype) = TYPE_CANONICAL (fixed_underlying_type);
+ c_update_type_canonical (enumtype);
  layout_type (enumtype);
}
 }
@@ -10094,6 +10097,10 @@ finish_enum (tree enumtype, tree values, tree 
attributes)
   ENUM_UNDERLYING_TYPE (enumtype) =
c_common_type_for_size (TYPE_PRECISION (tem), TYPE_UNSIGNED (tem));
 
+  TYPE_CANONICAL (enumtype) =
+   TYPE_CANONICAL (ENUM_UNDERLYING_TYPE (enumtype));
+  c_update_type_canonical (enumtype);
+
   layout_type (enumtype);
 }
 
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index b7c72d2609c..551ec6f4b65 100644
--- 

Re: [C PATCH, v2] Fix for redeclared enumerator initialized with different type [PR115109]

2024-05-20 Thread Martin Uecker
Am Montag, dem 20.05.2024 um 21:30 + schrieb Joseph Myers:
> On Sun, 19 May 2024, Martin Uecker wrote:
> 
> > c23 specifies that the type of a redeclared enumerator is the one of the
> > previous declaration.  Convert initializers with different type 
> > accordingly
> > and add -Woverflow warning.
> 
> It doesn't make sense to use -Woverflow.  Either the value is the same (in 
> which case it fits in the desired type), or it's different (and you should 
> get the "conflicting redeclaration of enumerator" error or some equivalent 
> error, whether or not the value in the redeclaration fits in the previous 
> type).
> 
> Note that this includes both explicit values and values determined by 
> adding 1 implicitly.  E.g.
> 
>   enum e { A = 0, B = UINT_MAX };
>   enum e { B = UINT_MAX, A };
> 
> is not valid, because in the redefinition, A gets the value 1 greater than 
> UINT_MAX (which is not representable in unsigned int) - there is *not* an 
> addition in type unsigned int, or in type enum e.
> 
> The constraint violated is the general one "If an identifier has no 
> linkage, there shall be no more than one declaration of the identifier (in 
> a declarator or type specifier) with the same scope and in the same name 
> space, except that: ... enumeration constants and tags may be redeclared 
> as specified in 6.7.3.3 and 6.7.3.4, respectively." (where 6.7.3.3 says 
> "Enumeration constants can be redefined in the same scope with the same 
> value as part of a redeclaration of the same enumerated type." - as the 
> redefinition is not with the same value, the "as specified in 6.7.3.3" is 
> not satisfied and so the general constraint against redeclarations with no 
> linkage applies).

This assumes that the value in question is the one of the initializer and not 
the
one after initialization (with no clear rules how this works in this case), 
which is probably not how this wording would be understood in other contexts.
But I agree that your interpretation is probably closer to what was intended
and makes more sense in this case.

Martin

> 



[C PATCH, v2] Fix for redeclared enumerator initialized with different type [PR115109]

2024-05-19 Thread Martin Uecker



First version was flawed, as it used the wrong type.
Here is another iteration.

Bootstrapped and regression tested on x86_64.


c23: Fix for redeclared enumerator initialized with different type 
[PR115109]

c23 specifies that the type of a redeclared enumerator is the one of the
previous declaration.  Convert initializers with different type accordingly
and add -Woverflow warning.

2024-05-18 Martin Uecker  

PR c/115109

gcc/c/
* c-decl.cc (build_enumerator): When redeclaring an
enumerator convert value to previous type.  For redeclared
enumerators use underlying type for computing the next value.

gcc/testsuite/
* gcc.dg/pr115109.c: New test.
* gcc.dg/c23-tag-enum-6.c: New test.
* gcc.dg/c23-tag-enum-7.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b691b91b3db..540927a8df6 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10209,6 +10209,7 @@ build_enumerator (location_t decl_loc, location_t loc,
  struct c_enum_contents *the_enum, tree name, tree value)
 {
   tree decl;
+  tree old_decl;
 
   /* Validate and default VALUE.  */
 
@@ -10268,6 +10269,24 @@ build_enumerator (location_t decl_loc, location_t loc,
 definition.  */
   value = convert (the_enum->enum_type, value);
 }
+  else if (flag_isoc23
+  && (old_decl = lookup_name_in_scope (name, current_scope))
+  && old_decl != error_mark_node
+  && TREE_TYPE (old_decl)
+  && TREE_TYPE (TREE_TYPE (old_decl))
+  && TREE_CODE (old_decl) == CONST_DECL)
+{
+  /* Enumeration constants in a redeclaration have the previous type.  */
+  tree previous_type = TREE_TYPE (DECL_INITIAL (old_decl));
+  if (!int_fits_type_p (value, previous_type))
+   {
+ warning_at (loc, OPT_Woverflow,
+ "value of redeclared enumerator outside the range of "
+ "the previous type %qT", previous_type);
+ locate_old_decl (old_decl);
+   }
+  value = convert (previous_type, value);
+}
   else
 {
   /* Even though the underlying type of an enum is unspecified, the
@@ -10334,9 +10353,14 @@ build_enumerator (location_t decl_loc, location_t loc,
 false);
 }
   else
-the_enum->enum_next_value
-  = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
-PLUS_EXPR, value, integer_one_node, false);
+{
+  /* In a redeclaration the type can already be the enumeral type.  */
+  if (TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE)
+   value = convert (ENUM_UNDERLYING_TYPE (TREE_TYPE (value)), value);
+  the_enum->enum_next_value
+   = build_binary_op (EXPR_LOC_OR_LOC (value, input_location),
+  PLUS_EXPR, value, integer_one_node, false);
+}
   the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value);
   if (the_enum->enum_overflow
   && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type))
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
new file mode 100644
index 000..ff9ec89775e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+#include 
+
+enum E : int { a = 1, b = 2 };
+enum E : int { b = _Generic(a, enum E: 2), a = 1 };
+
+enum H { x = 1 };
+enum H { x = 2UL + UINT_MAX }; /* { dg-warning "outside the range" } */
+
+enum K : int { z = 1 };
+enum K : int { z = 2UL + UINT_MAX };   /* { dg-error "outside the range" } */
+
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
new file mode 100644
index 000..4a5b4bc63f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
@@ -0,0 +1,41 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23" } */
+
+#include 
+
+// enumerators are all representable in int
+enum E { a = 1UL, b = _Generic(a, int: 2) };
+static_assert(_Generic(a, int: 1));
+static_assert(_Generic(b, int: 1));
+enum E { a = 1UL, b = _Generic(a, int: 2) };
+static_assert(_Generic(a, int: 1));
+static_assert(_Generic(b, int: 1));
+
+// enumerators are not representable in int
+enum H { c = 1UL << (UINT_WIDTH + 1), d = 2 };
+static_assert(_Generic(c, enum H: 1));
+static_assert(_Generic(d, enum H: 1));
+enum H { c = 1UL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) };
+static_assert(_Generic(c, enum H: 1));
+static_assert(_Generic(d, enum H: 1));
+
+// there is an overflow in the first redeclaration
+enum K { e = UINT_MAX, f, g = _Generic(e, unsigned int: 0) + _Generic(f, 
unsigned long: 1) };
+static_assert(_Generic(e, enum K: 1));
+static_assert(_Generic(f, enum K: 1));
+static_assert(_Generic(g, enum K: 1

[C PATCH] Fix for redeclared enumerator initialized with different type [PR115109]

2024-05-18 Thread Martin Uecker



Bootstrapped and regression tested on x86_64



c23: Fix for redeclared enumerator initialized with different type 
[PR115109]

c23 specifies that the type of a redeclared enumerator is the one of the
previous declaration.  Convert initializers with different type accordingly
and add -Woverflow warning.

2024-05-18 Martin Uecker  

PR c/115109

gcc/c/
* c-decl.cc (build_enumerator): When redeclaring an
  enumerator convert value to previous type.

gcc/testsuite/
* gcc.dg/pr115109.c: New test.
* gcc.dg/c23-tag-enum-6.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b691b91b3db..08a51c7ad50 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10209,6 +10209,7 @@ build_enumerator (location_t decl_loc, location_t loc,
  struct c_enum_contents *the_enum, tree name, tree value)
 {
   tree decl;
+  tree old_decl;
 
   /* Validate and default VALUE.  */
 
@@ -10268,6 +10269,25 @@ build_enumerator (location_t decl_loc, location_t loc,
 definition.  */
   value = convert (the_enum->enum_type, value);
 }
+  else if (flag_isoc23
+  && (old_decl = lookup_name_in_scope (name, current_scope))
+  && old_decl != error_mark_node
+  && TREE_TYPE (old_decl)
+  && TREE_TYPE (TREE_TYPE (old_decl))
+  && TREE_CODE (old_decl) == CONST_DECL)
+{
+  tree previous_type = TREE_TYPE (TREE_TYPE (old_decl));
+
+  if (!int_fits_type_p (value, previous_type))
+   {
+ warning_at (loc, OPT_Woverflow,
+ "value of redeclared enumerator outside the range of "
+ "the previous type %qT", previous_type);
+ locate_old_decl (old_decl);
+   }
+
+  value = convert (previous_type, value);
+}
   else
 {
   /* Even though the underlying type of an enum is unspecified, the
diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c 
b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
new file mode 100644
index 000..ff9ec89775e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+#include 
+
+enum E : int { a = 1, b = 2 };
+enum E : int { b = _Generic(a, enum E: 2), a = 1 };
+
+enum H { x = 1 };
+enum H { x = 2UL + UINT_MAX }; /* { dg-warning "outside the range" } */
+
+enum K : int { z = 1 };
+enum K : int { z = 2UL + UINT_MAX };   /* { dg-error "outside the range" } */
+
diff --git a/gcc/testsuite/gcc.dg/pr115109.c b/gcc/testsuite/gcc.dg/pr115109.c
new file mode 100644
index 000..0c327ce1697
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr115109.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+enum E { a = 1L, b = 2 };
+enum E { a = 1L, b = _Generic(a, enum E: 2) };
+



Re: [C PATCH] Fix for some variably modified types not being recognized [PR114831]

2024-05-18 Thread Martin Uecker


(correct email)

> We did not propagate C_TYPE_VARIABLY_MODIFIED to pointers in all
> cases.   I added this directly in two places, but maybe we should
> check all cases of build_pointer_type or integrate this into 
> c_build_pointer_type and use this everywhere (but I do not fully 
> understand the pointer mode logic there).
> 
> 
> Bootstrapped and regession tested on x86_64.
> 
> 
> c: Fix for some variably modified types not being recognized [PR114831]
> 
> We did not evaluate expressions with variably modified types correctly
> in typeof and did not produce warnings when jumping over declarations
> using typeof.  After addressof or array-to-pointer decay we construct
> new pointer types that have to be marked variably modified if the pointer
> target is variably modified.
> 
> 2024-05-18 Martin Uecker  
> 
> PR c/114831
> gcc/c/
> * c-typeck.cc (array_to_pointer_conversion, build_unary_op):
> Propagate flag to pointer target.
> 
> gcc/testsuite/
> * gcc.dg/pr114831-1.c: New test.
> * gcc.dg/pr114831-2.c: New test.
> * gcc.dg/gnu23-varmod-1.c: New test.
> * gcc.dg/gnu23-varmod-2.c: New test.
> 
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 7ecca9f58c6..2d092357e0f 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -1891,8 +1891,12 @@ array_to_pointer_conversion (location_t loc, tree exp)
>  
>copy_warning (exp, orig_exp);
>  
> +  bool varmod = C_TYPE_VARIABLY_MODIFIED (restype);
> +
>ptrtype = build_pointer_type (restype);
>  
> +  C_TYPE_VARIABLY_MODIFIED (ptrtype) = varmod;
> +
>if (INDIRECT_REF_P (exp))
>  return convert (ptrtype, TREE_OPERAND (exp, 0));
>  
> @@ -4630,6 +4634,7 @@ build_unary_op (location_t location, enum tree_code 
> code, tree xarg,
>tree eptype = NULL_TREE;
>const char *invalid_op_diag;
>bool int_operands;
> +  bool varmod;
>  
>int_operands = EXPR_INT_CONST_OPERANDS (xarg);
>if (int_operands)
> @@ -5113,8 +5118,12 @@ build_unary_op (location_t location, enum tree_code 
> code, tree xarg,
>gcc_assert (TREE_CODE (arg) != COMPONENT_REF
> || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)));
>  
> +  varmod = C_TYPE_VARIABLY_MODIFIED (argtype);
> +
>argtype = build_pointer_type (argtype);
>  
> +  C_TYPE_VARIABLY_MODIFIED (argtype) = varmod;
> +
>/* ??? Cope with user tricks that amount to offsetof.  Delete this
>when we have proper support for integer constant expressions.  */
>val = get_base_address (arg);
> diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-1.c 
> b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c
> new file mode 100644
> index 000..add10d13573
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } 
> + * { dg-options "-std=gnu23" } */
> +
> +int foo(int n)
> +{
> + int (*a(void))[n] { return 0; };
> + goto err;   /* { dg-error "jump into scope" "variably modified" } */
> + typeof((n++,a)) b2; 
> +err:
> + return n;
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-2.c 
> b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c
> new file mode 100644
> index 000..c36af1d1647
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c
> @@ -0,0 +1,16 @@
> +/* { dg-do run } 
> + * { dg-options "-std=gnu23" } */
> +
> +int foo(int n)
> +{
> + int (*a(void))[n] { return 0; };
> + typeof((n++,a)) b2;
> + return n;
> +}
> +
> +int main()
> +{
> + if (2 != foo(1))
> + __builtin_abort();
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/pr114831-1.c 
> b/gcc/testsuite/gcc.dg/pr114831-1.c
> new file mode 100644
> index 000..ed30a494b3c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr114831-1.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile }
> + * { dg-options "-std=c23" } */
> +
> +void f(int n)
> +{
> + int a[n];
> + goto foo;   /* { dg-error "jump into scope" "variably modified" } */
> + typeof(a) b1;   
> +foo:
> +}
> +
> +void g(int n)
> +{
> + int a2[1][n];
> + goto foo;   /* { dg-error "jump into scope" "variably modified" } */
> + typeof((n++,a2)) b2;
> +foo:
> +}
> +
> +void h(int n)
> +{
> + int a[n];
> + typeof(a) b1;   
> + goto foo;   /* { dg-error "jump into scope" "variably modified" } */
> + typeof() b;
> +foo:
> +}
> diff --git a/gcc/testsuite/gcc.dg/pr114831-2.c 
> b/gcc/testsuite/gcc.dg/pr114831-2.c
> new file mode 100644
> index 000..ecfd87988c2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr114831-2.c
> @@ -0,0 +1,16 @@
> +/* { dg-do run } 
> + * { dg-options "-std=c23" } */
> +
> +int foo(int n)
> +{
> + int a[1][n];
> + typeof((n++,a)) b2;
> + return n;
> +}
> +
> +int main()
> +{
> + if (2 != foo(1))
> + __builtin_abort();
> +}
> +
> 



[C PATCH] Fix for some variably modified types not being recognized [PR114831]

2024-05-18 Thread Martin Uecker


We did not propagate C_TYPE_VARIABLY_MODIFIED to pointers in all
cases.   I added this directly in two places, but maybe we should
check all cases of build_pointer_type or integrate this into 
c_build_pointer_type and use this everywhere (but I do not fully 
understand the pointer mode logic there).


Bootstrapped and regession tested on x86_64.


c: Fix for some variably modified types not being recognized [PR114831]

We did not evaluate expressions with variably modified types correctly
in typeof and did not produce warnings when jumping over declarations
using typeof.  After addressof or array-to-pointer decay we construct
new pointer types that have to be marked variably modified if the pointer
target is variably modified.

2024-05-18 Martin Uecker  

PR c/114831
gcc/c/
* c-typeck.cc (array_to_pointer_conversion, build_unary_op):
Propagate flag to pointer target.

gcc/testsuite/
* gcc.dg/pr114831-1.c: New test.
* gcc.dg/pr114831-2.c: New test.
* gcc.dg/gnu23-varmod-1.c: New test.
* gcc.dg/gnu23-varmod-2.c: New test.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7ecca9f58c6..2d092357e0f 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1891,8 +1891,12 @@ array_to_pointer_conversion (location_t loc, tree exp)
 
   copy_warning (exp, orig_exp);
 
+  bool varmod = C_TYPE_VARIABLY_MODIFIED (restype);
+
   ptrtype = build_pointer_type (restype);
 
+  C_TYPE_VARIABLY_MODIFIED (ptrtype) = varmod;
+
   if (INDIRECT_REF_P (exp))
 return convert (ptrtype, TREE_OPERAND (exp, 0));
 
@@ -4630,6 +4634,7 @@ build_unary_op (location_t location, enum tree_code code, 
tree xarg,
   tree eptype = NULL_TREE;
   const char *invalid_op_diag;
   bool int_operands;
+  bool varmod;
 
   int_operands = EXPR_INT_CONST_OPERANDS (xarg);
   if (int_operands)
@@ -5113,8 +5118,12 @@ build_unary_op (location_t location, enum tree_code 
code, tree xarg,
   gcc_assert (TREE_CODE (arg) != COMPONENT_REF
  || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)));
 
+  varmod = C_TYPE_VARIABLY_MODIFIED (argtype);
+
   argtype = build_pointer_type (argtype);
 
+  C_TYPE_VARIABLY_MODIFIED (argtype) = varmod;
+
   /* ??? Cope with user tricks that amount to offsetof.  Delete this
 when we have proper support for integer constant expressions.  */
   val = get_base_address (arg);
diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-1.c 
b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c
new file mode 100644
index 000..add10d13573
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu23-varmod-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } 
+ * { dg-options "-std=gnu23" } */
+
+int foo(int n)
+{
+   int (*a(void))[n] { return 0; };
+   goto err;   /* { dg-error "jump into scope" "variably modified" } */
+   typeof((n++,a)) b2; 
+err:
+   return n;
+}
+
diff --git a/gcc/testsuite/gcc.dg/gnu23-varmod-2.c 
b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c
new file mode 100644
index 000..c36af1d1647
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu23-varmod-2.c
@@ -0,0 +1,16 @@
+/* { dg-do run } 
+ * { dg-options "-std=gnu23" } */
+
+int foo(int n)
+{
+   int (*a(void))[n] { return 0; };
+   typeof((n++,a)) b2;
+   return n;
+}
+
+int main()
+{
+   if (2 != foo(1))
+   __builtin_abort();
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr114831-1.c 
b/gcc/testsuite/gcc.dg/pr114831-1.c
new file mode 100644
index 000..ed30a494b3c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114831-1.c
@@ -0,0 +1,27 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23" } */
+
+void f(int n)
+{
+   int a[n];
+   goto foo;   /* { dg-error "jump into scope" "variably modified" } */
+   typeof(a) b1;   
+foo:
+}
+
+void g(int n)
+{
+   int a2[1][n];
+   goto foo;   /* { dg-error "jump into scope" "variably modified" } */
+   typeof((n++,a2)) b2;
+foo:
+}
+
+void h(int n)
+{
+   int a[n];
+   typeof(a) b1;   
+   goto foo;   /* { dg-error "jump into scope" "variably modified" } */
+   typeof() b;
+foo:
+}
diff --git a/gcc/testsuite/gcc.dg/pr114831-2.c 
b/gcc/testsuite/gcc.dg/pr114831-2.c
new file mode 100644
index 000..ecfd87988c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114831-2.c
@@ -0,0 +1,16 @@
+/* { dg-do run } 
+ * { dg-options "-std=c23" } */
+
+int foo(int n)
+{
+   int a[1][n];
+   typeof((n++,a)) b2;
+   return n;
+}
+
+int main()
+{
+   if (2 != foo(1))
+   __builtin_abort();
+}
+



Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-06 Thread Martin Uecker
Am Montag, dem 06.05.2024 um 11:07 +0200 schrieb Richard Biener:
> On Mon, 6 May 2024, Martin Uecker wrote:
> 
> > Am Montag, dem 06.05.2024 um 09:00 +0200 schrieb Richard Biener:
> > > On Sat, 4 May 2024, Martin Uecker wrote:
> > > 
> > > > Am Freitag, dem 03.05.2024 um 21:16 +0200 schrieb Jakub Jelinek:
> > > > > > On Fri, May 03, 2024 at 09:11:20PM +0200, Martin Uecker wrote:
> > > > > > > > > > TYPE_CANONICAL as used by the middle-end cannot express 
> > > > > > > > > > this but
> > > > > > > > 
> > > > > > > > Hm. so how does it work now for arrays?
> > > > > > 
> > > > > > Do you have a testcase which doesn't work correctly with the arrays?
> > > > 
> > > > I am mostly trying to understand better how this works. But
> > > > if I am not mistaken, the following example would indeed
> > > > indicate that we do incorrect aliasing decisions for types
> > > > derived from arrays:
> > > > 
> > > > https://godbolt.org/z/rTsE3PhKc
> > > 
> > > This example is about pointer-to-array types, int (*)[2] and
> > > int (*)[1] are supposed to be compatible as in receive the same alias
> > > set. 
> > 
> > In C, char (*)[2] and char (*)[1] are not compatible. But with
> > COMPAT set, the example operates^1 with char (*)[] and char (*)[1]
> > which are compatible.  If we form equivalence classes, then
> > all three types would need to be treated as equivalent. 
> > 
> > ^1 Actually, pointer to functions returning pointers
> > to arrays. Probably this example can still be simplified...
> > 
> > >  This is ensured by get_alias_set POINTER_TYPE_P handling,
> > > the alias set is supposed to be the same as that of int *.  It seems
> > > we do restrict the handling a bit, the code does
> > > 
> > >   /* Unnest all pointers and references.
> > >  We also want to make pointer to array/vector equivalent to 
> > > pointer to
> > >  its element (see the reasoning above). Skip all those types, 
> > > too.  
> > > */
> > >   for (p = t; POINTER_TYPE_P (p)
> > >|| (TREE_CODE (p) == ARRAY_TYPE
> > >&& (!TYPE_NONALIASED_COMPONENT (p)
> > >|| !COMPLETE_TYPE_P (p)
> > >|| TYPE_STRUCTURAL_EQUALITY_P (p)))
> > >|| TREE_CODE (p) == VECTOR_TYPE;
> > >p = TREE_TYPE (p))
> > > 
> > > where the comment doesn't exactly match the code - but C should
> > > never have TYPE_NONALIASED_COMPONENT (p).
> > > 
> > > But maybe I misread the example or it goes wrong elsewhere.
> > 
> > If I am not confusing myself too much, the example shows that
> > aliasing analysis treats the the types as incompatible in
> > both cases, because it does not reload *a with -O2. 
> > 
> > For char (*)[1] and char (*)[2] this would be correct (but an
> > implementation exploiting this would need to do structural
> > comparisons and not equivalence classes) but for 
> > char (*)[2] and char (*)[] it is not.
> 
> Oh, these are function pointers, so it's about the alias set of
> a pointer to FUNCTION_TYPE.  I don't see any particular code
> trying to make char[] * (*)() and char[1] *(*)() inter-operate
> for TBAA iff the FUNCTION_TYPEs themselves are not having the
> same TYPE_CANONICAL.
> 
> Can you open a bugreport and please point to the relevant parts
> of the C standard that tells how pointer-to FUNCTION_TYPE TBAA
> is supposed to work?

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114959

Martin
> 

> Thanks,
> Richard.
> 
> > Martin
> > 
> > 
> > > 
> > > Richard.
> > > 
> > > > Martin
> > > > 
> > > > > > 
> > > > > > E.g. same_type_for_tbaa has
> > > > > >   type1 = TYPE_MAIN_VARIANT (type1);
> > > > > >   type2 = TYPE_MAIN_VARIANT (type2);
> > > > > > 
> > > > > >   /* Handle the most common case first.  */
> > > > > >   if (type1 == type2)
> > > > > > return 1;
> > > > > > 
> > > > > >   /* If we would have to do structural comparison bail out.  */
> > > > > >   if (TYPE_STRUCTURAL_EQUALITY_P (type1)
> > > > > >   || TYPE_STRUCTURAL_EQUALITY_P (type2))
> > > > > > return -1;
> > > > > > 
> > > > > >   /* Compare the canonical types.  */
> > > > > >   if (TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2))
> > > > > > return 1;
> > > > > > 
> > > > > >   /* ??? Array types are not properly unified in all cases as we 
> > > > > > have
> > > > > >  spurious changes in the index types for example.  Removing this
> > > > > >  causes all sorts of problems with the Fortran frontend.  */
> > > > > >   if (TREE_CODE (type1) == ARRAY_TYPE
> > > > > >   && TREE_CODE (type2) == ARRAY_TYPE)
> > > > > > return -1;
> > > > > > ...
> > > > > > and later compares alias sets and the like.
> > > > > > So, even if int[] and int[0] have different TYPE_CANONICAL, they
> > > > > > will be considered maybe the same.  Also, guess get_alias_set
> > > > > > has some ARRAY_TYPE handling...
> > > > > > 
> > > > > > Anyway, I think we should just go with Richi's patch.
> > > > > > 
> > > > > > Jakub
> > > > > > 
> > > > 
> > > > 
> > > > 
> > > 
> > 
> > 
> 



Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-06 Thread Martin Uecker
Am Montag, dem 06.05.2024 um 09:00 +0200 schrieb Richard Biener:
> On Sat, 4 May 2024, Martin Uecker wrote:
> 
> > Am Freitag, dem 03.05.2024 um 21:16 +0200 schrieb Jakub Jelinek:
> > > > On Fri, May 03, 2024 at 09:11:20PM +0200, Martin Uecker wrote:
> > > > > > > > TYPE_CANONICAL as used by the middle-end cannot express this but
> > > > > > 
> > > > > > Hm. so how does it work now for arrays?
> > > > 
> > > > Do you have a testcase which doesn't work correctly with the arrays?
> > 
> > I am mostly trying to understand better how this works. But
> > if I am not mistaken, the following example would indeed
> > indicate that we do incorrect aliasing decisions for types
> > derived from arrays:
> > 
> > https://godbolt.org/z/rTsE3PhKc
> 
> This example is about pointer-to-array types, int (*)[2] and
> int (*)[1] are supposed to be compatible as in receive the same alias
> set. 

In C, char (*)[2] and char (*)[1] are not compatible. But with
COMPAT set, the example operates^1 with char (*)[] and char (*)[1]
which are compatible.  If we form equivalence classes, then
all three types would need to be treated as equivalent. 

^1 Actually, pointer to functions returning pointers
to arrays. Probably this example can still be simplified...

>  This is ensured by get_alias_set POINTER_TYPE_P handling,
> the alias set is supposed to be the same as that of int *.  It seems
> we do restrict the handling a bit, the code does
> 
>   /* Unnest all pointers and references.
>  We also want to make pointer to array/vector equivalent to 
> pointer to
>  its element (see the reasoning above). Skip all those types, too.  
> */
>   for (p = t; POINTER_TYPE_P (p)
>|| (TREE_CODE (p) == ARRAY_TYPE
>&& (!TYPE_NONALIASED_COMPONENT (p)
>|| !COMPLETE_TYPE_P (p)
>|| TYPE_STRUCTURAL_EQUALITY_P (p)))
>|| TREE_CODE (p) == VECTOR_TYPE;
>p = TREE_TYPE (p))
> 
> where the comment doesn't exactly match the code - but C should
> never have TYPE_NONALIASED_COMPONENT (p).
> 
> But maybe I misread the example or it goes wrong elsewhere.

If I am not confusing myself too much, the example shows that
aliasing analysis treats the the types as incompatible in
both cases, because it does not reload *a with -O2. 

For char (*)[1] and char (*)[2] this would be correct (but an
implementation exploiting this would need to do structural
comparisons and not equivalence classes) but for 
char (*)[2] and char (*)[] it is not.

Martin


> 
> Richard.
> 
> > Martin
> > 
> > > > 
> > > > E.g. same_type_for_tbaa has
> > > >   type1 = TYPE_MAIN_VARIANT (type1);
> > > >   type2 = TYPE_MAIN_VARIANT (type2);
> > > > 
> > > >   /* Handle the most common case first.  */
> > > >   if (type1 == type2)
> > > > return 1;
> > > > 
> > > >   /* If we would have to do structural comparison bail out.  */
> > > >   if (TYPE_STRUCTURAL_EQUALITY_P (type1)
> > > >   || TYPE_STRUCTURAL_EQUALITY_P (type2))
> > > > return -1;
> > > > 
> > > >   /* Compare the canonical types.  */
> > > >   if (TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2))
> > > > return 1;
> > > > 
> > > >   /* ??? Array types are not properly unified in all cases as we have
> > > >  spurious changes in the index types for example.  Removing this
> > > >  causes all sorts of problems with the Fortran frontend.  */
> > > >   if (TREE_CODE (type1) == ARRAY_TYPE
> > > >   && TREE_CODE (type2) == ARRAY_TYPE)
> > > > return -1;
> > > > ...
> > > > and later compares alias sets and the like.
> > > > So, even if int[] and int[0] have different TYPE_CANONICAL, they
> > > > will be considered maybe the same.  Also, guess get_alias_set
> > > > has some ARRAY_TYPE handling...
> > > > 
> > > > Anyway, I think we should just go with Richi's patch.
> > > > 
> > > > Jakub
> > > > 
> > 
> > 
> > 
> 

-- 
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging




Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-04 Thread Martin Uecker
Am Freitag, dem 03.05.2024 um 21:16 +0200 schrieb Jakub Jelinek:
> > On Fri, May 03, 2024 at 09:11:20PM +0200, Martin Uecker wrote:
> > > > > > TYPE_CANONICAL as used by the middle-end cannot express this but
> > > > 
> > > > Hm. so how does it work now for arrays?
> > 
> > Do you have a testcase which doesn't work correctly with the arrays?

I am mostly trying to understand better how this works. But
if I am not mistaken, the following example would indeed
indicate that we do incorrect aliasing decisions for types
derived from arrays:

https://godbolt.org/z/rTsE3PhKc

Martin

> > 
> > E.g. same_type_for_tbaa has
> >   type1 = TYPE_MAIN_VARIANT (type1);
> >   type2 = TYPE_MAIN_VARIANT (type2);
> > 
> >   /* Handle the most common case first.  */
> >   if (type1 == type2)
> > return 1;
> > 
> >   /* If we would have to do structural comparison bail out.  */
> >   if (TYPE_STRUCTURAL_EQUALITY_P (type1)
> >   || TYPE_STRUCTURAL_EQUALITY_P (type2))
> > return -1;
> > 
> >   /* Compare the canonical types.  */
> >   if (TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2))
> > return 1;
> > 
> >   /* ??? Array types are not properly unified in all cases as we have
> >  spurious changes in the index types for example.  Removing this
> >  causes all sorts of problems with the Fortran frontend.  */
> >   if (TREE_CODE (type1) == ARRAY_TYPE
> >   && TREE_CODE (type2) == ARRAY_TYPE)
> > return -1;
> > ...
> > and later compares alias sets and the like.
> > So, even if int[] and int[0] have different TYPE_CANONICAL, they
> > will be considered maybe the same.  Also, guess get_alias_set
> > has some ARRAY_TYPE handling...
> > 
> > Anyway, I think we should just go with Richi's patch.
> > 
> > Jakub
> > 




Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-03 Thread Martin Uecker
Am Freitag, dem 03.05.2024 um 20:48 +0200 schrieb Richard Biener:
> 
> > Am 03.05.2024 um 20:37 schrieb Martin Uecker :
> > 
> > Am Freitag, dem 03.05.2024 um 20:18 +0200 schrieb Jakub Jelinek:
> > > > On Fri, May 03, 2024 at 08:04:18PM +0200, Martin Uecker wrote:
> > > > A change that is not optimal but would avoid a lot of trouble is to
> > > > only use the tag of the struct for computing a TYPE_CANONICAL, which
> > > > could then be set already for incomplete types and never needs to
> > > > change again. We would not differentiate between different struct
> > > > types with the same tag for aliasing analysis, but in most cases
> > > > I would expect different structs to have a different tag.
> > > 
> > > Having incompatible types have the same TYPE_CANONICAL would lead to wrong
> > > code IMHO, while for aliasing purposes that might be conservative (though
> > > not sure, the alias set computation is based on what types the element 
> > > have
> > > etc., so if the alias set is computed for say struct S { int s; }; and
> > > then the same alias set used for struct S { long long a; double b; union {
> > > short c; float d; } c; };, I think nothing good will come out of that),
> > 
> > The C type systems requires us to form equivalence classes though.
> > For example
> > 
> > int (*r)[1];
> > int (*q)[];
> > int (*p)[3];
> > 
> > need to be in the same equivalence class even though r and p are
> > not compatible, while at the same time r and q and q and p
> > are compatible.
> 
> TYPE_CANONICAL as used by the middle-end cannot express this but

Hm. so how does it work now for arrays?


> useless_type_conversion_p is directed and has similar behavior. 
> Note the dual-use for TBAA and compatibility was convenient but
> maybe we have to separate both since making the equivalence class
> for TBAA larger is more conservative while for compatibility it’s
> the other way around…

Maybe, although I do not understand why the middle end would
need precise knowledge for checking type compatibility?  The
FE has much stricter rules. 

Martin

> 
> Richard 
> 
> > 
> > > but middle-end also uses TYPE_CANONICAL to see if types are the same,
> > > say e.g. useless_type_conversion_p says that conversions from one
> > > RECORD_TYPE to a different RECORD_TYPE are useless if they have the
> > > same TYPE_CANONICAL.
> > >  /* For aggregates we rely on TYPE_CANONICAL exclusively and require
> > > explicit conversions for types involving to be structurally
> > > compared types.  */
> > >  else if (AGGREGATE_TYPE_P (inner_type)
> > >   && TREE_CODE (inner_type) == TREE_CODE (outer_type))
> > >return TYPE_CANONICAL (inner_type)
> > >   && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type);
> > > So, if you have struct S { int s; } and struct S { short a, b; }; and
> > > VIEW_CONVERT_EXPR between them, that VIEW_CONVERT_EXPR will be removed
> > > as useless, etc.
> > 
> > Maybe we could limit for purposes of computing TYPE_CANONICAL of derived
> > types, e.g. TYPE_CANONICAL of structs stays the same with the transition
> > from TYPE_STRUCT_EQUALITY to TYPE_CANONICAL but all the derived types
> > remain stable.
> > 
> > Martin
> > 
> > > 
> > > BTW, the idea of lazily updating TYPE_CANONICAL is basically what I've
> > > described as the option to update all the derived types where it would
> > > pretty much do that for all TYPE_STRUCTURAL_EQUALITY_P types in the
> > > hash table (see if they are derived from the type in question and 
> > > recompute
> > > the TYPE_CANONICAL after recomputing all the TYPE_CANONICAL of its base
> > > types), except perhaps even more costly (if the trigger would be some
> > > build_array_type/build_function_type/... function is called and found
> > > a cached TYPE_STRUCTURAL_EQUALITY_P type).  Note also that
> > > TYPE_STRUCTURAL_EQUALITY_P isn't the case just for the C23 types which
> > > are marked that way when incomplete and later completed, but by various
> > > other cases for types which will be permanently like that, so doing
> > > expensive checks each time some build*_type* is called that refers
> > > to those would be expensive.
> > > 
> > >Jakub
> > > 
> > 



Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-03 Thread Martin Uecker
Am Freitag, dem 03.05.2024 um 20:18 +0200 schrieb Jakub Jelinek:
> On Fri, May 03, 2024 at 08:04:18PM +0200, Martin Uecker wrote:
> > A change that is not optimal but would avoid a lot of trouble is to
> > only use the tag of the struct for computing a TYPE_CANONICAL, which
> > could then be set already for incomplete types and never needs to
> > change again. We would not differentiate between different struct
> > types with the same tag for aliasing analysis, but in most cases
> > I would expect different structs to have a different tag.
> 
> Having incompatible types have the same TYPE_CANONICAL would lead to wrong
> code IMHO, while for aliasing purposes that might be conservative (though
> not sure, the alias set computation is based on what types the element have
> etc., so if the alias set is computed for say struct S { int s; }; and
> then the same alias set used for struct S { long long a; double b; union {
> short c; float d; } c; };, I think nothing good will come out of that),

The C type systems requires us to form equivalence classes though.
For example

int (*r)[1];
int (*q)[];
int (*p)[3];

need to be in the same equivalence class even though r and p are 
not compatible, while at the same time r and q and q and p
are compatible.


> but middle-end also uses TYPE_CANONICAL to see if types are the same,
> say e.g. useless_type_conversion_p says that conversions from one
> RECORD_TYPE to a different RECORD_TYPE are useless if they have the
> same TYPE_CANONICAL.
>   /* For aggregates we rely on TYPE_CANONICAL exclusively and require
>  explicit conversions for types involving to be structurally
>  compared types.  */
>   else if (AGGREGATE_TYPE_P (inner_type)
>&& TREE_CODE (inner_type) == TREE_CODE (outer_type))
> return TYPE_CANONICAL (inner_type)
>&& TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type);
> So, if you have struct S { int s; } and struct S { short a, b; }; and
> VIEW_CONVERT_EXPR between them, that VIEW_CONVERT_EXPR will be removed
> as useless, etc.

Maybe we could limit for purposes of computing TYPE_CANONICAL of derived
types, e.g. TYPE_CANONICAL of structs stays the same with the transition
from TYPE_STRUCT_EQUALITY to TYPE_CANONICAL but all the derived types
remain stable.

Martin

> 
> BTW, the idea of lazily updating TYPE_CANONICAL is basically what I've
> described as the option to update all the derived types where it would
> pretty much do that for all TYPE_STRUCTURAL_EQUALITY_P types in the
> hash table (see if they are derived from the type in question and recompute
> the TYPE_CANONICAL after recomputing all the TYPE_CANONICAL of its base
> types), except perhaps even more costly (if the trigger would be some
> build_array_type/build_function_type/... function is called and found
> a cached TYPE_STRUCTURAL_EQUALITY_P type).  Note also that
> TYPE_STRUCTURAL_EQUALITY_P isn't the case just for the C23 types which
> are marked that way when incomplete and later completed, but by various
> other cases for types which will be permanently like that, so doing
> expensive checks each time some build*_type* is called that refers
> to those would be expensive.
> 
>   Jakub
> 



Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-03 Thread Martin Uecker
Am Freitag, dem 03.05.2024 um 19:30 +0200 schrieb Jakub Jelinek:
> On Fri, May 03, 2024 at 05:32:12PM +0200, Martin Uecker wrote:
> > Am Freitag, dem 03.05.2024 um 14:13 +0200 schrieb Richard Biener:
> > > TYPE_STRUCTURAL_EQUALITY_P is part of our type system so we have
> > > to make sure to include that into the type unification done via
> > > type_hash_canon.  This requires the flag to be set before querying
> > > the hash which is the biggest part of the patch.
> > 
> > I assume this does not affect structs / unions because they
> > do not make this mechanism of type unification (each tagged type
> > is a unique type), but only derived types that end up having
> > TYPE_STRUCTURAL_EQUALITY_P because they are constructed from
> > incomplete structs / unions before TYPE_CANONICAL is set.
> > 
> > I do not yet understand why this change is needed. Type
> > identity should not be affected by setting TYPE_CANONICAL, so
> > why do we need to keep such types separate?  I understand that we
> > created some inconsistencies, but I do not see why this change
> > is needed to fix it.  But I also haven't understood how we ended
> > up with a TYPE_CANONICAL having TYPE_STRUCTURAL_EQUALITY_P in
> > PR 114931 ...
> 
> So, the C23 situation before the r14-10045 change (not counting the
> r14-9763 change that was later reverted) was that sometimes TYPE_CANONICAL
> of a RECORD_TYPE/UNION_TYPE could change from self to a different
> RECORD_TYPE/UNION_TYPE and we didn't bother to adjust derived types.
> That was really dangerous, I think e.g. type alias set wasn't recomputed.
> 
> r14-10045 changed it to the non-ideal, but perhaps less wrong model,
> where we start with TYPE_STRUCTURAL_EQUALITY_P on incomplete types in C23
> and perhaps later on change them to !TYPE_STRUCTURAL_EQUALITY_P when
> the type is completed, and adjust TYPE_CANONICAL of some easily discoverable
> derived types but certainly not all.
> 
> Still, that change introduces something novel to the type system, namely
> that TYPE_CANONICAL can change on a type, even when it is just limited to
> the TYPE_STRUCTURAL_EQUALITY_P -> !TYPE_STRUCTURAL_EQUALITY_P kind of
> change and we never change one non-NULL TYPE_CANONICAL to a different one
> (ok, not counting the short lived TYPE_CANONICAL being initially set to
> self during make_node and then quickly adjusted in the callers).
> 
> One question is, could we for C23 somehow limit this for the most common
> case where people just forward declare some aggregate type and then soon
> after define it?  But guess the problematic counterexample there is
> struct S; // forward declare
> struct S *p; // create some derived types from it
> void foo (void)
> {
>   struct S { int s; };// define the type in a different scope
>   // (perhaps with a forward declaration as well)
>   struct S s;
>   use ();   // create derived types
> }
> struct S { int s; };  // define the type in the global scope to something
>   // that matches previously defined struct S in
>   // another scope
> So e.g. noting in the hash table that a particular type has been forward
> declared so far and using TYPE_STRUCTURAL_EQUALITY_P only if it has been
> forward declared in some other scope wouldn't work.
> 
> Another question is whether c_update_type_canonical can or should try to
> update TYPE_ALIAS_SET if TYPE_ALIAS_SET_KNOWN_P.  Or do we never cache
> alias sets for TYPE_STRUCTURAL_EQUALITY_P types?
> 
> Anyway, the ICE on the testcase is because alias.cc asserts that
> a !TYPE_STRUCTURAL_EQUALITY_P (type) has
> !TYPE_STRUCTURAL_EQUALITY_P (TYPE_CANONICAL (type)).
> 
> The possibilities to resolve that are either at c_update_type_canonical
> time try to find all the derived types rather than just some and recompute
> their TYPE_CANONICAL.  Guess we could e.g. just traverse the whole
> type_hash_table hash table and for each type see if it is in any way related
> to the type that is being changed and then recompute them.  Though,
> especially FUNCTION_TYPEs make that really ugly and furthermore it needs
> to be recomputed in the right order, basically in the derivation order.
> Without doing that, we'll have some TYPE_STRUCTURAL_EQUALITY_P derived
> types in the type_hash_table hash table; that is conservatively correct,
> but can result in worse code generation because of using alias set 0.
> 
> Another possibility is what Richi posted, essentially stop reusing
> derived types created from the time when the base type was incomplete
> when asking for a new derived type.  We'll get the TYPE_STRUCTURAL_EQUALITY_P
> derived types if they we

Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-03 Thread Martin Uecker
Am Freitag, dem 03.05.2024 um 18:23 +0200 schrieb Richard Biener:
> 
> > Am 03.05.2024 um 17:33 schrieb Martin Uecker :
> > 
> > Am Freitag, dem 03.05.2024 um 14:13 +0200 schrieb Richard Biener:
> > > TYPE_STRUCTURAL_EQUALITY_P is part of our type system so we have
> > > to make sure to include that into the type unification done via
> > > type_hash_canon.  This requires the flag to be set before querying
> > > the hash which is the biggest part of the patch.
> > 
> > I assume this does not affect structs / unions because they
> > do not make this mechanism of type unification (each tagged type
> > is a unique type), but only derived types that end up having
> > TYPE_STRUCTURAL_EQUALITY_P because they are constructed from
> > incomplete structs / unions before TYPE_CANONICAL is set.
> > 
> > I do not yet understand why this change is needed. Type
> > identity should not be affected by setting TYPE_CANONICAL, so
> > why do we need to keep such types separate?  I understand that we
> > created some inconsistencies, but I do not see why this change
> > is needed to fix it.  But I also haven't understood how we ended
> > up with a TYPE_CANONICAL having TYPE_STRUCTURAL_EQUALITY_P in
> > PR 114931 ...
> 
> Because we created the canonical function type before where one
> of its arguments had TYPE_STEUCTURAL_EQUALITY which makes the
> function type so.

So build_function_type when called recursively for creating
a TYPE_CANONICAL found some type with TYPE_STRUCTURAL_EQUALITY.

And the plan is to separate those in the hash table so that this
cannot happen?

Couldn't we instead lazily update TYPE_CANONICAL at this point? 


Martin

> 
> Richard 
> 
> > 
> > Martin
> > 
> > 
> > > 
> > > Bootstrapped and tested on x86_64-unknown-linux-gnu for all languages.
> > > 
> > > As said in the PR this merely makes sure to keep individual types
> > > consistent with themselves.  We still will have a set of types
> > > with TYPE_STRUCTURAL_EQUALITY_P and a set without that might be
> > > otherwise identical.  That could be only avoided with changes in
> > > the frontend.
> > > 
> > > OK for trunk?
> > > 
> > > Thanks,
> > > Richard.
> > > 
> > >PR middle-end/114931
> > > gcc/
> > >* tree.cc (type_hash_canon_hash): Hash TYPE_STRUCTURAL_EQUALITY_P.
> > >(type_cache_hasher::equal): Compare TYPE_STRUCTURAL_EQUALITY_P.
> > >(build_array_type_1): Set TYPE_STRUCTURAL_EQUALITY_P before
> > >probing with type_hash_canon.
> > >(build_function_type): Likewise.
> > >(build_method_type_directly): Likewise.
> > >(build_offset_type): Likewise.
> > >(build_complex_type): Likewise.
> > >* attribs.cc (build_type_attribute_qual_variant): Likewise.
> > > 
> > > gcc/c-family/
> > >* c-common.cc (complete_array_type): Set TYPE_STRUCTURAL_EQUALITY_P
> > >before probing with type_hash_canon.
> > > 
> > > gcc/testsuite/
> > >* gcc.dg/pr114931.c: New testcase.
> > > ---
> > > gcc/attribs.cc  | 20 +-
> > > gcc/c-family/c-common.cc| 11 --
> > > gcc/testsuite/gcc.dg/pr114931.c | 10 +
> > > gcc/tree.cc | 65 +++--
> > > 4 files changed, 74 insertions(+), 32 deletions(-)
> > > create mode 100644 gcc/testsuite/gcc.dg/pr114931.c
> > > 
> > > diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> > > index 12ffc5f170a..3ab0b0fd87a 100644
> > > --- a/gcc/attribs.cc
> > > +++ b/gcc/attribs.cc
> > > @@ -1336,6 +1336,16 @@ build_type_attribute_qual_variant (tree otype, 
> > > tree attribute, int quals)
> > >   tree dtype = ntype = build_distinct_type_copy (ttype);
> > > 
> > >   TYPE_ATTRIBUTES (ntype) = attribute;
> > > +  /* If the target-dependent attributes make NTYPE different from
> > > + its canonical type, we will need to use structural equality
> > > + checks for this type.
> > > +
> > > + We shouldn't get here for stripping attributes from a type;
> > > + the no-attribute type might not need structural comparison.  But
> > > + we can if was discarded from type_hash_table.  */
> > > +  if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
> > > +  || !comp_type_attributes (ntype, ttype))
> > > +SET_TYPE_STRUCTURAL_EQUALITY (ntype);
> > > 
> > >   hashval_t hash = type_h

Re: [PATCH] middle-end/114931 - type_hash_canon and structual equality types

2024-05-03 Thread Martin Uecker
Am Freitag, dem 03.05.2024 um 14:13 +0200 schrieb Richard Biener:
> TYPE_STRUCTURAL_EQUALITY_P is part of our type system so we have
> to make sure to include that into the type unification done via
> type_hash_canon.  This requires the flag to be set before querying
> the hash which is the biggest part of the patch.

I assume this does not affect structs / unions because they
do not make this mechanism of type unification (each tagged type
is a unique type), but only derived types that end up having
TYPE_STRUCTURAL_EQUALITY_P because they are constructed from
incomplete structs / unions before TYPE_CANONICAL is set.

I do not yet understand why this change is needed. Type
identity should not be affected by setting TYPE_CANONICAL, so
why do we need to keep such types separate?  I understand that we
created some inconsistencies, but I do not see why this change
is needed to fix it.  But I also haven't understood how we ended
up with a TYPE_CANONICAL having TYPE_STRUCTURAL_EQUALITY_P in
PR 114931 ...

Martin


> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu for all languages.
> 
> As said in the PR this merely makes sure to keep individual types
> consistent with themselves.  We still will have a set of types
> with TYPE_STRUCTURAL_EQUALITY_P and a set without that might be
> otherwise identical.  That could be only avoided with changes in
> the frontend.
> 
> OK for trunk?
> 
> Thanks,
> Richard.
> 
>   PR middle-end/114931
> gcc/
>   * tree.cc (type_hash_canon_hash): Hash TYPE_STRUCTURAL_EQUALITY_P.
>   (type_cache_hasher::equal): Compare TYPE_STRUCTURAL_EQUALITY_P.
>   (build_array_type_1): Set TYPE_STRUCTURAL_EQUALITY_P before
>   probing with type_hash_canon.
>   (build_function_type): Likewise.
>   (build_method_type_directly): Likewise.
>   (build_offset_type): Likewise.
>   (build_complex_type): Likewise.
>   * attribs.cc (build_type_attribute_qual_variant): Likewise.
> 
> gcc/c-family/
>   * c-common.cc (complete_array_type): Set TYPE_STRUCTURAL_EQUALITY_P
>   before probing with type_hash_canon.
> 
> gcc/testsuite/
>   * gcc.dg/pr114931.c: New testcase.
> ---
>  gcc/attribs.cc  | 20 +-
>  gcc/c-family/c-common.cc| 11 --
>  gcc/testsuite/gcc.dg/pr114931.c | 10 +
>  gcc/tree.cc | 65 +++--
>  4 files changed, 74 insertions(+), 32 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/pr114931.c
> 
> diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> index 12ffc5f170a..3ab0b0fd87a 100644
> --- a/gcc/attribs.cc
> +++ b/gcc/attribs.cc
> @@ -1336,6 +1336,16 @@ build_type_attribute_qual_variant (tree otype, tree 
> attribute, int quals)
>tree dtype = ntype = build_distinct_type_copy (ttype);
>  
>TYPE_ATTRIBUTES (ntype) = attribute;
> +  /* If the target-dependent attributes make NTYPE different from
> +  its canonical type, we will need to use structural equality
> +  checks for this type.
> +
> +  We shouldn't get here for stripping attributes from a type;
> +  the no-attribute type might not need structural comparison.  But
> +  we can if was discarded from type_hash_table.  */
> +  if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
> +   || !comp_type_attributes (ntype, ttype))
> + SET_TYPE_STRUCTURAL_EQUALITY (ntype);
>  
>hashval_t hash = type_hash_canon_hash (ntype);
>ntype = type_hash_canon (hash, ntype);
> @@ -1343,16 +1353,6 @@ build_type_attribute_qual_variant (tree otype, tree 
> attribute, int quals)
>if (ntype != dtype)
>   /* This variant was already in the hash table, don't mess with
>  TYPE_CANONICAL.  */;
> -  else if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
> -|| !comp_type_attributes (ntype, ttype))
> - /* If the target-dependent attributes make NTYPE different from
> -its canonical type, we will need to use structural equality
> -checks for this type.
> -
> -We shouldn't get here for stripping attributes from a type;
> -the no-attribute type might not need structural comparison.  But
> -we can if was discarded from type_hash_table.  */
> - SET_TYPE_STRUCTURAL_EQUALITY (ntype);
>else if (TYPE_CANONICAL (ntype) == ntype)
>   TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
>  
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index 01e3d247fc2..032dcb4b41d 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -7115,6 +7115,13 @@ complete_array_type (tree *ptype, tree initial_value, 
> bool do_default)
>TYPE_TYPELESS_STORAGE (main_type) = TYPE_TYPELESS_STORAGE (type);
>layout_type (main_type);
>  
> +  /* Set TYPE_STRUCTURAL_EQUALITY_P early.  */
> +  if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (main_type))
> +  || TYPE_STRUCTURAL_EQUALITY_P (TYPE_DOMAIN (main_type)))
> +SET_TYPE_STRUCTURAL_EQUALITY (main_type);
> +  else
> +TYPE_CANONICAL 

Re: [C PATCH, v2] Fix ICE with -g and -std=c23 related to incomplete types [PR114361]

2024-04-14 Thread Martin Uecker


(new email for Joseph)

Am Sonntag, dem 14.04.2024 um 14:30 +0200 schrieb Martin Uecker:
> I had to revert the old patch because it broke LTO which lead
> to PR114574.  We now set TYPE_STRUCTURAL_EQUALITY and properly
> update TYPE_CANONICAL for such types and also for pointers
> to such types via a new function c_update_type_canonical
> (thanks to Jakob).
> 
> 
> Bootstrapped and regession tested on x86_64.
> 
> 
> 
> Fix ICE with -g and -std=c23 related to incomplete types [PR114361]
> 
> We did not update TYPE_CANONICAL for incomplete variants when
> completing a structure.  We now set TYPE_STRUCTURAL_EQUALITY for
> incomplete structure and union types and then update TYPE_CANONICAL
> later. See PR114574 for discussion.
> 
> 
> 2024-04-12  Martin Uecker  
>   Jakub Jelinek  
> 
>   PR lto/114574
>   PR c/114361
> gcc/
>   * ipa-free-lang-data.cc (fld_incomplete_type_of): Allow
>   either of the types in the assert to have TYPE_STRUCTURAL_EQUALITY_P.
> gcc/c/
>   * c-decl.cc (shadow_tag_warned): For flag_isoc23 and code not
>   ENUMERAL_TYPE use SET_TYPE_STRUCTURAL_EQUALITY.
>   (parser_xref_tag): Likewise.
>   (start_struct): For flag_isoc23 use SET_TYPE_STRUCTURAL_EQUALITY.
>   (c_update_type_canonical): New function.
>   (finish_struct): Put NULL as second == operand rather than first.
>   Assert TYPE_STRUCTURAL_EQUALITY_P.  Call c_update_type_canonical.
>   * c-typeck.cc (composite_type_internal): Use
>   SET_TYPE_STRUCTURAL_EQUALITY.  Formatting fix.
> gcc/testsuite/
>   * gcc.dg/pr114574-1.c: New test.
>   * gcc.dg/pr114574-2.c: New test.
>   * gcc.dg/pr114361.c: New test.
>   * gcc.dg/c23-tag-incomplete-1.c: New test.
>   * gcc.dg/c23-tag-incomplete-2.c: New test.
> ---
>  gcc/c/c-decl.cc | 47 -
>  gcc/c/c-typeck.cc   |  4 +-
>  gcc/ipa-free-lang-data.cc   |  4 +-
>  gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c | 14 ++
>  gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c | 13 ++
>  gcc/testsuite/gcc.dg/pr114361.c | 11 +
>  gcc/testsuite/gcc.dg/pr114574-1.c   | 10 +
>  gcc/testsuite/gcc.dg/pr114574-2.c   | 10 +
>  8 files changed, 110 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/pr114361.c
>  create mode 100644 gcc/testsuite/gcc.dg/pr114574-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/pr114574-2.c
> 
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 345090dae38..54917297b6a 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -5051,6 +5051,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, 
> int warned)
> if (t == NULL_TREE)
>   {
> t = make_node (code);
> +   if (flag_isoc23 && code != ENUMERAL_TYPE)
> + SET_TYPE_STRUCTURAL_EQUALITY (t);
> pushtag (input_location, name, t);
>   }
>   }
> @@ -8809,6 +8811,8 @@ parser_xref_tag (location_t loc, enum tree_code code, 
> tree name,
>   the forward-reference will be altered into a real type.  */
>  
>ref = make_node (code);
> +  if (flag_isoc23 && code != ENUMERAL_TYPE)
> +SET_TYPE_STRUCTURAL_EQUALITY (ref);
>if (code == ENUMERAL_TYPE)
>  {
>/* Give the type a default layout like unsigned int
> @@ -8910,6 +8914,8 @@ start_struct (location_t loc, enum tree_code code, tree 
> name,
>if (ref == NULL_TREE || TREE_CODE (ref) != code)
>  {
>ref = make_node (code);
> +  if (flag_isoc23)
> + SET_TYPE_STRUCTURAL_EQUALITY (ref);
>pushtag (loc, name, ref);
>  }
>  
> @@ -9347,6 +9353,43 @@ is_flexible_array_member_p (bool is_last_field,
>return false;
>  }
>  
> +/* Recompute TYPE_CANONICAL for qualified versions of the type and
> +   related pointer types after an aggregate type has been finalized.
> +   Will not update array types, pointers to array types, function
> +   types and other derived types created while the type was still
> +   incomplete, those will remain TYPE_STRUCTURAL_EQUALITY_P.  */
> +
> +static void
> +c_update_type_canonical (tree t)
> +{
> +  for (tree x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
> +{
> +  if (x != t
> +   && TYPE_STRUCTURAL_EQUALITY_P (x)
> +   && check_qualified_type (x, t, TYPE_QUALS (x)))
> + {
> +   if (TYPE_CANONICAL (t) != t)
> + TYPE_CANONICAL

[C PATCH, v2] Fix ICE with -g and -std=c23 related to incomplete types [PR114361]

2024-04-14 Thread Martin Uecker


I had to revert the old patch because it broke LTO which lead
to PR114574.  We now set TYPE_STRUCTURAL_EQUALITY and properly
update TYPE_CANONICAL for such types and also for pointers
to such types via a new function c_update_type_canonical
(thanks to Jakob).


Bootstrapped and regession tested on x86_64.



Fix ICE with -g and -std=c23 related to incomplete types [PR114361]

We did not update TYPE_CANONICAL for incomplete variants when
completing a structure.  We now set TYPE_STRUCTURAL_EQUALITY for
incomplete structure and union types and then update TYPE_CANONICAL
later. See PR114574 for discussion.


2024-04-12  Martin Uecker  
Jakub Jelinek  

PR lto/114574
PR c/114361
gcc/
* ipa-free-lang-data.cc (fld_incomplete_type_of): Allow
either of the types in the assert to have TYPE_STRUCTURAL_EQUALITY_P.
gcc/c/
* c-decl.cc (shadow_tag_warned): For flag_isoc23 and code not
ENUMERAL_TYPE use SET_TYPE_STRUCTURAL_EQUALITY.
(parser_xref_tag): Likewise.
(start_struct): For flag_isoc23 use SET_TYPE_STRUCTURAL_EQUALITY.
(c_update_type_canonical): New function.
(finish_struct): Put NULL as second == operand rather than first.
Assert TYPE_STRUCTURAL_EQUALITY_P.  Call c_update_type_canonical.
* c-typeck.cc (composite_type_internal): Use
SET_TYPE_STRUCTURAL_EQUALITY.  Formatting fix.
gcc/testsuite/
* gcc.dg/pr114574-1.c: New test.
* gcc.dg/pr114574-2.c: New test.
* gcc.dg/pr114361.c: New test.
* gcc.dg/c23-tag-incomplete-1.c: New test.
* gcc.dg/c23-tag-incomplete-2.c: New test.
---
 gcc/c/c-decl.cc | 47 -
 gcc/c/c-typeck.cc   |  4 +-
 gcc/ipa-free-lang-data.cc   |  4 +-
 gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c | 14 ++
 gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c | 13 ++
 gcc/testsuite/gcc.dg/pr114361.c | 11 +
 gcc/testsuite/gcc.dg/pr114574-1.c   | 10 +
 gcc/testsuite/gcc.dg/pr114574-2.c   | 10 +
 8 files changed, 110 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr114361.c
 create mode 100644 gcc/testsuite/gcc.dg/pr114574-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr114574-2.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 345090dae38..54917297b6a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5051,6 +5051,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, 
int warned)
  if (t == NULL_TREE)
{
  t = make_node (code);
+ if (flag_isoc23 && code != ENUMERAL_TYPE)
+   SET_TYPE_STRUCTURAL_EQUALITY (t);
  pushtag (input_location, name, t);
}
}
@@ -8809,6 +8811,8 @@ parser_xref_tag (location_t loc, enum tree_code code, 
tree name,
  the forward-reference will be altered into a real type.  */
 
   ref = make_node (code);
+  if (flag_isoc23 && code != ENUMERAL_TYPE)
+SET_TYPE_STRUCTURAL_EQUALITY (ref);
   if (code == ENUMERAL_TYPE)
 {
   /* Give the type a default layout like unsigned int
@@ -8910,6 +8914,8 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
   if (ref == NULL_TREE || TREE_CODE (ref) != code)
 {
   ref = make_node (code);
+  if (flag_isoc23)
+   SET_TYPE_STRUCTURAL_EQUALITY (ref);
   pushtag (loc, name, ref);
 }
 
@@ -9347,6 +9353,43 @@ is_flexible_array_member_p (bool is_last_field,
   return false;
 }
 
+/* Recompute TYPE_CANONICAL for qualified versions of the type and
+   related pointer types after an aggregate type has been finalized.
+   Will not update array types, pointers to array types, function
+   types and other derived types created while the type was still
+   incomplete, those will remain TYPE_STRUCTURAL_EQUALITY_P.  */
+
+static void
+c_update_type_canonical (tree t)
+{
+  for (tree x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+{
+  if (x != t
+ && TYPE_STRUCTURAL_EQUALITY_P (x)
+ && check_qualified_type (x, t, TYPE_QUALS (x)))
+   {
+ if (TYPE_CANONICAL (t) != t)
+   TYPE_CANONICAL (x)
+ = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
+ else
+   TYPE_CANONICAL (x) = x;
+   }
+  else if (x != t)
+   continue;
+  for (tree p = TYPE_POINTER_TO (x); p; p = TYPE_NEXT_PTR_TO (p))
+   {
+ if (!TYPE_STRUCTURAL_EQUALITY_P (p))
+   continue;
+ if (TYPE_CANONICAL (x) != x || TYPE_REF_CAN_ALIAS_ALL (p))
+   TYPE_CANONICAL (p)
+ = build_pointer_type_for_mode (TYPE_CANONICAL (x), TYPE_MODE (p),
+false);
+ else
+ 

Re: [PATCH v8 1/5] Provide counted_by attribute to flexible array member field (PR108896)

2024-04-11 Thread Martin Uecker
Am Mittwoch, dem 10.04.2024 um 19:35 + schrieb Qing Zhao:
> 
> > On Apr 10, 2024, at 15:05, Martin Uecker  wrote:
> > 
> > Am Mittwoch, dem 10.04.2024 um 20:25 +0200 schrieb Martin Uecker:
> > > Am Mittwoch, dem 10.04.2024 um 17:35 + schrieb Joseph Myers:
> > > > On Fri, 29 Mar 2024, Qing Zhao wrote:
> > > > 
> > > > > +  /* Issue error when there is a counted_by attribute with a 
> > > > > different
> > > > > + field as the argument for the same flexible array member field. 
> > > > >  */
> > > > 
> > > > There's another case of this to consider, though I'm not sure where 
> > > > best 
> > > > to check for it (Martin might have suggestions) - of course this case 
> > > > will 
> > > > need testcases as well.
> > > > 
> > > > Suppose, as allowed in C23, a structure is defined twice in the same 
> > > > scope, but the two definitions of the structure use inconsistent 
> > > > counted_by attributes.  I'd say that, when the declarations are in the 
> > > > same scope (thus required to be consistent), it should be an error for 
> > > > the 
> > > > two definitions of what is meant to be the same structure to use 
> > > > incompatible counted_by attributes (even though the member declarations 
> > > > are otherwise the same).
> > > 
> > > I think the right place could be comp_types_attributes in
> > > attributes.cc.  It may be sufficient to set the
> > > affects_type_identify flag.
> > > 
> > > This should then give a redefinition error as it should do for
> > > "packed".
> > 
> > Thinking about this a bit more, this will not work here, because
> > the counted_by attribute is not applied to the struct type but
> > one of the members.
> > 
> > So probably there should be a check added directly
> > to tagged_types_tu_compatible_p
> 
> 
> There are two cases we will check:
> 
>   A. Both definitions are in the same scope;
>   Then if the 2nd definition has a counted-by attribute different from 
> the 1st definition, the 2nd definition will be given a redefinition error; 
> 
>   B. These two definitions are in different scope;
>   When these two definitions are used in a way need to be compatible, an 
> incompatible error need to be issued at that
> Point;
> 
> 
> My question is, Will the routine “tagged_types_tu_compatible_p” can handle 
> both A and B?

Yes, changing this function should address both cases if I am
not missing something.

Martin

> 
> Thanks.
> 
> Qing
> > 
> > Martin
> > 
> > > 
> > > > 
> > > > In C23 structures defined with the same tag in different scopes are 
> > > > compatible given requirements including compatible types for 
> > > > corresponding 
> > > > elements.  It would seem most appropriate to me for such structures 
> > > > with 
> > > > incompatible counted_by attributes to be considered *not* compatible 
> > > > types 
> > > > (but it would be valid to define structures with the same tag, 
> > > > different 
> > > > scopes, and elements the same except for counted_by - just not to use 
> > > > them 
> > > > in any way requiring them to be compatible).
> > > 
> > > Another option might be to warn about the case when those types
> > > are then used together in a way where they are required to
> > > be compatible.  Then comp_types_attributes would have to return 2.
> > > 
> > > 
> > > Martin
> > > 
> > > > 
> > > > > +The @code{counted_by} attribute may be attached to the C99 flexible 
> > > > > array
> > > > > +member of a structure.  It indicates that the number of the elements 
> > > > > of the
> > > > > +array is given by the field "@var{count}" in the same structure as 
> > > > > the
> > > > 
> > > > As noted previously, the "" quotes should be removed there (or replaced 
> > > > by 
> > > > ``'' quotes).
> > > > 
> > > 
> > 
> 



Re: [PATCH v8 1/5] Provide counted_by attribute to flexible array member field (PR108896)

2024-04-10 Thread Martin Uecker
Am Mittwoch, dem 10.04.2024 um 20:25 +0200 schrieb Martin Uecker:
> Am Mittwoch, dem 10.04.2024 um 17:35 + schrieb Joseph Myers:
> > On Fri, 29 Mar 2024, Qing Zhao wrote:
> > 
> > > +  /* Issue error when there is a counted_by attribute with a different
> > > + field as the argument for the same flexible array member field.  */
> > 
> > There's another case of this to consider, though I'm not sure where best 
> > to check for it (Martin might have suggestions) - of course this case will 
> > need testcases as well.
> > 
> > Suppose, as allowed in C23, a structure is defined twice in the same 
> > scope, but the two definitions of the structure use inconsistent 
> > counted_by attributes.  I'd say that, when the declarations are in the 
> > same scope (thus required to be consistent), it should be an error for the 
> > two definitions of what is meant to be the same structure to use 
> > incompatible counted_by attributes (even though the member declarations 
> > are otherwise the same).
> 
> I think the right place could be comp_types_attributes in
> attributes.cc.  It may be sufficient to set the
> affects_type_identify flag.
> 
> This should then give a redefinition error as it should do for
> "packed".

Thinking about this a bit more, this will not work here, because
the counted_by attribute is not applied to the struct type but
one of the members.

So probably there should be a check added directly
to tagged_types_tu_compatible_p

Martin

> 
> > 
> > In C23 structures defined with the same tag in different scopes are 
> > compatible given requirements including compatible types for corresponding 
> > elements.  It would seem most appropriate to me for such structures with 
> > incompatible counted_by attributes to be considered *not* compatible types 
> > (but it would be valid to define structures with the same tag, different 
> > scopes, and elements the same except for counted_by - just not to use them 
> > in any way requiring them to be compatible).
> 
> Another option might be to warn about the case when those types
> are then used together in a way where they are required to
> be compatible.  Then comp_types_attributes would have to return 2.
> 
> 
> Martin
> 
> > 
> > > +The @code{counted_by} attribute may be attached to the C99 flexible array
> > > +member of a structure.  It indicates that the number of the elements of 
> > > the
> > > +array is given by the field "@var{count}" in the same structure as the
> > 
> > As noted previously, the "" quotes should be removed there (or replaced by 
> > ``'' quotes).
> > 
> 



Re: [PATCH v8 1/5] Provide counted_by attribute to flexible array member field (PR108896)

2024-04-10 Thread Martin Uecker
Am Mittwoch, dem 10.04.2024 um 17:35 + schrieb Joseph Myers:
> On Fri, 29 Mar 2024, Qing Zhao wrote:
> 
> > +  /* Issue error when there is a counted_by attribute with a different
> > + field as the argument for the same flexible array member field.  */
> 
> There's another case of this to consider, though I'm not sure where best 
> to check for it (Martin might have suggestions) - of course this case will 
> need testcases as well.
> 
> Suppose, as allowed in C23, a structure is defined twice in the same 
> scope, but the two definitions of the structure use inconsistent 
> counted_by attributes.  I'd say that, when the declarations are in the 
> same scope (thus required to be consistent), it should be an error for the 
> two definitions of what is meant to be the same structure to use 
> incompatible counted_by attributes (even though the member declarations 
> are otherwise the same).

I think the right place could be comp_types_attributes in
attributes.cc.  It may be sufficient to set the
affects_type_identify flag.

This should then give a redefinition error as it should do for
"packed".

> 
> In C23 structures defined with the same tag in different scopes are 
> compatible given requirements including compatible types for corresponding 
> elements.  It would seem most appropriate to me for such structures with 
> incompatible counted_by attributes to be considered *not* compatible types 
> (but it would be valid to define structures with the same tag, different 
> scopes, and elements the same except for counted_by - just not to use them 
> in any way requiring them to be compatible).

Another option might be to warn about the case when those types
are then used together in a way where they are required to
be compatible.  Then comp_types_attributes would have to return 2.


Martin

> 
> > +The @code{counted_by} attribute may be attached to the C99 flexible array
> > +member of a structure.  It indicates that the number of the elements of the
> > +array is given by the field "@var{count}" in the same structure as the
> 
> As noted previously, the "" quotes should be removed there (or replaced by 
> ``'' quotes).
> 



Re: [C PATCH] fix aliasing for structures/unions with incomplete types

2024-04-02 Thread Martin Uecker
Am Dienstag, dem 02.04.2024 um 20:42 + schrieb Joseph Myers:
> On Tue, 2 Apr 2024, Martin Uecker wrote:
> 
> > [C23]fix aliasing for structures/unions with incomplete types
> > 
> > When incomplete structure/union types are completed later, compatibility
> > of struct types that contain pointers to such types changes.  When forming
> > equivalence classes for TYPE_CANONICAL, we therefor need to be conservative
> > and treat all structs with the same tag which are pointer targets as
> > equivalent.
> 
> I don't see how what it done is actually about "which are pointer 
> targets".

Right, I see now that the description needs to be improved. This refers
only to targets of pointers included somewhere in the type we process
for purposes of determining the equivalence class of this type (but
not for other contexts).

> 
> > @@ -1355,6 +1356,7 @@ comptypes_internal (const_tree type1, const_tree 
> > type2,
> >/* Do not remove mode information.  */
> >if (TYPE_MODE (t1) != TYPE_MODE (t2))
> > return false;
> > +  data->pointedto = true;
> >return comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data);
> 
> This appears to be more like "which are the targets of pointers that *have 
> just been compared in the present comptypes call*".  Not which are targets 
> of some other pointers not involved in that call.

Correct.
> 
> Maybe some such logic based only on pointers compared in the present call 
> makes sense for some purposes, but it's not clear to me that either this 
> or any similar approach is a good approach for TYPE_CANONICAL - couldn't 
> that mean that two types are considered equivalent for TYPE_CANONICAL at 
> one point in the translation unit, but no longer equivalent at some later 
> point when the comparison takes place in the context of comparing two 
> other pointer types?

They would always be considered equivalent when pointed to from another
struct (or indirectly from a type nested in this struct) for purposes
of determining the equivalence class of this struct.

When not a pointer target, i.e. when considering the struct type itself
for which we compute TYPE_CANONICAL or another struct type directly used
for a member, then the types are compared by recursing into them. Such 
types can never be incomplete at this point, so this is also stable property.

To summarize: for determining equivalence classes we always stop
the recursion after following pointers into other structs. We give
the same TYPE_CANONICAL to the following two structs foo:

struct foo { struct aa { int x; } *p; };
struct foo { struct aa { float x; } *p; };

while we give different TYPE_CANONICAL to

struct bar { struct aa { int x; } p; };
struct bar { struct aa { float x; } p; };

(not pointer).  The reason is that for the struct foo's there
could be a 

struct foo { struct aa *p; };

with incomplete type struct aa that later turns out to be compatible
with either of them. So we have to put them all into the same 
equivalence class.

(a potential alternative is to compute the classes only at the very end
when all types have stablized, but this would require much more changes
and another pass over all the types.)


Note that the TYPE_CANONICAL for the aa's is not affected in any case and
always computed based on *their* content  independent of whether they are
pointer targets or not.  (but this reminds me to double check what
happens with types that are never completed in a TU.).


I hope this explanation makes sense.


Martin




> 



[C PATCH] fix aliasing for structures/unions with incomplete types

2024-04-02 Thread Martin Uecker



While fixing the other issue, I realized that the way the
equivalence classes are computed for TYPE_CANONICAL did
not take into account that completion of struct types
also affectes compatibility of types that contain pointers
to them.  So the algorithm must be more conservative
creating bigger equivalence classes.



Bootstrapped and regession tested on x86_64



[C23]fix aliasing for structures/unions with incomplete types

When incomplete structure/union types are completed later, compatibility
of struct types that contain pointers to such types changes.  When forming
equivalence classes for TYPE_CANONICAL, we therefor need to be conservative
and treat all structs with the same tag which are pointer targets as
equivalent.

gcc/c/
* c-typeck.cc (comptypes_internal): Add flag to track
whether a struct is the target of a pointer.
(tagged_types_tu_compatible): When forming equivalence
classes, treat pointed-to structs as equivalent.

gcc/testsuite/
* gcc.dg/c23-tag-incomplate-alias-1.c: New test.
---
 gcc/c/c-typeck.cc | 11 ++
 .../gcc.dg/c23-tag-incomplete-alias-1.c   | 34 +++
 2 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-alias-1.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ddeab1e2a8a..b86450580ad 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1170,6 +1170,7 @@ struct comptypes_data {
   bool different_types_p;
   bool warning_needed;
   bool anon_field;
+  bool pointedto;
   bool equiv;
 
   const struct tagged_tu_seen_cache* cache;
@@ -1355,6 +1356,7 @@ comptypes_internal (const_tree type1, const_tree type2,
   /* Do not remove mode information.  */
   if (TYPE_MODE (t1) != TYPE_MODE (t2))
return false;
+  data->pointedto = true;
   return comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data);
 
 case FUNCTION_TYPE:
@@ -1513,6 +1515,14 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
   if (TYPE_NAME (t1) != TYPE_NAME (t2))
 return false;
 
+  /* When forming equivalence classes for TYPE_CANONICAL in C23, we
+ have to treat structs with the same tag as equivalent, when they
+ are targets of pointers inside other structs.  This is necessary
+ so that the relationship of types does not change when incomplete
+ types are completed.  */
+  if (data->equiv && data->pointedto)
+return true;
+
   if (!data->anon_field && NULL_TREE == TYPE_NAME (t1))
 return false;
 
@@ -1608,6 +1618,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
  return false;
 
data->anon_field = !DECL_NAME (s1);
+   data->pointedto = false;
 
data->cache = 
if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data))
diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-alias-1.c 
b/gcc/testsuite/gcc.dg/c23-tag-incomplete-alias-1.c
new file mode 100644
index 000..7fb6a8513b2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-alias-1.c
@@ -0,0 +1,34 @@
+/* { dg-do run } 
+ * { dg-options "-std=c23 -O2" } */
+
+[[gnu::noinline]]
+void *alias(void *ap, void *b, void *x, void *y)
+{
+   struct foo { struct bar *f; } *a = ap;
+   struct bar { long x; };
+
+   a->f = x;
+
+   {
+   struct bar;
+   struct foo { struct bar *f; };
+   struct bar { long x; };
+
+   ((struct foo*)b)->f = y;
+   }
+
+
+   return a->f;
+}
+
+int main()
+{
+   struct bar { long x; };
+   struct foo { struct bar *f; } a;
+   struct bar x, y;
+   if ( != alias(, , , ))
+   __builtin_abort();
+
+   return 0;
+}
+
-- 
2.39.2




[C PATCH] Fix ICE with -g and -std=c23 related to incomplete types [PR114361]

2024-04-02 Thread Martin Uecker



I did not copy TYPE_CANONICAL to incomplete variants
when they are completed.



Bootstrapped and regession tested on x86_64



Fix ICE with -g and -std=c23 related to incomplete types [PR114361]

We did not copy TYPE_CANONICAL to the incomplete variants when
completing a structure.

PR c/114361

gcc/c/
* c-decl.c (finish_struct): Set TYPE_CANONICAL when completing
strucute types.

gcc/testsuite/
* gcc.dg/pr114361.c: New test.
* gcc.dg/c23-tag-incomplete-1.c: New test.
* gcc.dg/c23-tag-incomplete-2.c: New test.
---
 gcc/c/c-decl.cc |  1 +
 gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c | 14 ++
 gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c | 13 +
 gcc/testsuite/gcc.dg/pr114361.c | 11 +++
 4 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr114361.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index c747abe9f4e..f2083b9d96f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9722,6 +9722,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
   C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (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.
diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c 
b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
new file mode 100644
index 000..82d652569e9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23 -g" } */
+
+struct a;
+typedef struct a b;
+
+void g() {
+struct a { b* x; };
+}
+
+struct a { b* x; };
+
+
+
diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c 
b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
new file mode 100644
index 000..bc47a04ece5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23 -g" } */
+
+struct a;
+typedef struct a b;
+
+void f() {
+   extern struct a { b* x; } t;
+}
+
+extern struct a { b* x; } t;
+
+
diff --git a/gcc/testsuite/gcc.dg/pr114361.c b/gcc/testsuite/gcc.dg/pr114361.c
new file mode 100644
index 000..0f3feb53566
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114361.c
@@ -0,0 +1,11 @@
+/* PR c/114361 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -g" } */
+
+void f()
+{
+typedef struct foo bar;
+typedef __typeof( ({ (struct foo { bar *x; }){ }; }) ) wuz;
+struct foo { wuz *x; };
+}
+
-- 
2.39.2




Re: [PATCH v4 0/4]New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2024-01-29 Thread Martin Uecker
Am Montag, dem 29.01.2024 um 15:09 + schrieb Qing Zhao:
> Thank you!
> 
> Joseph and Richard,  could you also comment on this?
> 
> > On Jan 28, 2024, at 5:09 AM, Martin Uecker  wrote:
> > 
> > Am Freitag, dem 26.01.2024 um 14:33 + schrieb Qing Zhao:
> > > 
> > > > On Jan 26, 2024, at 3:04 AM, Martin Uecker  wrote:
> > > > 
> > > > 
> > > > I haven't looked at the patch, but it sounds you give the result
> > > > the wrong type. Then patching up all use cases instead of the
> > > > type seems wrong.
> > > 
> > > Yes, this is for resolving a very early gimplification issue as I 
> > > reported last Nov:
> > > https://gcc.gnu.org/pipermail/gcc-patches/2023-November/638793.html
> > > 
> > > Since no-one responded at that time, I fixed the issue by replacing the 
> > > ARRAY_REF
> > > With a pointer indirection:
> > > https://gcc.gnu.org/pipermail/gcc-patches/2023-December/639605.html
> > > 
> > > The reason for such change is:  return a flexible array member TYPE is 
> > > not allowed
> > > by C language (our gimplification follows this rule), so, we have to 
> > > return a pointer TYPE instead. 
> > > 
> > > **The new internal function
> > > 
> > > .ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, CLASS_OF_SIZE, SIZE_OF_SIZE, 
> > > ACCESS_MODE, INDEX)
> > > 
> > > INTERNAL_FN (ACCESS_WITH_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
> > > 
> > > which returns the "REF_TO_OBJ" same as the 1st argument;
> > > 
> > > Both the return type and the type of the first argument of this function 
> > > have been converted from 
> > > the incomplete array type to the corresponding pointer type.
> > > 
> > > As a result, the original ARRAY_REF was converted to an INDIRECT_REF, the 
> > > original INDEX of the ARRAY_REF was lost
> > > when converting from ARRAY_REF to INDIRECT_REF, in order to keep the 
> > > INDEX for bound sanitizer instrumentation, I added
> > > The 6th argument “INDEX”.
> > > 
> > > What’s your comment and suggestion on this solution?
> > 
> > I am not entirely sure but changing types in the FE seems
> > problematic because this breaks language semantics. And
> > then adding special code everywhere to treat it specially
> > in the FE does not seem a good way forward.
> > 
> > If I understand correctly, returning an incomplete array 
> > type is not allowed and then fails during gimplification.
> 
> Yes, this is the problem in gimplification. 
> 
> > So I would suggest to make it return a pointer to the 
> > incomplete array (and not the element type)
> 
> 
> for the following:
> 
> struct annotated {
>   unsigned int size;
>   int array[] __attribute__((counted_by (size)));
> };
> 
>   struct annotated * p = ….
>   p->array[9] = 0;
> 
> The IL for the above array reference p->array[9] is:
> 
> 1. If the return type is the original incomplete array type, 
> 
> .ACCESS_WITH_SIZE ((int *) >array, >size, 1, 32, -1)[9] = 0;
> 
> (this triggered the gimplification failure since the return type cannot be a 
> complete type).
> 
> 2. When the return type is changed to a pointer to the element type of the 
> incomplete array, (the current patch)
> Then the original array reference naturally becomes an indirect reference 
> through the pointer
> 
> *(.ACCESS_WITH_SIZE ((int *) >array, >size, 1, 32, -1, 9) + 36) = 0;
> 
> Since the original array reference becomes an indirect reference through the 
> pointer to the element array, the INDEX info 
> is mixed into the OFFSET of the indirect reference and lost, so, I added the 
> 6th argument to the routine .ACCESS_WITH_SIZE
> to record the INDEX. 
> 
> 3. With your suggestion, the return type is changed to a pointer to the 
> incomplete array, 
> I just tried this to change the result type :
> 
> 
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -2619,7 +2619,7 @@ build_access_with_size_for_counted_by (location_t loc, 
> tree ref,
>tree counted_by_type)
>  {
>gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref)));
> -  tree result_type = build_pointer_type (TREE_TYPE (TREE_TYPE (ref)));
> +  tree result_type = build_pointer_type (TREE_TYPE (ref));
> 
> Then, I got the following FE errors:
> 
> test.c:10:11: error: invalid use of flexible array member
>10 |   p->array[9] = 0;
> 
> The reason for the error is: when the orig

Re: [PATCH v4 0/4]New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2024-01-28 Thread Martin Uecker
Am Freitag, dem 26.01.2024 um 14:33 + schrieb Qing Zhao:
> 
> > On Jan 26, 2024, at 3:04 AM, Martin Uecker  wrote:
> > 
> > 
> > I haven't looked at the patch, but it sounds you give the result
> > the wrong type. Then patching up all use cases instead of the
> > type seems wrong.
> 
> Yes, this is for resolving a very early gimplification issue as I reported 
> last Nov:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-November/638793.html
> 
> Since no-one responded at that time, I fixed the issue by replacing the 
> ARRAY_REF
> With a pointer indirection:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-December/639605.html
> 
> The reason for such change is:  return a flexible array member TYPE is not 
> allowed
> by C language (our gimplification follows this rule), so, we have to return a 
> pointer TYPE instead. 
> 
> **The new internal function
> 
>  .ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, CLASS_OF_SIZE, SIZE_OF_SIZE, 
> ACCESS_MODE, INDEX)
> 
> INTERNAL_FN (ACCESS_WITH_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
> 
> which returns the "REF_TO_OBJ" same as the 1st argument;
> 
> Both the return type and the type of the first argument of this function have 
> been converted from 
> the incomplete array type to the corresponding pointer type.
> 
> As a result, the original ARRAY_REF was converted to an INDIRECT_REF, the 
> original INDEX of the ARRAY_REF was lost
> when converting from ARRAY_REF to INDIRECT_REF, in order to keep the INDEX 
> for bound sanitizer instrumentation, I added
> The 6th argument “INDEX”.
> 
> What’s your comment and suggestion on this solution?

I am not entirely sure but changing types in the FE seems
problematic because this breaks language semantics. And
then adding special code everywhere to treat it specially
in the FE does not seem a good way forward.

If I understand correctly, returning an incomplete array 
type is not allowed and then fails during gimplification.
So I would suggest to make it return a pointer to the 
incomplete array (and not the element type) but then wrap
it with an indirection when inserting this code in the FE
so that the full replacement has the correct type again
(of the incomplete array).


Alternatively, one could allow this during gimplification
or add some conversion.

Martin


> 
> Thanks.
> 
> Qing
> 
> 
> > 
> > Martin
> > 
> > 
> > Am Donnerstag, dem 25.01.2024 um 20:11 + schrieb Qing Zhao:
> > > Thanks a lot for the testing.
> > > 
> > > Yes, I can repeat the issue with the following small example:
> > > 
> > > #include 
> > > #include 
> > > #include 
> > > 
> > > #define MAX(a, b)  ((a) > (b) ? (a) :  (b))
> > > 
> > > struct untracked {
> > >   int size;
> > >   int array[] __attribute__((counted_by (size)));
> > > } *a;
> > > struct untracked * alloc_buf (int index)
> > > {
> > >  struct untracked *p;
> > >  p = (struct untracked *) malloc (MAX (sizeof (struct untracked),
> > >(offsetof (struct untracked, 
> > > array[0])
> > > + (index) * sizeof (int;
> > >  p->size = index;
> > >  return p;
> > > }
> > > 
> > > int main()
> > > {
> > >  a = alloc_buf(10);
> > > printf ("same_type is %d\n",
> > >  (__builtin_types_compatible_p(typeof (a->array), typeof 
> > > (&(a->array)[0];
> > >  return 0;
> > > }
> > > 
> > > 
> > > /home/opc/Install/latest-d/bin/gcc -O2 btcp.c
> > > same_type is 1
> > > 
> > > Looks like that the “typeof” operator need to be handled specially in C FE
> > > for the new internal function .ACCESS_WITH_SIZE. 
> > > 
> > > (I have specially handle the operator “offsetof” in C FE already).
> > > 
> > > Will fix this issue.
> > > 
> > > Thanks.
> > > 
> > > Qing
> > > 
> > > > On Jan 24, 2024, at 7:51 PM, Kees Cook  wrote:
> > > > 
> > > > On Wed, Jan 24, 2024 at 12:29:51AM +, Qing Zhao wrote:
> > > > > This is the 4th version of the patch.
> > > > 
> > > > Thanks very much for this!
> > > > 
> > > > I tripped over an unexpected behavioral change that the Linux kernel
> > > > depends on:
> > > > 
> > > > __builtin_types_compatible_p() no longer treats an array marked with
> > > > counted_by as differ

Fix ICE with -g and -std=c23 when forming composite types [PR113438]

2024-01-27 Thread Martin Uecker


Debug output ICEs when we do not set TYPE_STUB_DECL, fix this.


Fix ICE with -g and -std=c23 when forming composite types [PR113438]

Set TYPE_STUB_DECL to an artificial decl when creating a new structure
as a composite type.

PR c/113438

gcc/c/
* c-typeck.cc (composite_type_internal): Set TYPE_STUB_DECL.

gcc/testsuite/
* gcc.dg/pr113438.c: New test.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 66c6abc9f07..cfa3b7ab10f 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -585,6 +585,11 @@ composite_type_internal (tree t1, tree t2, struct 
composite_cache* cache)
  /* Setup the struct/union type.  Because we inherit all variably
 modified components, we can ignore the size expression.  */
  tree expr = NULL_TREE;
+
+ /* Set TYPE_STUB_DECL for debugging symbols.  */
+ TYPE_STUB_DECL (n) = pushdecl (build_decl (input_location, TYPE_DECL,
+NULL_TREE, n));
+
  n = finish_struct(input_location, n, fields, attributes, NULL, );
 
  n = qualify_type (n, t1);
diff --git a/gcc/testsuite/gcc.dg/pr113438.c b/gcc/testsuite/gcc.dg/pr113438.c
new file mode 100644
index 000..5612ee4fa38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr113438.c
@@ -0,0 +1,7 @@
+/* PR113438
+ * { dg-do compile }
+ * { dg-options "-std=c23 -g" } */
+
+void g(struct foo { int x; } a);
+void g(struct foo { int x; } a);
+



Re: [PATCH v4 0/4]New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2024-01-26 Thread Martin Uecker


I haven't looked at the patch, but it sounds you give the result
the wrong type. Then patching up all use cases instead of the
type seems wrong.

Martin


Am Donnerstag, dem 25.01.2024 um 20:11 + schrieb Qing Zhao:
> Thanks a lot for the testing.
> 
> Yes, I can repeat the issue with the following small example:
> 
> #include 
> #include 
> #include 
> 
> #define MAX(a, b)  ((a) > (b) ? (a) :  (b))
> 
> struct untracked {
>int size;
>int array[] __attribute__((counted_by (size)));
> } *a;
> struct untracked * alloc_buf (int index)
> {
>   struct untracked *p;
>   p = (struct untracked *) malloc (MAX (sizeof (struct untracked),
> (offsetof (struct untracked, array[0])
>  + (index) * sizeof (int;
>   p->size = index;
>   return p;
> }
> 
> int main()
> {
>   a = alloc_buf(10);
>  printf ("same_type is %d\n",
>   (__builtin_types_compatible_p(typeof (a->array), typeof (&(a->array)[0];
>   return 0;
> }
> 
> 
> /home/opc/Install/latest-d/bin/gcc -O2 btcp.c
> same_type is 1
> 
> Looks like that the “typeof” operator need to be handled specially in C FE
>  for the new internal function .ACCESS_WITH_SIZE. 
> 
> (I have specially handle the operator “offsetof” in C FE already).
> 
> Will fix this issue.
> 
> Thanks.
> 
> Qing
> 
> > On Jan 24, 2024, at 7:51 PM, Kees Cook  wrote:
> > 
> > On Wed, Jan 24, 2024 at 12:29:51AM +, Qing Zhao wrote:
> > > This is the 4th version of the patch.
> > 
> > Thanks very much for this!
> > 
> > I tripped over an unexpected behavioral change that the Linux kernel
> > depends on:
> > 
> > __builtin_types_compatible_p() no longer treats an array marked with
> > counted_by as different from that array's decayed pointer. Specifically,
> > the kernel uses these macros:
> > 
> > 
> > /*
> > * Force a compilation error if condition is true, but also produce a
> > * result (of value 0 and type int), so the expression can be used
> > * e.g. in a structure initializer (or where-ever else comma expressions
> > * aren't permitted).
> > */
> > #define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))
> > 
> > #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
> > 
> > /* [0] degrades to a pointer: a different type from an array */
> > #define __must_be_array(a)   BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
> > 
> > 
> > This gets used in various places to make sure we're dealing with an
> > array for a macro:
> > 
> > #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + 
> > __must_be_array(arr))
> > 
> > 
> > So this builds:
> > 
> > struct untracked {
> >int size;
> >int array[];
> > } *a;
> > 
> > __must_be_array(a->array)
> > => 0 (as expected)
> > __builtin_types_compatible_p(typeof(a->array), typeof(&(a->array)[0]))
> > => 0 (as expected, array vs decayed array pointer)
> > 
> > 
> > But if counted_by is added, we get a build failure:
> > 
> > struct tracked {
> >int size;
> >int array[] __counted_by(size);
> > } *b;
> > 
> > __must_be_array(b->array)
> > => build failure (not expected)
> > __builtin_types_compatible_p(typeof(b->array), typeof(&(b->array)[0]))
> > => 1 (not expected, both pointers?)
> > 
> > 
> > 
> > 
> > -- 
> > Kees Cook
> 



[C PATCH] Fix ICE for composite type for structs with unsigned bitfields [PR113492]

2024-01-20 Thread Martin Uecker


C23: Fix ICE for composite type for structs with unsigned bitfields [PR113492]

This patch fixes a bug when forming a composite type from structs that
contain an unsigned bitfield declared with int while using -funsigned-bitfields.
In such structs the unsigned integer type was not compatible to the
regular unsigned integer type used elsewhere in the C FE.

PR c/113492

gcc/c:
* c-decl.cc (grokdeclarator): Use c_common_unsigned_type instead of
unsigned_type_for to create the unsigned type for bitfields declared
with int when using -funsigned-bitfields.

gcc/testsuite:
* gcc.dg/pr113492.c: New test.




diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4029bbc59fe..8d18a3e11f4 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6947,7 +6947,7 @@ grokdeclarator (const struct c_declarator *declarator,
  "signed".  */
   if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p
   && TREE_CODE (type) == INTEGER_TYPE)
-type = unsigned_type_for (type);
+type = c_common_unsigned_type (type);
 
   /* Figure out the type qualifiers for the declaration.  There are
  two ways a declaration can become qualified.  One is something
diff --git a/gcc/testsuite/gcc.dg/pr113492.c b/gcc/testsuite/gcc.dg/pr113492.c
new file mode 100644
index 000..56296c51072
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr113492.c
@@ -0,0 +1,43 @@
+/* PR 113492
+ * { dg-do compile }
+ * { dg-options "-std=c23 -funsigned-bitfields" } */
+
+struct foo {
+   int i : 3;
+} i;
+
+void test()
+{
+   struct foo {
+   unsigned i : 3;
+   } u;
+
+   1 ? i : u;
+   1 ? u : i;
+}
+   
+struct bar {
+   unsigned i : 3;
+} u;
+
+void test2()
+{
+   struct bar {
+   int i : 3;
+   } i;
+
+   1 ? i : u;
+   1 ? u : i;
+}
+   
+void test3()
+{
+   typedef int myint;
+   struct bar {
+   myint i : 3;
+   } i;
+
+   1 ? i : u;
+   1 ? u : i;
+}
+



[C PATCH] C: Fix type compatibility for structs with variable sized fields.

2023-12-27 Thread Martin Uecker


This patch hopefully fixes the test failure we see with gnu23-tag-4.c.
It does for me locally with -march=native (which otherwise reproduces
the problem).

Bootstrapped and regession tested on x86_64


C: Fix type compatibility for structs with variable sized fields.

This fixes the test gcc.dg/gnu23-tag-4.c introduced by commit 23fee88f
which fails for -march=... because the DECL_FIELD_BIT_OFFSET are set
inconsistently for types with and without variable-sized field.  This
is fixed by testing for DECL_ALIGN instead.  The code is further
simplified by removing some unnecessary conditions, i.e. anon_field is
set unconditionaly and all fields are assumed to be DECL_FIELDs.

gcc/c:
* c-typeck.c (tagged_types_tu_compatible_p): Revise.

gcc/testsuite:
* gcc.dg./c23-tag-9.c: New test.
---
 gcc/c/c-typeck.cc| 19 ---
 gcc/testsuite/gcc.dg/c23-tag-9.c |  8 
 2 files changed, 16 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-9.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2d9139d09d2..84ddda1ebab 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1511,8 +1511,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
   if (!data->anon_field && TYPE_STUB_DECL (t1) != TYPE_STUB_DECL (t2))
 data->different_types_p = true;
 
-  data->anon_field = false;
-
   /* Incomplete types are incompatible inside a TU.  */
   if (TYPE_SIZE (t1) == NULL || TYPE_SIZE (t2) == NULL)
 return false;
@@ -1592,22 +1590,21 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
 s1 && s2;
 s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
  {
-   if (TREE_CODE (s1) != TREE_CODE (s2)
-   || DECL_NAME (s1) != DECL_NAME (s2))
+   gcc_assert (TREE_CODE (s1) == FIELD_DECL);
+   gcc_assert (TREE_CODE (s2) == FIELD_DECL);
+
+   if (DECL_NAME (s1) != DECL_NAME (s2))
+ return false;
+
+   if (DECL_ALIGN (s1) != DECL_ALIGN (s2))
  return false;
 
-   if (!DECL_NAME (s1) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (s1)))
- data->anon_field = true;
+   data->anon_field = !DECL_NAME (s1);
 
data->cache = 
if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data))
  return false;
 
-   if (TREE_CODE (s1) == FIELD_DECL
-   && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
-DECL_FIELD_BIT_OFFSET (s2)) != 1)
- return false;
-
tree st1 = TYPE_SIZE (TREE_TYPE (s1));
tree st2 = TYPE_SIZE (TREE_TYPE (s2));
 
diff --git a/gcc/testsuite/gcc.dg/c23-tag-9.c b/gcc/testsuite/gcc.dg/c23-tag-9.c
new file mode 100644
index 000..1d32560ec23
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-9.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+struct foo { int x; } x;
+struct foo { alignas(128) int x; } y;  /* { dg-error "redefinition" } */
+static_assert(alignof(y) == 128);
+
+
-- 
2.39.2





Re: [r14-6770 Regression] FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors) on Linux/x86_64

2023-12-25 Thread Martin Uecker


Yes, I am testing a patch. The DECL_FIELD_BIT_OFFSET are set
inconsistently for some reason.

Martin 

Am Montag, dem 25.12.2023 um 07:49 + schrieb Jiang, Haochen:
> It is not a target specific issue, it will fail if we enabled AVX.
> 
> e.g.:
> 
> $ /export/users/haochenj/env/build_no_bootstrap_master/gcc/xgcc 
> -B/export/users/haochenj/env/build_no_bootstrap_master/gcc/  
> /export/users/haochenj/src/gcc/master/gcc/testsuite/gcc.dg/gnu23-tag-4.c  
> -m64 -mavx   -fdiagnostics-plain-output   -std=gnu23 -S -o gnu23-tag-4.s
> /export/users/haochenj/src/gcc/master/gcc/testsuite/gcc.dg/gnu23-tag-4.c: In 
> function ‘bar’:
> /export/users/haochenj/src/gcc/master/gcc/testsuite/gcc.dg/gnu23-tag-4.c:18:47:
>  error: initialization of ‘struct g *’ from incompatible pointer type ‘struct 
> g *’ [-Wincompatible-pointer-types]
> 
> Thx,
> Haochen
> 
> > -Original Message-
> > From: Martin Uecker 
> > Sent: Friday, December 22, 2023 5:39 PM
> > To: gcc-regress...@gcc.gnu.org; gcc-patches@gcc.gnu.org; Jiang, Haochen
> > ; Joseph Myers 
> > Subject: Re: [r14-6770 Regression] FAIL: gcc.dg/gnu23-tag-4.c (test for 
> > excess
> > errors) on Linux/x86_64
> > 
> > 
> > Hm, this is weird, as it really seems to depend on the -march=  So if 
> > there is
> > really a difference between those structs which make them incompatible on
> > some archs, we should not consider them to be compatible in general.
> > 
> > struct g { int a[n]; int b; } *y;
> > { struct g { int a[4]; int b; } *y2 = y; }
> > 
> > But I do not see what could go wrong here as sizeof / alignment is the same 
> > for
> > n = 4.  So there is something else I missed
> > 
> > 
> > 
> > Am Freitag, dem 22.12.2023 um 05:07 +0800 schrieb haochen.jiang:
> > > On Linux/x86_64,
> > > 
> > > 23fee88f84873b0b8b41c8e5a9b229d533fb4022 is the first bad commit
> > > commit 23fee88f84873b0b8b41c8e5a9b229d533fb4022
> > > Author: Martin Uecker 
> > > Date:   Tue Aug 15 14:58:32 2023 +0200
> > > 
> > > c23: tag compatibility rules for struct and unions
> > > 
> > > caused
> > > 
> > > FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors)
> > > 
> > > with GCC configured with
> > > 
> > > ../../gcc/configure
> > > --prefix=/export/users/haochenj/src/gcc-bisect/master/master/r14-6770/
> > > usr --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld
> > > --with-fpmath=sse --enable-languages=c,c++,fortran --enable-cet
> > > --without-isl --enable-libmpx x86_64-linux --disable-bootstrap
> > > 
> > > To reproduce:
> > > 
> > > $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-
> > tag-4.c --target_board='unix{-m32\ -march=cascadelake}'"
> > > $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-
> > tag-4.c --target_board='unix{-m64\ -march=cascadelake}'"
> > > 
> > > (Please do not reply to this email, for question about this report,
> > > contact me at haochen dot jiang at intel.com.) (If you met problems
> > > with cascadelake related, disabling AVX512F in command line might save
> > that.) (However, please make sure that there is no potential problems with
> > AVX512.)
> 



Re: [r14-6770 Regression] FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors) on Linux/x86_64

2023-12-22 Thread Martin Uecker


Hm, this is weird, as it really seems to depend on the
-march=  So if there is really a difference
between those structs which make them incompatible on
some archs, we should not consider them to be
compatible in general.

struct g { int a[n]; int b; } *y;
{ struct g { int a[4]; int b; } *y2 = y; }

But I do not see what could go wrong here as
sizeof / alignment is the same for n = 4.  So there
is something else I missed



Am Freitag, dem 22.12.2023 um 05:07 +0800 schrieb haochen.jiang:
> On Linux/x86_64,
> 
> 23fee88f84873b0b8b41c8e5a9b229d533fb4022 is the first bad commit
> commit 23fee88f84873b0b8b41c8e5a9b229d533fb4022
> Author: Martin Uecker 
> Date:   Tue Aug 15 14:58:32 2023 +0200
> 
> c23: tag compatibility rules for struct and unions
> 
> caused
> 
> FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors)
> 
> with GCC configured with
> 
> ../../gcc/configure 
> --prefix=/export/users/haochenj/src/gcc-bisect/master/master/r14-6770/usr 
> --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld 
> --with-fpmath=sse --enable-languages=c,c++,fortran --enable-cet --without-isl 
> --enable-libmpx x86_64-linux --disable-bootstrap
> 
> To reproduce:
> 
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-tag-4.c 
> --target_board='unix{-m32\ -march=cascadelake}'"
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-tag-4.c 
> --target_board='unix{-m64\ -march=cascadelake}'"
> 
> (Please do not reply to this email, for question about this report, contact 
> me at haochen dot jiang at intel.com.)
> (If you met problems with cascadelake related, disabling AVX512F in command 
> line might save that.)
> (However, please make sure that there is no potential problems with AVX512.)



[V6] c23: construct composite type for tagged types

2023-12-21 Thread Martin Uecker


This version now sets  DECL_NONADDRESSABLE_P, DECL_PADDING_P 
and C_DECL_VARIABLE_SIZE and adds three new tests:
c23-tag-alias-7.c, c23-tag-composite-10.c, and 
gnu23-tag-composite-5.c.

Martin



Support for constructing composite types 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.
* c-decl.cc (finish_struct): Allow NULL for
enclosing_struct_parse_info.

gcc/testsuite:
* gcc.dg/c23-tag-alias-6.c: New test.
* gcc.dg/c23-tag-alias-7.c: New test.
* gcc.dg/c23-tag-composite-1.c: New test.
* gcc.dg/c23-tag-composite-2.c: New test.
* gcc.dg/c23-tag-composite-3.c: New test.
* gcc.dg/c23-tag-composite-4.c: New test.
* gcc.dg/c23-tag-composite-5.c: New test.
* gcc.dg/c23-tag-composite-6.c: New test.
* gcc.dg/c23-tag-composite-7.c: New test.
* gcc.dg/c23-tag-composite-8.c: New test.
* gcc.dg/c23-tag-composite-9.c: New test.
* gcc.dg/c23-tag-composite-10.c: New test.
* gcc.dg/gnu23-tag-composite-1.c: New test.
* gcc.dg/gnu23-tag-composite-2.c: New test.
* gcc.dg/gnu23-tag-composite-3.c: New test.
* gcc.dg/gnu23-tag-composite-4.c: New test.
* gcc.dg/gnu23-tag-composite-5.c: New test.
---
 gcc/c/c-decl.cc  |  21 +--
 gcc/c/c-typeck.cc| 140 ---
 gcc/testsuite/gcc.dg/c23-tag-alias-6.c   |  32 +
 gcc/testsuite/gcc.dg/c23-tag-alias-7.c   |  34 +
 gcc/testsuite/gcc.dg/c23-tag-composite-1.c   |  26 
 gcc/testsuite/gcc.dg/c23-tag-composite-10.c  |  35 +
 gcc/testsuite/gcc.dg/c23-tag-composite-2.c   |  16 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-3.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-4.c   |  21 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-5.c   |  25 
 gcc/testsuite/gcc.dg/c23-tag-composite-6.c   |  18 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-7.c   |  20 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-8.c   |  15 ++
 gcc/testsuite/gcc.dg/c23-tag-composite-9.c   |  19 +++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c |  45 ++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c |  30 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c |  24 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c |  28 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-5.c |  29 
 19 files changed, 601 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-10.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-8.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-9.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-5.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6639ec35e5f..b72738ea04a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9674,7 +9674,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 }
 
   /* Check for consistency with previous definition.  */
-  if (flag_isoc23)
+  if (flag_isoc23 && NULL != enclosing_struct_parse_info)
 {
   tree vistype = previous_tag (t);
   if (vistype
@@ -9744,16 +9744,19 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
 
-  delete struct_parse_info;
+  if (NULL != enclosing_struct_parse_info)
+{
+  delete struct_parse_info;
 
-  struct_parse_info = enclosing_struct_parse_info;
+  struct_parse_info = enclosing_struct_parse_info;
 
-  /* If this struct is defined inside a struct, add it to
- struct_types.  */
-  if (warn_cxx_compat
-  && struct_parse_info != NULL
-  && !in_sizeof && !in_typeof && !in_alignof)
-struct_parse_info->struct_types.safe_push (t);
+  /* If this struct is defined inside a struct, add it to
+struct_types.  */
+  if (warn_cxx_compat
+ && struct_parse_info != NULL
+ && !in_sizeof && !in_typeof && 

Re: [PATCH] c: Split -Wcalloc-transposed-args warning from -Walloc-size, -Walloc-size fixes

2023-12-19 Thread Martin Uecker
Am Dienstag, dem 19.12.2023 um 12:20 -0500 schrieb Jason Merrill:
> On 12/19/23 03:47, Jakub Jelinek wrote:
> > On Tue, Dec 19, 2023 at 08:11:11AM +0100, Martin Uecker wrote:
> > > Am Montag, dem 18.12.2023 um 20:14 +0100 schrieb Jakub Jelinek:
> > > > Hi!
> > > > 
> > > > The following patch changes -Walloc-size warning to no longer warn
> > > > about int *p = calloc (1, sizeof (int));, because as discussed earlier,
> > > > the size is IMNSHO sufficient in that case, for alloc_size with 2
> > > > arguments warns if the product of the 2 arguments is insufficiently 
> > > > small.
> > > > 
> > > > Also, it warns also for explicit casts of malloc/calloc etc. calls
> > > > rather than just implicit, so not just
> > > >int *p = malloc (1);
> > > > but also
> > > >int *p = (int *) malloc (1);
> > > > 
> > > > It also fixes some ICEs where the code didn't verify the alloc_size
> > > > arguments properly (Walloc-size-5.c testcase ICEs with vanilla trunk).
> > > > 
> > > > And lastly, it introduces a coding style warning, 
> > > > -Wcalloc-transposed-args
> > > > to warn for calloc (sizeof (struct S), 1) and similar calls (regardless
> > > > of what they are cast to, warning whenever first argument is sizeof and
> > > > the second is not).
> > > 
> > > I would generally see function arguments that are swapped relative
> > > to the documented ABI as more than a coding style issue even in
> > > cases where it can be expected to make no difference.
> > 
> > If you have suggestions how to reword the documentation, would that be
> > sufficient for you?  I still don't see why given correct alignment one can't
> > store struct S into sizeof (struct S) sized heap char array,
> 
> Seems to me one can in C++, anyway.  An unsigned char array can provide 
> storage for another type, and the call to calloc can be interpreted as 
> creating such an array if that gives the program defined behavior.
> https://eel.is/c++draft/intro.object#def:provides_storage
> https://eel.is/c++draft/intro.object#def:object,implicit_creation

This is also true in C.  There is nothing wrong with calloc(10, 1)
allocating a char array with 10 elements and then storing a struct
of size 10 in it.


Martin

> 



Re: [PATCH] c: Split -Wcalloc-transposed-args warning from -Walloc-size, -Walloc-size fixes

2023-12-19 Thread Martin Uecker
Am Dienstag, dem 19.12.2023 um 09:47 +0100 schrieb Jakub Jelinek:
> On Tue, Dec 19, 2023 at 08:11:11AM +0100, Martin Uecker wrote:
> > Am Montag, dem 18.12.2023 um 20:14 +0100 schrieb Jakub Jelinek:
> > > Hi!
> > > 
> > > The following patch changes -Walloc-size warning to no longer warn
> > > about int *p = calloc (1, sizeof (int));, because as discussed earlier,
> > > the size is IMNSHO sufficient in that case, for alloc_size with 2
> > > arguments warns if the product of the 2 arguments is insufficiently small.
> > > 
> > > Also, it warns also for explicit casts of malloc/calloc etc. calls
> > > rather than just implicit, so not just
> > >   int *p = malloc (1);
> > > but also
> > >   int *p = (int *) malloc (1);
> > > 
> > > It also fixes some ICEs where the code didn't verify the alloc_size
> > > arguments properly (Walloc-size-5.c testcase ICEs with vanilla trunk).
> > > 
> > > And lastly, it introduces a coding style warning, -Wcalloc-transposed-args
> > > to warn for calloc (sizeof (struct S), 1) and similar calls (regardless
> > > of what they are cast to, warning whenever first argument is sizeof and
> > > the second is not).
> > 
> > I would generally see function arguments that are swapped relative
> > to the documented ABI as more than a coding style issue even in 
> > cases where it can be expected to make no difference.
> 
> If you have suggestions how to reword the documentation, would that be
> sufficient for you?  

Maybe simple remove "This is a coding style warning." ?

> I still don't see why given correct alignment one can't
> store struct S into sizeof (struct S) sized heap char array, but if the
> documentation explain reasons why should one write it one way and not the
> other except for coding style, sure.

I do not think we need to argue one way or the other in
the documentation.  

> 
> > > Ok for trunk if this passes bootstrap/regtest?
> > 
> > I wonder whether we could turn on -Walloc-size for -Wall with this change?
> 
> I think that is a possibility, yes.
> 
> BTW, the patch passed bootstrap/regtest on x86_64-linux and i686-linux.
> 
>   Jakub

Anyway, thank you for fixing / improving this warning!

Martin



Re: [PATCH] c: Split -Wcalloc-transposed-args warning from -Walloc-size, -Walloc-size fixes

2023-12-18 Thread Martin Uecker
Am Montag, dem 18.12.2023 um 20:14 +0100 schrieb Jakub Jelinek:
> Hi!
> 
> The following patch changes -Walloc-size warning to no longer warn
> about int *p = calloc (1, sizeof (int));, because as discussed earlier,
> the size is IMNSHO sufficient in that case, for alloc_size with 2
> arguments warns if the product of the 2 arguments is insufficiently small.
> 
> Also, it warns also for explicit casts of malloc/calloc etc. calls
> rather than just implicit, so not just
>   int *p = malloc (1);
> but also
>   int *p = (int *) malloc (1);
> 
> It also fixes some ICEs where the code didn't verify the alloc_size
> arguments properly (Walloc-size-5.c testcase ICEs with vanilla trunk).
> 
> And lastly, it introduces a coding style warning, -Wcalloc-transposed-args
> to warn for calloc (sizeof (struct S), 1) and similar calls (regardless
> of what they are cast to, warning whenever first argument is sizeof and
> the second is not).

I would generally see function arguments that are swapped relative
to the documented ABI as more than a coding style issue even in 
cases where it can be expected to make no difference.

> 
> Ok for trunk if this passes bootstrap/regtest?

I wonder whether we could turn on -Walloc-size for -Wall with this change?


Martin


> 
> If yes, I'd implement it for C++ next.
> If not, we should at least fix the ICEs.
> 
> 2023-12-18  Jakub Jelinek  
> 
> gcc/
>   * doc/invoke.texi (-Walloc-size): Add to the list of
>   warning options, remove unnecessary line-break.
>   (-Wcalloc-transposed-args): Document new warning.
> gcc/c-family/
>   * c.opt (Wcalloc-transposed-args): New warning.
>   * c-common.h (warn_for_calloc, warn_for_alloc_size): Declare.
>   * c-warn.cc (warn_for_calloc, warn_for_alloc_size): New functions.
> gcc/c/
>   * c-parser.cc (c_parser_postfix_expression_after_primary): Grow
>   sizeof_arg and sizeof_arg_loc arrays to 6 elements.  Call
>   warn_for_calloc if warn_calloc_transposed_args for functions with
>   alloc_size type attribute with 2 arguments.
>   (c_parser_expr_list): Use 6 instead of 3.
>   * c-typeck.cc (build_c_cast): Call warn_for_alloc_size for casts
>   of calls to functions with alloc_size type attribute.
>   (convert_for_assignment): Likewise.
> gcc/testsuite/
>   * gcc.dg/Walloc-size-4.c: New test.
>   * gcc.dg/Walloc-size-5.c: New test.
>   * gcc.dg/Wcalloc-transposed-args-1.c: New test.
> 
> --- gcc/doc/invoke.texi.jj2023-12-18 09:39:49.411355496 +0100
> +++ gcc/doc/invoke.texi   2023-12-18 19:59:37.139525128 +0100
> @@ -328,7 +328,7 @@ Objective-C and Objective-C++ Dialects}.
>  -pedantic-errors -fpermissive
>  -w  -Wextra  -Wall  -Wabi=@var{n}
>  -Waddress  -Wno-address-of-packed-member  -Waggregate-return
> --Walloc-size-larger-than=@var{byte-size}  -Walloc-zero
> +-Walloc-size  -Walloc-size-larger-than=@var{byte-size}  -Walloc-zero
>  -Walloca  -Walloca-larger-than=@var{byte-size}
>  -Wno-aggressive-loop-optimizations
>  -Warith-conversion
> @@ -344,6 +344,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wc++20-compat
>  -Wno-c++11-extensions  -Wno-c++14-extensions -Wno-c++17-extensions
>  -Wno-c++20-extensions  -Wno-c++23-extensions
> +-Wcalloc-transposed-args
>  -Wcast-align  -Wcast-align=strict  -Wcast-function-type  -Wcast-qual
>  -Wchar-subscripts
>  -Wclobbered  -Wcomment
> @@ -8260,8 +8261,7 @@ Warn about calls to allocation functions
>  @code{alloc_size} that specify insufficient size for the target type of
>  the pointer the result is assigned to, including those to the built-in
>  forms of the functions @code{aligned_alloc}, @code{alloca},
> -@code{calloc},
> -@code{malloc}, and @code{realloc}.
> +@code{calloc}, @code{malloc}, and @code{realloc}.
>  
>  @opindex Wno-alloc-zero
>  @opindex Walloc-zero
> @@ -8274,6 +8274,21 @@ when called with a zero size differs amo
>  of @code{realloc} has been deprecated) relying on it may result in subtle
>  portability bugs and should be avoided.
>  
> +@opindex Wcalloc-transposed-args
> +@opindex Wno-calloc-transposed-args
> +@item -Wcalloc-transposed-args
> +Warn about calls to allocation functions decorated with attribute
> +@code{alloc_size} with two arguments, which use @code{sizeof} operator
> +as the earlier size argument and don't use it as the later size argument.
> +This is a coding style warning.  The first argument to @code{calloc} is
> +documented to be number of elements in array, while the second argument
> +is size of each element, so @code{calloc (@var{n}, sizeof (int))} is 
> preferred
> +over @code{calloc (sizeof (int), @var{n})}.  If @code{sizeof} in the earlier
> +argument and not the latter is intentional, the warning can be suppressed
> +by using @code{calloc (sizeof (struct @var{S}) + 0, n)} or
> +@code{calloc (1 * sizeof (struct @var{S}), 4)} or using @code{sizeof} in the
> +later argument as well.
> +
>  @opindex Walloc-size-larger-than=
>  @opindex Wno-alloc-size-larger-than
>  @item 

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

2023-12-17 Thread Martin Uecker



Support for constructing composite types 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.
* c-decl.cc (finish_struct): Allow NULL for
enclosing_struct_parse_info.

gcc/testsuite:
* gcc.dg/c23-tag-alias-6.c: New test.
* gcc.dg/c23-tag-composite-1.c: New test.
* gcc.dg/c23-tag-composite-2.c: New test.
* gcc.dg/c23-tag-composite-3.c: New test.
* gcc.dg/c23-tag-composite-4.c: New test.
* gcc.dg/c23-tag-composite-5.c: New test.
* gcc.dg/c23-tag-composite-6.c: New test.
* gcc.dg/c23-tag-composite-7.c: New test.
* gcc.dg/c23-tag-composite-8.c: New test.
* gcc.dg/c23-tag-composite-9.c: New test.
* gcc.dg/gnu23-tag-composite-1.c: New test.
* gcc.dg/gnu23-tag-composite-2.c: New test.
* gcc.dg/gnu23-tag-composite-3.c: New test.
* gcc.dg/gnu23-tag-composite-4.c: New test.
---
 gcc/c/c-decl.cc  |  21 +--
 gcc/c/c-typeck.cc| 137 ---
 gcc/testsuite/gcc.dg/c23-tag-alias-6.c   |  32 +
 gcc/testsuite/gcc.dg/c23-tag-composite-1.c   |  26 
 gcc/testsuite/gcc.dg/c23-tag-composite-2.c   |  16 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-3.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-4.c   |  21 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-5.c   |  25 
 gcc/testsuite/gcc.dg/c23-tag-composite-6.c   |  18 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-7.c   |  20 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-8.c   |  15 ++
 gcc/testsuite/gcc.dg/c23-tag-composite-9.c   |  19 +++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c |  45 ++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c |  30 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c |  24 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c |  28 
 16 files changed, 500 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-8.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-9.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6639ec35e5f..b72738ea04a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9674,7 +9674,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 }
 
   /* Check for consistency with previous definition.  */
-  if (flag_isoc23)
+  if (flag_isoc23 && NULL != enclosing_struct_parse_info)
 {
   tree vistype = previous_tag (t);
   if (vistype
@@ -9744,16 +9744,19 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
 
-  delete struct_parse_info;
+  if (NULL != enclosing_struct_parse_info)
+{
+  delete struct_parse_info;
 
-  struct_parse_info = enclosing_struct_parse_info;
+  struct_parse_info = enclosing_struct_parse_info;
 
-  /* If this struct is defined inside a struct, add it to
- struct_types.  */
-  if (warn_cxx_compat
-  && struct_parse_info != NULL
-  && !in_sizeof && !in_typeof && !in_alignof)
-struct_parse_info->struct_types.safe_push (t);
+  /* If this struct is defined inside a struct, add it to
+struct_types.  */
+  if (warn_cxx_compat
+ && struct_parse_info != NULL
+ && !in_sizeof && !in_typeof && !in_alignof)
+   struct_parse_info->struct_types.safe_push (t);
+ }
 
   return t;
 }
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 4d3079156ba..ac31eba6e46 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;
@@ -427,7 

[V5] [C PATCH 3/4] c23: aliasing of compatible tagged types

2023-12-17 Thread Martin Uecker



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.

The following two structs are incompatible and lvalues
with these types can be assumed not to alias:

 struct foo { int a[3]; };
 struct foo { int a[4]; };

The following two structs are also incompatible, but
will get the same TYPE_CANONICAL and it is then not
exploited that lvalues with those types can not alias:

 struct bar { int (*p)[3]; };
 struct bar { int (*p)[4]; };

The reason is that both are compatible to

 struct bar { int (*p)[]; };

and therefore are in the same equivalence class.  For
the same reason all enums with the same underyling type
are in the same equivalence class.  Tests are added
for the expected aliasing behavior with optimization.

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/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-5.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/c23-tag-alias-3.c: New test.
* gcc.dg/c23-tag-alias-4.c: New test.
* gcc.dg/c23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-1.c: New test.
* gcc.dg/gnu23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-3.c: New test.
* gcc.dg/gnu23-tag-alias-4.c: New test.
* gcc.dg/gnu23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-6.c: New test.
* gcc.dg/gnu23-tag-alias-7.c: New test.
---
 gcc/c/c-decl.cc  |  51 ++-
 gcc/c/c-objc-common.cc   |   5 ++
 gcc/c/c-tree.h   |   1 +
 gcc/c/c-typeck.cc|  31 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-5.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-alias-1.c   |  49 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-2.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-3.c   |  32 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-4.c   |  32 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-5.c   |  36 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c |  33 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c |  85 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c |  83 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c |  36 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c | 107 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c |  60 +
 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c |  93 
 18 files changed, 785 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 26188aa225e..6639ec35e5f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -634,6 +634,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;
@@ -8713,7 

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

2023-12-17 Thread Martin Uecker



Allow redefinition of enum types and enumerators.  Diagnose
nested redefinitions including redefinitions in the enum
specifier for enum types with fixed underlying type.

gcc/c:
* c-tree.h (c_parser_enum_specifier): Add parameter.
* c-decl.cc (start_enum): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.
* c-parser.cc (c_parser_enum_specifier): Remember when
seen is from an enum type which is not yet defined.

gcc/testsuide/:
* gcc.dg/c23-tag-enum-1.c: New test.
* gcc.dg/c23-tag-enum-2.c: New test.
* gcc.dg/c23-tag-enum-3.c: New test.
* gcc.dg/c23-tag-enum-4.c: New test.
* gcc.dg/c23-tag-enum-5.c: New test.
* gcc.dg/gnu23-tag-enum-1.c: Mew test.
---
 gcc/c/c-decl.cc | 65 +
 gcc/c/c-parser.cc   |  5 +-
 gcc/c/c-tree.h  |  3 +-
 gcc/c/c-typeck.cc   |  5 +-
 gcc/testsuite/gcc.dg/c23-tag-enum-1.c   | 56 +
 gcc/testsuite/gcc.dg/c23-tag-enum-2.c   | 17 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-3.c   |  7 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-4.c   | 22 +
 gcc/testsuite/gcc.dg/c23-tag-enum-5.c   | 18 +++
 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c | 19 
 10 files changed, 205 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 0e6b4a5248b..26188aa225e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2112,9 +2112,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_isoc23
+ && 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;
 }
 
@@ -3275,8 +3290,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;
@@ -9759,7 +9777,7 @@ layout_array_type (tree t)
 
 tree
 start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
-   tree fixed_underlying_type)
+   tree fixed_underlying_type, bool potential_nesting_p)
 {
   tree enumtype = NULL_TREE;
   location_t enumloc = UNKNOWN_LOCATION;
@@ -9771,9 +9789,26 @@ 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 (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
+{
+  /* If the type is currently being defined or if we have seen an
+incomplete version which is now complete, this is a nested
+redefinition.  The later happens if the redefinition occurs
+inside the enum specifier itself.  */
+  if (C_TYPE_BEING_DEFINED (enumtype)
+ || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
+   error_at (loc, "nested redefinition of %", name);
+
+  /* For C23 we allow redefinitions.  We set to zero and check for
+consistency later.  */
+  if (flag_isoc23 && 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, 

[V5] [C PATCH 1/4] c23: tag compatibility rules for struct and unions

2023-12-17 Thread Martin Uecker


Here is the revised series.  The first three patches only
have changes in the tests as well as the return value
changes.   The fourth patch was now also revised,
with changes and tests to make sure that the composite
type works correctly for bit-fields, anonymous structs/unions,
alignment, packed structs, attributes, aliasing, etc. 
It now calls finish_struct to reuse the existing code for
setting up the struct.


Bootstrapped and regression tested on x86_64.




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

gcc/c/:
* c-decl.cc (previous_tag): New function.
(parser_xref_tag): Find earlier definition.
(get_parm_info): Turn off warning for C23.
(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): Ignore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c23-enum-7.c: Remove warning.
* gcc.dg/c23-tag-1.c: New test.
* gcc.dg/c23-tag-2.c: New deactivated test.
* gcc.dg/c23-tag-3.c: New test.
* gcc.dg/c23-tag-4.c: New test.
* gcc.dg/c23-tag-5.c: New deactivated test.
* gcc.dg/c23-tag-6.c: New test.
* gcc.dg/c23-tag-7.c: New test.
* gcc.dg/c23-tag-8.c: New test.
* gcc.dg/gnu23-tag-1.c: New test.
* gcc.dg/gnu23-tag-2.c: New test.
* gcc.dg/gnu23-tag-3.c: New test.
* gcc.dg/gnu23-tag-4.c: New test.
* gcc.dg/pr112488-2.c: Remove warning.
---
 gcc/c/c-decl.cc| 72 +++---
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 38 +---
 gcc/testsuite/gcc.dg/c23-enum-7.c  |  6 +--
 gcc/testsuite/gcc.dg/c23-tag-1.c   | 67 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c   | 43 ++
 gcc/testsuite/gcc.dg/c23-tag-3.c   | 16 +++
 gcc/testsuite/gcc.dg/c23-tag-4.c   | 26 +++
 gcc/testsuite/gcc.dg/c23-tag-5.c   | 33 ++
 gcc/testsuite/gcc.dg/c23-tag-6.c   | 58 
 gcc/testsuite/gcc.dg/c23-tag-7.c   | 12 +
 gcc/testsuite/gcc.dg/c23-tag-8.c   | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-2.c | 18 
 gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 
 gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 +
 gcc/testsuite/gcc.dg/pr112488-2.c  |  2 +-
 17 files changed, 454 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 039a66fef09..0e6b4a5248b 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2037,6 +2037,28 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+
+/* Helper function.  For a tagged type, it finds the declaration
+   for a visible tag declared in the the same scope if such a
+   declaration exists.  */
+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
@@ -8573,11 +8595,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_isoc23)
+   warning_at (b->locus, 0,
+   "%<%s %E%> declared inside parameter list"
+ 

v2 [C PATCH] Fix regression causing ICE for structs with VLAs [PR 112488]

2023-12-09 Thread Martin Uecker


I revised version which fixes a problem with breaking other
callers of finish_rust. Please ignore the previous one.

Bootstrapped and regression tested on x86_64


Fix regression causing ICE for structs with VLAs [PR 112488]

A previous patch the fixed several ICEs related to size expressions
of VM types (PR c/70418, ...) caused a regression for structs where
a DECL_EXPR is not generated anymore although reqired.  We now call
add_decl_expr introduced by the previous patch from finish_struct.
The function is revised with a new argument to not set the TYPE_NAME
for the type to the DECL_EXPR in this specific case.

PR c/112488

gcc/c
* c-decl.cc (add_decl_expr): Revise.
(finish_struct): Create DECL_EXPR.
* c-parser.cc (c_parser_struct_or_union_specifier): Call
finish_struct with expression for VLA sizes.
* c-tree.h (finish_struct): Add argument.

gcc/testsuite
* gcc.dg/pr112488-1.c: New test.
* gcc.dg/pr112488-2.c: New test.
* gcc.dg/pr112898.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.
---
 gcc/c/c-decl.cc | 33 -
 gcc/c/c-parser.cc   |  2 +-
 gcc/c/c-tree.h  |  3 +-
 gcc/testsuite/gcc.dg/pr112488-1.c   | 14 +
 gcc/testsuite/gcc.dg/pr112488-2.c   | 13 
 gcc/testsuite/gcc.dg/pr112898.c |  9 ++
 gcc/testsuite/gcc.misc-tests/gcov-pr85350.c |  2 +-
 7 files changed, 65 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112898.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 92c83e1bf10..039a66fef09 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6618,12 +6618,10 @@ smallest_type_quals_location (const location_t 
*locations,
the size evaluation prior to the side effects.  We therefore
use BIND_EXPRs in TYPENAME contexts too.  */
 static void
-add_decl_expr (location_t loc, enum decl_context decl_context, tree type,
-  tree *expr)
+add_decl_expr (location_t loc, tree type, tree *expr, bool set_name_p)
 {
   tree bind = NULL_TREE;
-  if (decl_context == TYPENAME || decl_context == PARM
-  || decl_context == FIELD)
+  if (expr)
 {
   bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE,
 NULL_TREE);
@@ -6636,7 +6634,8 @@ add_decl_expr (location_t loc, enum decl_context 
decl_context, tree type,
   pushdecl (decl);
   DECL_ARTIFICIAL (decl) = 1;
   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
-  TYPE_NAME (type) = decl;
+  if (set_name_p)
+TYPE_NAME (type) = decl;
 
   if (bind)
 {
@@ -7635,7 +7634,12 @@ grokdeclarator (const struct c_declarator *declarator,
   type has a name/declaration of it's own, but special attention
   is required if the type is anonymous. */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ {
+   bool bind_p = decl_context == TYPENAME
+ || decl_context == FIELD
+ || decl_context == PARM;
+   add_decl_expr (loc, type, bind_p ? expr : NULL, true);
+ }
 
type = c_build_pointer_type (type);
 
@@ -7900,7 +7904,12 @@ grokdeclarator (const struct c_declarator *declarator,
 
/* The pointed-to type may need a decl expr (see above).  */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ {
+   bool bind_p = decl_context == TYPENAME
+ || decl_context == FIELD
+ || decl_context == PARM;
+   add_decl_expr (loc, type, bind_p ? expr : NULL, true);
+ }
 
type = c_build_pointer_type (type);
type_quals = array_ptr_quals;
@@ -9257,7 +9266,8 @@ is_flexible_array_member_p (bool is_last_field,
 
 tree
 finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
-  class c_struct_parse_info *enclosing_struct_parse_info)
+  class c_struct_parse_info *enclosing_struct_parse_info,
+  tree *expr)
 {
   tree x;
   bool toplevel = file_scope == current_scope;
@@ -9595,6 +9605,13 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   finish_incomplete_vars (incomplete_vars, toplevel);
 
+  /* Make sure a DECL_EXPR is created for structs with VLA members.
+ Because we do not know the context, we always pass expr
+ to force creation of a BIND_EXPR which is required in some
+ contexts.  */
+  if (c_type_variably_modified_p (t))
+add_decl_expr (loc, t, expr, false);
+
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct 

[C PATCH] Fix regression causing ICE for structs with VLAs [PR 112488]

2023-12-08 Thread Martin Uecker


This fixes a regression caused by my previous VM fixes.


Fix regression causing ICE for structs with VLAs [PR 112488]

A previous patch the fixed several ICEs related to size expressions
of VM types (PR c/70418, ...) caused a regression for structs where
a DECL_EXPR is not generated anymore although reqired.  We now call
add_decl_expr introduced by the previous patch from finish_struct.
The function gets a new argument to not set the TYPE_NAME for the
type to the DECL_EXPR in this spicitic case.

PR c/112488

gcc/c
* c-decl.cc (add_decl_expr): Add argument.
(finish_struct): Create DECL_EXPR.
(c_simulate_record_decl): Adapt.
* c-parser.cc (c_parser_struct_or_union_specifier): Call
finish_struct with expression for VLA sizes.
* c-tree.h (finish_struct): Add argument.

gcc/testsuite
* gcc.dg/pr112488-1.c: New test.
* gcc.dg/pr112488-2.c: New test.
* gcc.dg/pr112898.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.
---
 gcc/c/c-decl.cc | 22 +++--
 gcc/c/c-parser.cc   |  2 +-
 gcc/c/c-tree.h  |  3 ++-
 gcc/testsuite/gcc.dg/pr112488-1.c   | 14 +
 gcc/testsuite/gcc.dg/pr112488-2.c   | 13 
 gcc/testsuite/gcc.dg/pr112898.c |  9 +
 gcc/testsuite/gcc.misc-tests/gcov-pr85350.c |  2 +-
 7 files changed, 56 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112898.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 92c83e1bf10..0b500c19e70 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6619,7 +6619,7 @@ smallest_type_quals_location (const location_t *locations,
use BIND_EXPRs in TYPENAME contexts too.  */
 static void
 add_decl_expr (location_t loc, enum decl_context decl_context, tree type,
-  tree *expr)
+  tree *expr, bool set_name_p)
 {
   tree bind = NULL_TREE;
   if (decl_context == TYPENAME || decl_context == PARM
@@ -6636,7 +6636,8 @@ add_decl_expr (location_t loc, enum decl_context 
decl_context, tree type,
   pushdecl (decl);
   DECL_ARTIFICIAL (decl) = 1;
   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
-  TYPE_NAME (type) = decl;
+  if (set_name_p)
+TYPE_NAME (type) = decl;
 
   if (bind)
 {
@@ -7635,7 +7636,7 @@ grokdeclarator (const struct c_declarator *declarator,
   type has a name/declaration of it's own, but special attention
   is required if the type is anonymous. */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ add_decl_expr (loc, decl_context, type, expr, true);
 
type = c_build_pointer_type (type);
 
@@ -7900,7 +7901,7 @@ grokdeclarator (const struct c_declarator *declarator,
 
/* The pointed-to type may need a decl expr (see above).  */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ add_decl_expr (loc, decl_context, type, expr, true);
 
type = c_build_pointer_type (type);
type_quals = array_ptr_quals;
@@ -9257,7 +9258,8 @@ is_flexible_array_member_p (bool is_last_field,
 
 tree
 finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
-  class c_struct_parse_info *enclosing_struct_parse_info)
+  class c_struct_parse_info *enclosing_struct_parse_info,
+  tree *expr)
 {
   tree x;
   bool toplevel = file_scope == current_scope;
@@ -9595,6 +9597,13 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   finish_incomplete_vars (incomplete_vars, toplevel);
 
+  /* Make sure a DECL_EXPR is created for structs with VLA members.
+ Because we do not know the context, we use decl_context TYPENAME
+ here to force creation of a BIND_EXPR which is required in some
+ contexts.  */
+  if (c_type_variably_modified_p (t))
+add_decl_expr (loc, TYPENAME, t, expr, false);
+
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
 
@@ -10191,7 +10200,8 @@ c_simulate_record_decl (location_t loc, const char 
*name,
DECL_CHAIN (fields[i - 1]) = fields[i];
 }
 
-  finish_struct (loc, type, fields[0], NULL_TREE, struct_info);
+  tree expr = NULL_TREE;
+  finish_struct (loc, type, fields[0], NULL_TREE, struct_info, );
 
   tree decl = build_decl (loc, TYPE_DECL, ident, type);
   set_underlying_type (decl);
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index df9a07928b5..dcb6c21da41 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -4087,7 +4087,7 @@ c_parser_struct_or_union_specifier (c_parser *parser)
   ret.spec = finish_struct (struct_loc, type, nreverse 

Re: [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 16:01 +0100 schrieb Jakub Jelinek:
> On Wed, Dec 06, 2023 at 03:56:10PM +0100, Martin Uecker wrote:
> > > That would be my preference because then the allocation size is
> > > correct and it is purely a style warning.
> > > It doesn't follow how the warning is described:
> > > "Warn about calls to allocation functions decorated with attribute
> > > @code{alloc_size} that specify insufficient size for the target type of
> > > the pointer the result is assigned to"
> > > when the size is certainly sufficient.
> > 
> > The C standard defines the semantics of to allocate space 
> > of 'nmemb' objects of size 'size', so I would say
> > the warning and its description are correct because
> > if you call calloc with '1' as size argument but
> > the object size is larger then you specify an 
> > insufficient size for the object given the semantical
> > description of calloc in the standard.
> 
> 1 is sizeof (char), so you ask for an array of sizeof (struct ...)
> chars and store the struct into it.

If you use

char *p = calloc(sizeof(struct foo), 1);

it does not warn.

> 
> > > We have the -Wmemset-transposed-args warning, couldn't we
> > > have a similar one for calloc, and perhaps do it solely in
> > > the case where one uses sizeof of the type used in the cast
> > > pointer?
> > > So warn for
> > > (struct S *) calloc (sizeof (struct S), 1)
> > > or
> > > (struct S *) calloc (sizeof (struct S), n)
> > > but not for
> > > (struct S *) calloc (4, 15)
> > > or
> > > (struct S *) calloc (sizeof (struct T), 1)
> > > or similar?  Of course check for compatible types of TYPE_MAIN_VARIANTs.
> > 
> > Yes, although in contrast to -Wmeset-transposed-args
> > this would be considered a "style" option which then
> > nobody would activate.  And if we put it into -Wextra
> > then we have the same situation as today.
> 
> Well, the significant difference would be that users would
> know that they got the size for the allocation right, just
> that a coding style says it is better to put the type's size
> as the second argument rather than first, and they could disable
> that warning separately from -Walloc-size and still get warnings
> on (struct S *) calloc (1, 1) or (struct S *) malloc (3) if
> sizeof (struct S) is 24...

Ok. 

Note that another limitation of the current version is that it
does not warn for

... = (struct S*) calloc (...)

with the cast (which is non-idiomatic in C).  This is also
something I would like to address in the future and would be
more important for the C++ version.  But for this case it
should probably use the type of the cast and the warning
needs to be added somewhere else in the FE.


Martin



Re: [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 15:21 +0100 schrieb Jakub Jelinek:
> On Wed, Dec 06, 2023 at 02:34:10PM +0100, Martin Uecker wrote:
> > > Further I think
> > > "size less than or equal to the size requested"
> > > is quite ambiguous in the calloc case, isn't the size requested in the
> > > calloc case actually nmemb * size rather than just size?
> > 
> > This is unclear but it can be understood this way.
> > This was also Joseph's point.
> > 
> > I am happy to submit a patch that changes the code so
> > that the swapped arguments to calloc do not cause a warning
> > anymore.
> 
> That would be my preference because then the allocation size is
> correct and it is purely a style warning.
> It doesn't follow how the warning is described:
> "Warn about calls to allocation functions decorated with attribute
> @code{alloc_size} that specify insufficient size for the target type of
> the pointer the result is assigned to"
> when the size is certainly sufficient.

The C standard defines the semantics of to allocate space 
of 'nmemb' objects of size 'size', so I would say
the warning and its description are correct because
if you call calloc with '1' as size argument but
the object size is larger then you specify an 
insufficient size for the object given the semantical
description of calloc in the standard.

If this does not affect alignment, then  this should 
not matter, but it is still not really correct. 
> 
> But wonder what others think about it.
> 
> BTW, shouldn't the warning be for C++ as well?  Sure, I know,
> people use operator new more often, but still, the 
> allocators are used in there as well.

We should, but it I am not familiar with the C++ FE.

> 
> We have the -Wmemset-transposed-args warning, couldn't we
> have a similar one for calloc, and perhaps do it solely in
> the case where one uses sizeof of the type used in the cast
> pointer?
> So warn for
> (struct S *) calloc (sizeof (struct S), 1)
> or
> (struct S *) calloc (sizeof (struct S), n)
> but not for
> (struct S *) calloc (4, 15)
> or
> (struct S *) calloc (sizeof (struct T), 1)
> or similar?  Of course check for compatible types of TYPE_MAIN_VARIANTs.
> 
>   Jakub

Yes, although in contrast to -Wmeset-transposed-args
this would be considered a "style" option which then
nobody would activate.  And if we put it into -Wextra
then we have the same situation as today.

Martin





Re: [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 14:34 +0100 schrieb Martin Uecker:
> Am Mittwoch, dem 06.12.2023 um 13:57 +0100 schrieb Jakub Jelinek:
> > On Wed, Dec 06, 2023 at 08:31:12PM +0800, Xi Ruoyao wrote:
> > > On Wed, 2023-12-06 at 13:24 +0100, Jakub Jelinek wrote:
> > > > I wonder if this part isn't too pedantic or more of a code style.
> > > > Some packages fail to build with this with -Werror because they do
> > > >   struct S *p = calloc (sizeof (struct S), 1);
> > > > or similar.  It is true that calloc arguments are documented to be
> > > > nmemb, size, but given sufficient alignment (which is not really 
> > > > different
> > > > between either order of arguments) isn't it completely valid to allocate
> > > > char array with sizeof (struct S) elements and then store a struct S 
> > > > object
> > > > into it?
> > > 
> > > In PR112364 Martin Uecker has pointed out the alignment may be different
> > > with the different order of arguments, per C23 (N2293).  With earlier
> > > versions of the standard some people believe the alignment should not be
> > > different, while the other people disagree (as the text is not very
> > > clear).
> > 
> > I can understand implementations which use smaller alignment based on
> > allocation size, but are there any which consider for that just the second
> > calloc argument rather than the product of both arguments?
> 
> Not that I know of.  
> 
> > I think they'd quickly break a lot of real-world code.
> 
> There are quite a few projects which use calloc with swapped
> arguments.
> 
> > Further I think
> > "size less than or equal to the size requested"
> > is quite ambiguous in the calloc case, isn't the size requested in the
> > calloc case actually nmemb * size rather than just size?
> 
> This is unclear but it can be understood this way.
> This was also Joseph's point.
> 
> I am happy to submit a patch that changes the code so
> that the swapped arguments to calloc do not cause a warning
> anymore.
> 
> On the other hand, the only feedback I got so far was
> from people who were then happy to get this warning.

Note that it is now -Wextra.  



Re: [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 13:57 +0100 schrieb Jakub Jelinek:
> On Wed, Dec 06, 2023 at 08:31:12PM +0800, Xi Ruoyao wrote:
> > On Wed, 2023-12-06 at 13:24 +0100, Jakub Jelinek wrote:
> > > I wonder if this part isn't too pedantic or more of a code style.
> > > Some packages fail to build with this with -Werror because they do
> > >   struct S *p = calloc (sizeof (struct S), 1);
> > > or similar.  It is true that calloc arguments are documented to be
> > > nmemb, size, but given sufficient alignment (which is not really different
> > > between either order of arguments) isn't it completely valid to allocate
> > > char array with sizeof (struct S) elements and then store a struct S 
> > > object
> > > into it?
> > 
> > In PR112364 Martin Uecker has pointed out the alignment may be different
> > with the different order of arguments, per C23 (N2293).  With earlier
> > versions of the standard some people believe the alignment should not be
> > different, while the other people disagree (as the text is not very
> > clear).
> 
> I can understand implementations which use smaller alignment based on
> allocation size, but are there any which consider for that just the second
> calloc argument rather than the product of both arguments?

Not that I know of.  

> I think they'd quickly break a lot of real-world code.

There are quite a few projects which use calloc with swapped
arguments.

> Further I think
> "size less than or equal to the size requested"
> is quite ambiguous in the calloc case, isn't the size requested in the
> calloc case actually nmemb * size rather than just size?

This is unclear but it can be understood this way.
This was also Joseph's point.

I am happy to submit a patch that changes the code so
that the swapped arguments to calloc do not cause a warning
anymore.

On the other hand, the only feedback I got so far was
from people who were then happy to get this warning.

Martin






Re: [gcc15] nested functions in C

2023-12-05 Thread Martin Uecker
Am Dienstag, dem 05.12.2023 um 21:08 + schrieb Joseph Myers:
> On Mon, 4 Dec 2023, Martin Uecker wrote:
> 
> > > The key feature of lambdas (which failed to make it into C23) for this 
> > > purpose is that you can't convert them to function pointers, which 
> > > eliminates any need for trampolines.
> > 
> > And also makes them useful only for template-like macro programming,
> > but not much else. So my understanding was that this needs to be 
> > addressed at some point. 
> 
> Where "addressed" probably means some kind of callable object that stores 
> more than just a function pointer in order to be able to encapsulate both 
> the code address of a lambda and the context it needs to receive 
> implicitly.  So still not needing trampolines.

Yes, a wide function pointer type similar to C++'s std::function.

This would also be a way to eliminate the need for trampolines
for GCC's nested function.

Martin
> 



Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 19:51 +0100 schrieb Jakub Jelinek:
> On Mon, Dec 04, 2023 at 01:27:32PM -0500, Siddhesh Poyarekar wrote:
> > [Branching this into a separate conversation to avoid derailing the patch,
> > which isn't directly related]
> > 
> > On 2023-12-04 12:21, Martin Uecker wrote:
> > > I do not really agree with that.  Nested functions can substantially
> > > improve code quality and in C can avoid type unsafe use of
> > > void* pointers in callbacks. The code is often much better with
> > > nested functions than without.  Nested functions and lambdas
> > > (i.e. anonymous nested functions) are used in many languages
> > > because they make code better and GNU's nested function are no
> > > exception.
> > > 
> > > So I disagree with the idea that discouraging nested functions leads
> > > to better code - I think the exact opposite is true.
> > 
> > I would argue that GNU's nested functions *are* an exception because they're
> > like feathers stuck on a pig to try and make it fly; I think a significant
> > specification effort is required to actually make it a cleanly usable
> > feature.
> 
> Why?  The syntax doesn't seem to be something unexpected, and as C doesn't
> have lambdas, one can use the nested functions instead.
> The only problem is if you need to pass function pointers somewhere else
> (and target doesn't have function descriptors or something similar), if it
> is only done to make code more readable compared to say use of macros, I
> think the nested functions are better, one doesn't have to worry about
> multiple evaluations of argument side-effects etc.  And if everything is
> inlined and SRA optimized, there is no extra cost.
> The problem of passing it as a function pointer to other functions is
> common with C++, only lambdas which don't capture anything actually can be
> convertible to function pointer, for anything else you need a template and
> instantiate it for a particular lambda (which is something you can't do in
> C).

In C++ you can erase the type with std::function.  C is missing a 
function pointer type which can encapsulate the static chain on
all archs (not only for nested functions, also for language 
interoperability).

Martin

> 



Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 15:35 -0500 schrieb Siddhesh Poyarekar:
> On 2023-12-04 13:48, Martin Uecker wrote:
> > > I empathize with Jakub's stated use case though of keeping the C
> > > frontend support for testing purposes, but that could easily be done
> > > behind a flag, or by putting nested C func deprecation behind a flag.
> > 
> > I am relatively sure C will get some form of nested functions.
> > Maybe as anonymous nested functions, i.e. lambdas, but I do
> > not see a fundamental difference here (I personally like naming
> > things for clarity, so i prefer named nested functions)
> 
> If (assuming from them being called lambdas) they are primarily for 
> small functions without side-effects then it's already a significantly 
> stronger specification than what we have right now with C nested 
> functions.  That would end up enforcing what you demonstrate as the good 
> way to use nested functions.

The proposal we have seen for C23 (which was not accepted into
C23 mostly due to timing and lack of implementation experience)
were similar to C++'s lambdas and did not have any such restriction.

> 
> I suppose minimal, contained side-effects (such as atomically updating a 
> structure) may also constitute sound design, but that should be made 
> explicit in the language.

Updating some variable is useful for example for contractions, e.g.
summing over a certain range of values in an array, etc.

> 
> > > I don't disagree for cases like -Warray-bounds,
> > > but for warnings/errors that are more deterministic in nature (like
> > > -Werror=trampolines), they're going to point at actual problems and
> > > larger projects and distributions will usually prefer to at least track
> > > them, if not actually fix them.  For Fedora we tend to provide macro
> > > overrides for packages that need to explicitly disable a security
> > > related flag.
> > 
> > In projects such as mine, this will lead to a lot of code
> > transformations as indicated above, i.e. much worse code.
> > 
> > One could get away with it, since nested functions are rarely
> > used, but I think this is bad, because a lot of code would
> > improve if it used them.
> 
> If nested functions are eventually going to make it into the C standard 
> then effort is probably better spent in porting the C nested functions 
> to use descriptors instead of executable stacks or heaps.

I submitted a patch for this a long time ago which was based
on the code for Ada that uses a bit in the pointer to differentiate
between conventional pointers and descriptors.

I would now prefer an approach that uses a qualifier on the
function type to indicate that the static chain has to be
set. A pointer to such a qualified function would a descriptor
that consists of the address and the value for the static chain.

This would be useful for many things.

Martin







Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 21:33 + schrieb Joseph Myers:
> On Mon, 4 Dec 2023, Siddhesh Poyarekar wrote:
> 
> > On 2023-12-04 13:48, Martin Uecker wrote:
> > > > I empathize with Jakub's stated use case though of keeping the C
> > > > frontend support for testing purposes, but that could easily be done
> > > > behind a flag, or by putting nested C func deprecation behind a flag.
> > > 
> > > I am relatively sure C will get some form of nested functions.
> > > Maybe as anonymous nested functions, i.e. lambdas, but I do
> > > not see a fundamental difference here (I personally like naming
> > > things for clarity, so i prefer named nested functions)
> > 
> > If (assuming from them being called lambdas) they are primarily for small
> > functions without side-effects then it's already a significantly stronger
> > specification than what we have right now with C nested functions.  That 
> > would
> > end up enforcing what you demonstrate as the good way to use nested 
> > functions.
> 
> The key feature of lambdas (which failed to make it into C23) for this 
> purpose is that you can't convert them to function pointers, which 
> eliminates any need for trampolines.

And also makes them useful only for template-like macro programming,
but not much else. So my understanding was that this needs to be 
addressed at some point. 

Martin

> 



Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 13:27 -0500 schrieb Siddhesh Poyarekar:
> [Branching this into a separate conversation to avoid derailing the 
> patch, which isn't directly related]
> 
> On 2023-12-04 12:21, Martin Uecker wrote:
> > I do not really agree with that.  Nested functions can substantially
> > improve code quality and in C can avoid type unsafe use of
> > void* pointers in callbacks. The code is often much better with
> > nested functions than without.  Nested functions and lambdas
> > (i.e. anonymous nested functions) are used in many languages
> > because they make code better and GNU's nested function are no
> > exception.
> > 
> > So I disagree with the idea that discouraging nested functions leads
> > to better code - I think the exact opposite is true.
> 
> I would argue that GNU's nested functions *are* an exception because 
> they're like feathers stuck on a pig to try and make it fly; I think a 
> significant specification effort is required to actually make it a 
> cleanly usable feature.  It *may* be possible to implement patterns that 
> use C nested functions well enough *and* result in readable code, but 
> IMO it is easier to write clunky and unmaintainable code with it.

I use them in my code a lot and I think they improve
code quality.  For example:

int foo_find(int N, struct foo in_array[N], const char* *key)
{
  bool cond(struct foo* x)
  {
return 0 == strcmp(x->name, key); 
  }
  return find(N, in_array, cond);
}

is a lot cleaner and safer than what you need to write
without nested functions:

struct foo_find {
  const char* name;
}; 

int foo_cond(void *vdata, struct foo* a)
{
  struct foo *key = data;
  return 0 == strcmp(x->name, key->name);  
}

void foo_sort(int N, struct foo in_array[N], const char* key)
{
  struct foo_find data = { key };
  sort(N, in_array, foo_cond, );
}

and this is a toy example, the improvement gets more 
substantial with more complicated logic.

> 
> I empathize with Jakub's stated use case though of keeping the C 
> frontend support for testing purposes, but that could easily be done 
> behind a flag, or by putting nested C func deprecation behind a flag.

I am relatively sure C will get some form of nested functions.
Maybe as anonymous nested functions, i.e. lambdas, but I do
not see a fundamental difference here (I personally like naming
things for clarity, so i prefer named nested functions)

> > I am generally wary of mitigations that may make exploitation of
> > buffer overflows a bit harder  while increasing the likelihood
> > of buffer overflows by reducing type safety and/or code quality.
> > 
> > But I would agree that trampolines are generally problematic. A
> > better strategy would be wide function pointer type (as in Apple'
> > Blocks extension). Alternatively, an explicit way to obtain the
> > static chain for a nested function which could be used with
> > __builtin_call_with_static_chain  could also work.
> > 
> > But in any case, I think it diminishes the value of -fhardening
> > it if requires source code changes, because then it is not as easy
> > to simply turn it on in larger projects / distributitions.
> 
> I suppose you mean source code changes even in correct code just to 
> comply with the flag?  

Yes

> I don't disagree for cases like -Warray-bounds, 
> but for warnings/errors that are more deterministic in nature (like 
> -Werror=trampolines), they're going to point at actual problems and 
> larger projects and distributions will usually prefer to at least track 
> them, if not actually fix them.  For Fedora we tend to provide macro 
> overrides for packages that need to explicitly disable a security 
> related flag.

In projects such as mine, this will lead to a lot of code
transformations as indicated above, i.e. much worse code. 

One could get away with it, since nested functions are rarely
used, but I think this is bad, because a lot of code would
improve if it used them.

Martin

> 
> Thanks,
> Sid



Re: [PATCH] gcc: Disallow trampolines when -fhardened

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 11:46 -0500 schrieb Siddhesh Poyarekar:
> On 2023-12-04 11:39, Andreas Schwab wrote:
> > On Dez 04 2023, Siddhesh Poyarekar wrote:
> > 
> > > For hardened code in C, I think we really should look to step away from
> > > nested functions instead of adding ways to continue supporting it. There's
> > > probably a larger conversation to be had about the utility of nested
> > > functions in general for C (and whether this GCC extension should be
> > > deprecated altogether in future), but I feel like the -fhardened subset
> > > gives us the opportunity to enforce at least a safe subset for now,
> > > possibly extending it in future.
> > 
> > Nested functions by itself don't need a trampoline, only if the address
> > of it is passed outside the containing function's scope (as a callback,
> > for example).
> 
> Yes, that's why I said that the conversation about deprecating the C 
> nested functions extension is a broader one (and hence for gcc 15) that 
> will likely involve the question of whether dropping the extension 
> altogether gives any benefit or if dropping support for on-stack 
> trampolines is sufficient.  On-heap trampolines are maybe slightly 
> better in that they don't need an executable stack, but defaulting to 
> on-heap trampolines for -fhardened seems like a lost opportunity to 
> enforce better user code.

I do not really agree with that.  Nested functions can substantially
improve code quality and in C can avoid type unsafe use of
void* pointers in callbacks. The code is often much better with
nested functions than without.  Nested functions and lambdas
(i.e. anonymous nested functions) are used in many languages
because they make code better and GNU's nested function are no
exception.

So I disagree with the idea that discouraging nested functions leads 
to better code - I think the exact opposite is true.

I am generally wary of mitigations that may make exploitation of
buffer overflows a bit harder  while increasing the likelihood
of buffer overflows by reducing type safety and/or code quality.

But I would agree that trampolines are generally problematic. A
better strategy would be wide function pointer type (as in Apple'
Blocks extension). Alternatively, an explicit way to obtain the
static chain for a nested function which could be used with 
__builtin_call_with_static_chain  could also work.

But in any case, I think it diminishes the value of -fhardening 
it if requires source code changes, because then it is not as easy
to simply turn it on in larger projects / distributitions. 

Martin



> 
> Thanks,
> Sid



Re: [PATCH] gcc: Disallow trampolines when -fhardened

2023-12-02 Thread Martin Uecker


> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> It came up that a good hardening strategy is to disable trampolines
> which may require executable stack.  Therefore the following patch
> adds -Werror=trampolines to -fhardened.

This would add a warning about specific code (where it is then
unclear whether rewriting it is feasible or even an improvement),
which seems different to all the other flags -fhardening has
now.

GCC now has an option to allocate trampolines on the heap,
which would seem to be a better fit.  On the other hand,
it does not work with longjmp which may be a limitation.

Martin


> 
> gcc/ChangeLog:
> 
>   * common.opt (Wtrampolines): Enable by -fhardened.
>   * doc/invoke.texi: Reflect that -fhardened enables -Werror=trampolines.
>   * opts.cc (print_help_hardened): Add -Werror=trampolines.
>   * toplev.cc (process_options): Enable -Werror=trampolines for
>   -fhardened.
> 
> gcc/testsuite/ChangeLog:
> 
>   * gcc.dg/fhardened-1.c: New test.
>   * gcc.dg/fhardened-2.c: New test.
>   * gcc.dg/fhardened-3.c: New test.
>   * gcc.dg/fhardened-4.c: New test.
>   * gcc.dg/fhardened-5.c: New test.
> ---
>  gcc/common.opt |  2 +-
>  gcc/doc/invoke.texi|  1 +
>  gcc/opts.cc|  1 +
>  gcc/testsuite/gcc.dg/fhardened-1.c | 27 +++
>  gcc/testsuite/gcc.dg/fhardened-2.c | 25 +
>  gcc/testsuite/gcc.dg/fhardened-3.c | 25 +
>  gcc/testsuite/gcc.dg/fhardened-4.c | 25 +
>  gcc/testsuite/gcc.dg/fhardened-5.c | 27 +++
>  gcc/toplev.cc  |  8 +++-
>  9 files changed, 139 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-3.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-4.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-5.c
> 
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 161a035d736..9b09c7cb3df 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -807,7 +807,7 @@ Common Var(warn_system_headers) Warning
>  Do not suppress warnings from system headers.
>  
>  Wtrampolines
> -Common Var(warn_trampolines) Warning
> +Common Var(warn_trampolines) Warning EnabledBy(fhardened)
>  Warn whenever a trampoline is generated.
>  
>  Wtrivial-auto-var-init
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 2fab4c5d71f..c1664a1a0f1 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -17745,6 +17745,7 @@ may change between major releases of GCC, but are 
> currently:
>  -fstack-protector-strong
>  -fstack-clash-protection
>  -fcf-protection=full @r{(x86 GNU/Linux only)}
> +-Werror=trampolines
>  }
>  
>  The list of options enabled by @option{-fhardened} can be generated using
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 5d5efaf1b9e..aa062b87cef 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -2517,6 +2517,7 @@ print_help_hardened ()
>printf ("  %s\n", "-fstack-protector-strong");
>printf ("  %s\n", "-fstack-clash-protection");
>printf ("  %s\n", "-fcf-protection=full");
> +  printf ("  %s\n", "-Werror=trampolines");
>putchar ('\n');
>  }
>  
> diff --git a/gcc/testsuite/gcc.dg/fhardened-1.c 
> b/gcc/testsuite/gcc.dg/fhardened-1.c
> new file mode 100644
> index 000..8710959b6f1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fhardened-1.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-require-effective-target trampolines } */
> +/* { dg-options "-fhardened -O" } */
> +
> +static void
> +baz (int (*bar) (void))
> +{
> +  bar ();
> +}
> +
> +int
> +main (void)
> +{
> +  int a = 6;
> +
> +  int
> +  bar (void) // { dg-error "trampoline" }
> +  {
> +return a;
> +  }
> +
> +  baz (bar);
> +
> +  return 0;
> +}
> +
> +/* { dg-prune-output "some warnings being treated as errors" } */
> diff --git a/gcc/testsuite/gcc.dg/fhardened-2.c 
> b/gcc/testsuite/gcc.dg/fhardened-2.c
> new file mode 100644
> index 000..d47512aa47f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fhardened-2.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-require-effective-target trampolines } */
> +/* { dg-options "-fhardened -O -Wno-trampolines" } */
> +
> +static void
> +baz (int (*bar) (void))
> +{
> +  bar ();
> +}
> +
> +int
> +main (void)
> +{
> +  int a = 6;
> +
> +  int
> +  bar (void) // { dg-bogus "trampoline" }
> +  {
> +return a;
> +  }
> +
> +  baz (bar);
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/fhardened-3.c 
> b/gcc/testsuite/gcc.dg/fhardened-3.c
> new file mode 100644
> index 000..cebae13d8be
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fhardened-3.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */

Re: [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-28 Thread Martin Uecker
Am Dienstag, dem 28.11.2023 um 10:47 + schrieb Richard Biener:
> On Tue, 28 Nov 2023, Joseph Myers wrote:
> 
> > On Sun, 26 Nov 2023, Martin Uecker wrote:
> > 
> 

> > > > I also think more rationale is needed for ignoring sizes like this.  Is 
> > > > it 
> > > > intended for e.g. making structs with flexible array members 
> > > > alias-compatible with similar structs with a fixed-size array?
> > > 
> > > The main reason are pointers to arrays:
> > > 
> > > struct foo { int (*x)[]; }
> > > struct foo { int (*x)[2]; };
> > > struct foo { int (*x)[1]; };
> > 
> > Thanks for the explanation.
> > 
> > I guess the cases involving flexible array members actually show up a bug 
> > in the standard rather than any kind of issue with this patch - the 
> > standard allows one structure ending with a flexible array member, and 
> > another ending with a fixed-size array, to be compatible (and in different 
> > translation units allowed that even before C23), but there is also clear 
> > text in the standard showing it's not intended to require the layout to be 
> > consistent (the fixed-size and flexible arrays might have different 
> > offsets), and what you'd actually get with an assignment or conditional 
> > expression mixing such structures certainly isn't clearly specified.  
> > Maybe the right resolution for that issue with the standard would be to 
> > make that particular case incompatible, but it would need to be raised as 
> > an issue after C23 is out.
> 
> I think from a middle-end perspective it's desirable that accessing
> either of the foo with size 2 and 1 through a pointer of the type
> of the foo with unknown size is permissible from a TBAA view.  But
> it's not clear to me that accessing the foo with array size 2 via
> an lvalue of the type of foo with array size 1 is required to be
> supported (from a TBAA view).

This is the same from the C language side.  In principle, accesses 
to an object with effective type foo [2] using an lvalue of type 
foo [1] or vice versa are undefined behavior.

So a model based on equivalence classes loses some information. 

Martin



Re: [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-27 Thread Martin Uecker
Am Dienstag, dem 28.11.2023 um 01:00 + schrieb Joseph Myers:
> On Sun, 26 Nov 2023, Martin Uecker wrote:
> 
> > My understand is that it is used for aliasing analysis and also
> > checking of conversions.  TYPE_CANONICAL must be consistent with
> > the idea the middle-end has about type conversions.  But as long
> > as we do not give the same TYPE_CANONICAL to types the middle-end
> > thinks must be incompatible using its own type checking machinery,
> > it should be safe even for types the C standard thinks must be
> > incompatible for some reason.
> 
> And presumably also for types that definitely can't be assigned because 
> they have incompatible layout through the use of different array sizes - 
> since the front end won't generate such assignments, it would never matter 
> whether the middle end considers them valid without conversion or not?

Yes, for checking assignments we use the stricter language
semantics so we should never generate assignments for
structs with different fields offsets or sizes. (I will
check this again).

> > > I also think more rationale is needed for ignoring sizes like this.  Is 
> > > it 
> > > intended for e.g. making structs with flexible array members 
> > > alias-compatible with similar structs with a fixed-size array?
> > 
> > The main reason are pointers to arrays:
> > 
> > struct foo { int (*x)[]; }
> > struct foo { int (*x)[2]; };
> > struct foo { int (*x)[1]; };
> 
> Thanks for the explanation.
> 
> I guess the cases involving flexible array members actually show up a bug 
> in the standard rather than any kind of issue with this patch - the 
> standard allows one structure ending with a flexible array member, and 
> another ending with a fixed-size array, to be compatible (and in different 
> translation units allowed that even before C23), but there is also clear 
> text in the standard showing it's not intended to require the layout to be 
> consistent (the fixed-size and flexible arrays might have different 
> offsets), and what you'd actually get with an assignment or conditional 
> expression mixing such structures certainly isn't clearly specified.  

I agree, unfortunately it seems not well specified and we somehow missed 
that this now becomes more important.

> Maybe the right resolution for that issue with the standard would be to 
> make that particular case incompatible, but it would need to be raised as 
> an issue after C23 is out.

I think FAM may need further consideration from the standard
point of view for also other reasons.

My other issues I have now run into are structs with variably size
which I think do not work properly with LTO already today:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112716



Martin

> 






Re: Ping: [PATCH] Fix PR112419

2023-11-27 Thread Martin Uecker
Am Montag, dem 27.11.2023 um 16:54 +0100 schrieb Martin Uecker:
> Am Montag, dem 27.11.2023 um 08:36 -0700 schrieb Jeff Law:
> > 
> > On 11/23/23 10:05, Hans-Peter Nilsson wrote:
> > > > From: Hans-Peter Nilsson 
> > > > Date: Thu, 16 Nov 2023 05:24:06 +0100
> > > > 
> > > > > From: Martin Uecker 
> > > > > Date: Tue, 07 Nov 2023 06:56:25 +0100
> > > > 
> > > > > Am Montag, dem 06.11.2023 um 21:01 -0700 schrieb Jeff Law:
> > > > > > 
> > > > > > On 11/6/23 20:58, Hans-Peter Nilsson wrote:
> > > > > > > This patch caused a testsuite regression: there's now an
> > > > > > > "excess error" failure for gcc.dg/Wnonnull-4.c for 32-bit
> > > > > > > targets (and 64-bit targets testing with a "-m32" option)
> > > > > > > after your r14-5115-g6e9ee44d96e5.  It's logged as PR112419.
> > > > > > It caused failures for just about every target ;(  Presumably it 
> > > > > > worked
> > > > > > on x86_64...
> > > > > 
> > > > > I do not think this is a true regression
> > > > > just a problem with the test on 32-bit which somehow surfaced
> > > > > due to the change.
> > > > > 
> > > > > The excess error is:
> > > > > 
> > > > > FAIL: gcc.dg/Wnonnull-4.c (test for excess errors)
> > > > > Excess errors:
> > > > > /home/tcwg-buildslave/workspace/tcwg_gnu_6/abe/snapshots/gcc.git~master/gcc/testsuite/gcc.dg/Wnonnull-4.c:144:3:
> > > > >  warning: 'fda_n_5' specified size 4294967256 exceeds maximum object 
> > > > > size
> > > > > 2147483647 [-Wstringop-overflow=]
> > > > > 
> > > > > I think the warning was suppressed before due to the other (nonnull)
> > > > > warning which I removed in this case.
> > > > > 
> > > > > I think the simple fix might be to to turn off -Wstringop-overflow.
> > > > 
> > > > No, that trigs many of the dg-warnings that are tested.
> > > > 
> > > > (I didn't pay attention to the actual warning messages and
> > > > tried to pursue that at first.)
> > > > 
> > > > Maybe think it's best to actually expect the warning, like
> > > > so.
> > > > 
> > > > Maintainers of 16-bit targets will have to address their
> > > > concerns separately.  For example, they may choose to not
> > > > run the test at all.
> > > > 
> > > > Ok to commit?
> > > > 
> > > > Subject: [PATCH] gcc.dg/Wnonnull-4.c: Handle new overflow warning for 
> > > > 32-bit targets [PR112419]
> > > > 
> > > > PR testsuite/112419
> > > > * gcc.dg/Wnonnull-4.c (test_fda_n_5): Expect warning for 
> > > > exceeding
> > > > maximum object size for 32-bit targets.
> > > > ---
> > > >   gcc/testsuite/gcc.dg/Wnonnull-4.c | 1 +
> > > >   1 file changed, 1 insertion(+)
> > > > 
> > > > diff --git a/gcc/testsuite/gcc.dg/Wnonnull-4.c 
> > > > b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > > index 1f14fbba45df..d63e76da70a2 100644
> > > > --- a/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > > +++ b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > > @@ -142,6 +142,7 @@ void test_fda_n_5 (int r_m1)
> > > > T (  1);  // { dg-bogus "argument 2 of variable length 
> > > > array 'double\\\[n]\\\[5]' is null but the corresponding bound argument 
> > > > 1 value is 1" }
> > > > T (  9);  // { dg-bogus "argument 2 of variable length 
> > > > array 'double\\\[n]\\\[5]' is null but the corresponding bound argument 
> > > > 1 value is 9" }
> > > > T (max);  // { dg-bogus "argument 2 of variable length 
> > > > array 'double\\\[n]\\\[5]' is null but the corresponding bound argument 
> > > > 1 value is \\d+" }
> > > > +// { dg-warning "size 4294967256 exceeds maximum object size" "" { 
> > > > target ilp32 } .-1 }
> > > >   }
> > Unfortunately I think we need to go back to the original issue that 
> > Martin (I think) dismissed.
> > 
> > Specifically, this is a regression.  It's very clear that prior to the 
> > patch in question there was no diagnostic about the size of the 
> > requested memory allocation and after the patch in question we get the 
> > "exceeds maximum object size" diagnostic.
> > 
> > Now one explanation could be that the diagnostic is warranted and it was 
> > a bug that the diagnostic hadn't been emitted prior to Martin's patch. 
> > In this case some kind of dg-blah is warranted, but I don't think anyone 
> > has made this argument.
> > 
> I believe the warning is correct but was suppressed before.
> 
> 
> My plan was to split up the test case in one which is for
> -Wstringop-overflow and one which is for -Wnonnull and then
> one could turn off the -Wstringop-overflow for the tests
> which are actually for -Wnonnull.  But adding the dg-blah
> would certainly be simpler.

Specifically, also with 13.2 if you suppress the warning which
I removed with -Wno-nonnull you will get the otherwise hidden
-Wstringop-overflow warning with -m32:

See here: https://godbolt.org/z/ev5GhMonq

The warning also seems correct to me, so I suggest to accept
the proposed patch. 

Martin






Re: Ping: [PATCH] Fix PR112419

2023-11-27 Thread Martin Uecker
Am Montag, dem 27.11.2023 um 08:36 -0700 schrieb Jeff Law:
> 
> On 11/23/23 10:05, Hans-Peter Nilsson wrote:
> > > From: Hans-Peter Nilsson 
> > > Date: Thu, 16 Nov 2023 05:24:06 +0100
> > > 
> > > > From: Martin Uecker 
> > > > Date: Tue, 07 Nov 2023 06:56:25 +0100
> > > 
> > > > Am Montag, dem 06.11.2023 um 21:01 -0700 schrieb Jeff Law:
> > > > > 
> > > > > On 11/6/23 20:58, Hans-Peter Nilsson wrote:
> > > > > > This patch caused a testsuite regression: there's now an
> > > > > > "excess error" failure for gcc.dg/Wnonnull-4.c for 32-bit
> > > > > > targets (and 64-bit targets testing with a "-m32" option)
> > > > > > after your r14-5115-g6e9ee44d96e5.  It's logged as PR112419.
> > > > > It caused failures for just about every target ;(  Presumably it 
> > > > > worked
> > > > > on x86_64...
> > > > 
> > > > I do not think this is a true regression
> > > > just a problem with the test on 32-bit which somehow surfaced
> > > > due to the change.
> > > > 
> > > > The excess error is:
> > > > 
> > > > FAIL: gcc.dg/Wnonnull-4.c (test for excess errors)
> > > > Excess errors:
> > > > /home/tcwg-buildslave/workspace/tcwg_gnu_6/abe/snapshots/gcc.git~master/gcc/testsuite/gcc.dg/Wnonnull-4.c:144:3:
> > > >  warning: 'fda_n_5' specified size 4294967256 exceeds maximum object 
> > > > size
> > > > 2147483647 [-Wstringop-overflow=]
> > > > 
> > > > I think the warning was suppressed before due to the other (nonnull)
> > > > warning which I removed in this case.
> > > > 
> > > > I think the simple fix might be to to turn off -Wstringop-overflow.
> > > 
> > > No, that trigs many of the dg-warnings that are tested.
> > > 
> > > (I didn't pay attention to the actual warning messages and
> > > tried to pursue that at first.)
> > > 
> > > Maybe think it's best to actually expect the warning, like
> > > so.
> > > 
> > > Maintainers of 16-bit targets will have to address their
> > > concerns separately.  For example, they may choose to not
> > > run the test at all.
> > > 
> > > Ok to commit?
> > > 
> > > Subject: [PATCH] gcc.dg/Wnonnull-4.c: Handle new overflow warning for 
> > > 32-bit targets [PR112419]
> > > 
> > >   PR testsuite/112419
> > >   * gcc.dg/Wnonnull-4.c (test_fda_n_5): Expect warning for exceeding
> > >   maximum object size for 32-bit targets.
> > > ---
> > >   gcc/testsuite/gcc.dg/Wnonnull-4.c | 1 +
> > >   1 file changed, 1 insertion(+)
> > > 
> > > diff --git a/gcc/testsuite/gcc.dg/Wnonnull-4.c 
> > > b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > index 1f14fbba45df..d63e76da70a2 100644
> > > --- a/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > +++ b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > @@ -142,6 +142,7 @@ void test_fda_n_5 (int r_m1)
> > > T (  1);  // { dg-bogus "argument 2 of variable length array 
> > > 'double\\\[n]\\\[5]' is null but the corresponding bound argument 1 value 
> > > is 1" }
> > > T (  9);  // { dg-bogus "argument 2 of variable length array 
> > > 'double\\\[n]\\\[5]' is null but the corresponding bound argument 1 value 
> > > is 9" }
> > > T (max);  // { dg-bogus "argument 2 of variable length array 
> > > 'double\\\[n]\\\[5]' is null but the corresponding bound argument 1 value 
> > > is \\d+" }
> > > +// { dg-warning "size 4294967256 exceeds maximum object size" "" { 
> > > target ilp32 } .-1 }
> > >   }
> Unfortunately I think we need to go back to the original issue that 
> Martin (I think) dismissed.
> 
> Specifically, this is a regression.  It's very clear that prior to the 
> patch in question there was no diagnostic about the size of the 
> requested memory allocation and after the patch in question we get the 
> "exceeds maximum object size" diagnostic.
> 
> Now one explanation could be that the diagnostic is warranted and it was 
> a bug that the diagnostic hadn't been emitted prior to Martin's patch. 
> In this case some kind of dg-blah is warranted, but I don't think anyone 
> has made this argument.
> 
I believe the warning is correct but was suppressed before.


My plan was to split up the test case in one which is for
-Wstringop-overflow and one which is for -Wnonnull and then
one could turn off the -Wstringop-overflow for the tests
which are actually for -Wnonnull.  But adding the dg-blah
would certainly be simpler.


Martin





[V4] [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-27 Thread Martin Uecker


(this mostly got an extended description and more
comments, also tests were reorganized)



c23: aliasing of compatible tagged types

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.

The following two structs are incompatible and lvalues
with these types can be assumed not to alias:

 struct foo { int a[3]; };
 struct foo { int a[4]; };

The following two structs are also incompatible, but
will get the same TYPE_CANONICAL and it is then not
exploited that lvalues with those types can not alias:

 struct bar { int (*p)[3]; };
 struct bar { int (*p)[4]; };

The reason is that both are compatible to

 struct bar { int (*p)[]; };

and therefore are in the same equivalence class.  For
the same reason all enums with the same underyling type
are in the same equivalence class.  Tests are added
for the expected aliasing behavior with optimization.

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/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-6.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-1.c: New test.
* gcc.dg/gnu23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-3.c: New test.
* gcc.dg/gnu23-tag-alias-4.c: New test.
* gcc.dg/gnu23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-6.c: New test.
* gcc.dg/gnu23-tag-alias-7.c: New test.
---
 gcc/c/c-decl.cc  |  51 ++-
 gcc/c/c-objc-common.cc   |   5 ++
 gcc/c/c-tree.h   |   1 +
 gcc/c/c-typeck.cc|  31 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-5.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-alias-1.c   |  49 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-2.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-3.c   |  32 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-4.c   |  54 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c |  33 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c |  85 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c |  83 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c |  36 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c | 107 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c |  60 +
 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c |  93 
 17 files changed, 771 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index bcc09ba479e..68cba131704 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -634,6 +634,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;
@@ -8713,7 +8743,8 @@ parser_xref_tag (location_t loc, enum tree_code code, 
tree name,
   ref = lookup_tag (code, name, 

[V4] [PATCH 4/4] c23: construct composite type for tagged types

2023-11-27 Thread Martin Uecker


(this patch was still not updated and needs more work, so
only included now for completeness) 


c23: construct composite type for tagged types

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

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 00eb65dbcce..7901368c9fd 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;
@@ -427,7 +434,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);
@@ -435,7 +443,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);
@@ -503,9 +512,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_isoc23 && !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.  */
@@ -520,7 +581,8 @@ composite_type (tree t1, tree t2)
   /* Function types: prefer the one that specified arg types.

[V4] [PATCH 2/4] c23: tag compatibility rules for enums

2023-11-27 Thread Martin Uecker


(only tests were changed)


c23: tag compatibility rules for enums

Allow redefinition of enum types and enumerators.  Diagnose
nested redefinitions including redefinitions in the enum
specifier for enum types with fixed underlying type.

gcc/c:
* c-tree.h (c_parser_enum_specifier): Add parameter.
* c-decl.cc (start_enum): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.
* c-parser.cc (c_parser_enum_specifier): Remember when
seen is from an enum type which is not yet defined.

gcc/testsuide/:
* gcc.dg/c23-tag-enum-1.c: New test.
* gcc.dg/c23-tag-enum-2.c: New test.
* gcc.dg/c23-tag-enum-3.c: New test.
* gcc.dg/c23-tag-enum-4.c: New test.
* gcc.dg/c23-tag-enum-5.c: New test.
* gcc.dg/gnu23-tag-enum-1.c: Mew test.
---
 gcc/c/c-decl.cc | 65 +
 gcc/c/c-parser.cc   |  5 +-
 gcc/c/c-tree.h  |  3 +-
 gcc/c/c-typeck.cc   |  5 +-
 gcc/testsuite/gcc.dg/c23-tag-enum-1.c   | 56 +
 gcc/testsuite/gcc.dg/c23-tag-enum-2.c   | 17 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-3.c   |  7 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-4.c   | 22 +
 gcc/testsuite/gcc.dg/c23-tag-enum-5.c   | 18 +++
 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c | 19 
 10 files changed, 205 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index ebe1708b977..bcc09ba479e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2114,9 +2114,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_isoc23
+ && 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;
 }
 
@@ -3277,8 +3292,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;
@@ -9747,7 +9765,7 @@ layout_array_type (tree t)
 
 tree
 start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
-   tree fixed_underlying_type)
+   tree fixed_underlying_type, bool potential_nesting_p)
 {
   tree enumtype = NULL_TREE;
   location_t enumloc = UNKNOWN_LOCATION;
@@ -9759,9 +9777,26 @@ 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 (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
+{
+  /* If the type is currently being defined or if we have seen an
+incomplete version which is now complete, this is a nested
+redefinition.  The later happens if the redefinition occurs
+inside the enum specifier itself.  */
+  if (C_TYPE_BEING_DEFINED (enumtype)
+ || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
+   error_at (loc, "nested redefinition of %", name);
+
+  /* For C23 we allow redefinitions.  We set to zero and check for
+consistency later.  */
+  if (flag_isoc23 && TYPE_VALUES (enumtype) != NULL_TREE)
+   enumtype = NULL_TREE;
+}
+
   if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
 {
   enumtype = make_node 

[V4] [C PATCH 1/4] c23: tag compatibility rules for struct and unions

2023-11-27 Thread Martin Uecker


Note that there is an additional change in parser_xref_tag
to address the issue regarding completeness in redefinition
which affects also structs / unions.  The test c23-tag-6.c
was changed accordingly.


c23: tag compatibility rules for struct and unions

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

gcc/c/:
* c-decl.cc (previous_tag): New function.
(parser_xref_tag): Find earlier definition.
(get_parm_info): Turn off warning for C23.
(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): Ignore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c23-enum-7.c: Remove warning.
* gcc.dg/c23-tag-1.c: New test.
* gcc.dg/c23-tag-2.c: New deactivated test.
* gcc.dg/c23-tag-3.c: New test.
* gcc.dg/c23-tag-4.c: New test.
* gcc.dg/c23-tag-5.c: New deactivated test.
* gcc.dg/c23-tag-6.c: New test.
* gcc.dg/c23-tag-7.c: New test.
* gcc.dg/c23-tag-8.c: New test.
* gcc.dg/gnu23-tag-1.c: New test.
* gcc.dg/gnu23-tag-2.c: New test.
* gcc.dg/gnu23-tag-3.c: New test.
* gcc.dg/gnu23-tag-4.c: New test.
---
 gcc/c/c-decl.cc| 72 +++---
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 38 +---
 gcc/testsuite/gcc.dg/c23-enum-7.c  |  6 +--
 gcc/testsuite/gcc.dg/c23-tag-1.c   | 67 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c   | 43 ++
 gcc/testsuite/gcc.dg/c23-tag-3.c   | 16 +++
 gcc/testsuite/gcc.dg/c23-tag-4.c   | 26 +++
 gcc/testsuite/gcc.dg/c23-tag-5.c   | 33 ++
 gcc/testsuite/gcc.dg/c23-tag-6.c   | 58 
 gcc/testsuite/gcc.dg/c23-tag-7.c   | 12 +
 gcc/testsuite/gcc.dg/c23-tag-8.c   | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-2.c | 19 
 gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 
 gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 +
 16 files changed, 454 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64d3a941cb9..ebe1708b977 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2039,6 +2039,28 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+
+/* Helper function.  For a tagged type, it finds the declaration
+   for a visible tag declared in the the same scope if such a
+   declaration exists.  */
+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
@@ -8573,11 +8595,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_isoc23)
+   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,
@@ -8668,6 +8693,16 

Re: [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-26 Thread Martin Uecker


Thanks Joseph, I will sent an updated series tomorrow. 

Richard, maybe you could look at what I wrote below
about my use of TYPE_CANONICAL ?  Does this make sense?


Am Donnerstag, dem 23.11.2023 um 23:47 + schrieb Joseph Myers:
> On Thu, 16 Nov 2023, Martin Uecker wrote:
> 
> > 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.
> 
> Is TYPE_CANONICAL *only* used for alias analysis?  It's not obvious to me 
> that setting TYPE_CANONICAL to a type that's definitely not equivalent for 
> other purposes is necessarily safe.

My understand is that it is used for aliasing analysis and also
checking of conversions.  TYPE_CANONICAL must be consistent with
the idea the middle-end has about type conversions.  But as long
as we do not give the same TYPE_CANONICAL to types the middle-end
thinks must be incompatible using its own type checking machinery,
it should be safe even for types the C standard thinks must be
incompatible for some reason.

> I also think more rationale is needed for ignoring sizes like this.  Is it 
> intended for e.g. making structs with flexible array members 
> alias-compatible with similar structs with a fixed-size array?

The main reason are pointers to arrays:

struct foo { int (*x)[]; }
struct foo { int (*x)[2]; };
struct foo { int (*x)[1]; };

So at least when putting it in terms of equivalence classes,
one has no choice than making those types equivalent. So
all those would get the same TYPE_CANONICAL. The middle-end 
does not care about the different pointer types (in
useless_type_conversion_p or
gimple_canonical_types_compatible_p).


Martin




> 
> > @@ -1250,6 +1266,9 @@ comptypes_internal (const_tree type1, const_tree 
> > type2,
> >  
> > if ((d1 == NULL_TREE) != (d2 == NULL_TREE))
> >   data->different_types_p = true;
> > +   /* ignore size mismatches */
> > +   if (data->equiv)
> > + return 1;
> 
> Should start comment with capital letter, end with '.'.
> 
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-2.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-2.c
> > index 5dd4a21e9df..e28c2b5eea2 100644
> > --- a/gcc/testsuite/gcc.dg/c23-tag-2.c
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-2.c
> > @@ -1,5 +1,5 @@
> > -/* { dg-do compile { target { ! "*-*-*" } } }
> > - * { dg-options "-std=c23" }
> > +/* { dg-do compile }
> > + * { dg-options "-std=c2x" }
> >   */
> >  
> >  // compatibility of structs in assignment
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-5.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-5.c
> > index ff40d07aef1..95a04bf9b0e 100644
> > --- a/gcc/testsuite/gcc.dg/c23-tag-5.c
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-5.c
> > @@ -1,5 +1,6 @@
> > -/* { dg-do run { target { ! "*-*-*" } } }
> > - * { dg-options "-std=c23" }
> > +/*
> > + * { dg-do run }
> > + * { dg-options "-std=c2x" }
> 
> These tests should not be changed to use -std=c2x.
> 
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-2.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-alias-2.c
> > new file mode 100644
> > index 000..555c30a8501
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-2.c
> > @@ -0,0 +1,73 @@
> > +/*
> > + * { dg-do run }
> > + * { dg-options "-std=c23 -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 main()
> > +{
> > +   struct foo y;
> > +
> > +   if (1 != test_foo1(, ))
> > +   __builtin_abort();
> 
> This test appears to be testing various invalid cases - testing that the 
> compiler does not consider aliasing to occur in those cases (even though 
> in fact there is aliasing).
> 
> If that's the intent of this test, it definitely needs commenting.  The 
> test would also need to (be a gnu23-* test and) use appropriate attributes 
> to disable interprocedural analysis, since it would be entirely valid for 
> the compiler in this test to inline test_foo1, see that p->x in fact 
> points to the same location as a->x despite the incompatible types, and 
> have the function return 2.
> 
> The same applies to c23-tag-alias-4.c and c23-tag-alias-5.c.
> 
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-5.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-alias-5.c
> > new file mode 100644
> > index 000..4e956720143
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-5.c
> > @@ -0,0 +1,30 @@
> > +/* { dg-do run }
> > + * { dg-options "-std=c23 -O2" }
> > + */
> > +
> > +// not sure this is wise, but this was already like thi sbefore
> 
> "this before"
> 



Re: [PATCH] c-family, middle-end: Add __builtin_c[lt]zg (arg, 0ULL) exception

2023-11-20 Thread Martin Uecker


(corrected address)


> On Mon, 20 Nov 2023, Jakub Jelinek wrote:
> 
> > On Mon, Nov 20, 2023 at 08:37:55AM +, Richard Biener wrote:
> > > > I'm not sure about that, it would be nice for them to be usable there,
> > > 
> > > Btw, I think that {( .. )} should be made usable in sizeof () and
> > > possibly even in at least C++ constant expressions (not sure about C).
> > 
> > I believe the problkem is having new VAR_DECLs in those which actually
> > aren't file scope/namespace scope variables but there is no function
> > DECL_CONTEXT to attach to them.  So, it probably wouldn't be one afternoon
> > change to allow that.

There is an open bug about this:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93239

But the required feature is simpler than full statement 
expression, essentially

let x = y in z

where x is an identifier and y and z are expression, and
this should be much easier to implement.

I thought about an extension to _Generic which would be
useful here:

_GNU_Generic(y, int x1: z1, float x2: z2)

or even

_GNU_Generic(y, default x: z)

which would be useful in general.


> > 
> > > > but I think e.g. none of Joseph's implementation of those macros
> > > > made them usable there (except inside of sizeof/typeof/typeof_unquall)
> > > > and I don't see a requirement in the C23 standard that they must be 
> > > > usable
> > > > in constant expressions.
> > > > The versions I've posted on Thursday were usable there except for
> > > > stdc_has_single_bit (but that actually can be implemented that way too)
> > > > and stdc_bit_floor.  And the version I haven't posted that used the 3
> > > > patches posted on Saturday would have all functions usable when the
> > > > argument to those macros is a constant expression.
> > > > 
> > > > BTW, if we go route of implementing all of the stdc_ type-generic macros
> > > > as builtins, we could as well not implement that way the following 4
> > > > # define stdc_first_leading_one(x) (__builtin_clzg (x, -1) + 1U)
> > > > # define stdc_first_trailing_one(x) (__builtin_ctzg (x, -1) + 1U)
> > > > # define stdc_count_ones(x) ((unsigned int) __builtin_popcountg (x))
> > > > # define stdc_has_single_bit(x) ((_Bool) (__builtin_popcountg (x) == 1))
> > > > which are implementable without any new extensions.
> > > 
> > > I'd rather do all of those necessary as builtins instead of hacking
> > > around limitations.  If we don't want to solve those limitations in
> > > a more generic way.
> > 
> > Ok, I can prepare a patch for that, shouldn't be that hard.
> > Do you want all 14, or just the 10 and leave the above 4 with the
> > above definitions?
> 
> I'd say all of them for consistency, we can parse/gimplify them to
> the open-coded variants then.

For use of _Generic with _BitInt one would need some kind
of _BitInt_Width(x) macro/builtin that returns the width as an
constant expressions, which would also be useful in general.

Then one could write:

_Generic(x, int a: foo, _BitInt(_BitInt_Width(x)): bar);

With this and an extension as suggested above, I think one could
solve this in a generic way.

Martin

> > > And of course nobody would write
> > > 
> > > const int x = sizeof (stdc_first_leading_one (5));
> > > 
> > > that's just stupid ... (but oh well).
> > 
> > Well, standard testsuite needs to include that at least.
> > But of course, if it is usable in constant expressions,
> > unsigned a = stdc_bit_width ((unsigned _BitInt(824)) 
> > 435987349856735489657489657468954768954674589674598uwb * 
> > 49876558967549867548967548967548967549867548967456uwb);
> > etc. can be useful in constant expressions.


> > 
> > Jakub
> > 
> > 



[PATCH 4/4] c: runtime checking for assigment of VM types 4/4

2023-11-18 Thread Martin Uecker



Add warning for the case when a function call can not be instrumened.

gcc/c-family/:
* c.opt (Wvla-parameter-missing-check): Add warning.

gcc/c/:
* c-typeck.cc (process_vm_constraints): Add warning.

gcc/doc/:
* invoke.texi (Wvla-parameter-missing-check): Document warning.
(flag_vla_bounds): Update.

gcc/testsuite/:
* gcc.dg/vla-bounds-func-1.c: Add warning.
---
 gcc/c-family/c.opt   |  5 +
 gcc/c/c-typeck.cc|  4 
 gcc/doc/invoke.texi  | 11 ---
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c |  6 +++---
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 29bc0956181..bd45ba577bd 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1485,6 +1485,11 @@ Wvla-parameter
 C ObjC C++ ObjC++ Var(warn_vla_parameter) Warning LangEnabledBy(C ObjC C++ 
ObjC++,Wall)
 Warn about mismatched declarations of VLA parameters.
 
+Wvla-parameter-missing-check
+C ObjC Var(warn_vla_parameter_check) Warning Init(0)
+When using run-time checking of VLA bounds, warn about function calls which
+could not be instrumented.
+
 Wvolatile
 C++ ObjC++ Var(warn_volatile) Warning
 Warn about deprecated uses of volatile qualifier.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1200abc2f4a..a4fb0a6b527 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3481,6 +3481,8 @@ process_vm_constraints (location_t location,
{
  /* FIXME: this can happen when forming composite types for the
 conditional operator.  */
+ warning_at (location, OPT_Wvla_parameter_missing_check,
+ "Function call not instrumented");
  return void_node;
}
}
@@ -3564,6 +3566,8 @@ process_vm_constraints (location_t location,
  also not instrument any of the others because it may have
  side effects affecting them.  (We could restart and instrument
  only the ones with integer constants.)   */
+   warning_at (location, OPT_Wvla_parameter_missing_check,
+   "Function call not instrumented");
return void_node;
}
 cont:
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c94ca59086b..6f4bbd43919 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10269,6 +10269,7 @@ void g (int n)
 @option{-Warray-parameter} option triggers warnings for similar problems
 involving ordinary array arguments.
 
+
 @opindex Wvla-parameter-missing-check
 @item -Wvla-parameter-missing-check
 Warn when function calls can not be instrumented with the use of
@@ -20063,9 +20064,13 @@ The @var{string} should be different for every file 
you compile.
 @item -fvla-bounds
 This option is only available when compiling C code.  If activated,
 additional code is emitted that verifies at run time for assignments
-involving variably-modified types that corresponding size expressions
-evaluate to the same value.
-
+and function calls involving variably-modified types that corresponding
+size expressions evaluate to the same value.  Note that for function
+calls the visible declarations needs to have a size expression that
+matches the size expression in the definition.  A mismatch seen by the
+the compiler is diagnosed by @option{-Wvla-parameter}). In same cases,
+a function call can not be instrumented.  This can be diagnosed by
+@option{-Wvla-parameter-missing-check}.
 
 @opindex save-temps
 @item -save-temps
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c 
b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
index 72dba39107b..205e5174185 100644
--- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fvla-bounds" } */
+/* { dg-options "-fvla-bounds -Wvla-parameter-missing-check" } */
 
 // make sure we do not ICE on any of these
 
@@ -31,7 +31,7 @@ void f(void)
 
int u = 3; int v = 4;
char a[u][v];
-   (1 ? f1 : f2)(u, v, a); /* "Function call not instrumented." */
+   (1 ? f1 : f2)(u, v, a); /* { dg-warning "Function call" "not 
instrumented." } */
 }
 
 /* size expression in parameter */
@@ -51,6 +51,6 @@ int c(int u, char (*a)[u]) { }
 int d(void)
 {
char a[3];
-   c(3, );   /* "Function call not instrumented." */
+   c(3, );   /* { dg-warning "Function call" "not 
instrumented." } */
 }
 
-- 
2.39.2




[PATCH 3/4] c: runtime checking for assigment of VM types 3/4

2023-11-18 Thread Martin Uecker



Support instrumentation of functions called via pointers.  To do so,
record the declaration with the parameter types, so that it can be
retrieved later.

gcc/c:
c-decl.cc (get_parm_info): Record function declaration
for arguments.
c-typeck.cc (process_vm_constraints): Instrument functions
called via pointers.

gcc/testsuide/gcc.dg:
* vla-bounds-func-1.c: Add warning.
* vla-bounds-fnptr.c: New test.
* vla-bounds-fnptr-1.c: New test.
* vla-bounds-fnptr-2.c: New test.
* vla-bounds-fnptr-3.c: New test.
* vla-bounds-fnptr-4.c: New test.
* vla-bounds-fnptr-5.c: New test.
---
 gcc/c/c-decl.cc   |  4 ++
 gcc/c/c-typeck.cc | 14 +++-
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr.c   | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c  |  2 +-
 9 files changed, 485 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64d3a941cb9..84a30f7476a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8549,6 +8549,10 @@ get_parm_info (bool ellipsis, tree expr)
 declared types.  The back end may override this later.  */
  DECL_ARG_TYPE (decl) = type;
  types = tree_cons (0, type, types);
+
+ /* Record the decl for use for VLA bounds checking.  */
+ if (flag_vla_bounds)
+   TREE_PURPOSE (types) = decl;
}
  break;
 
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index b65fc450940..1200abc2f4a 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3472,9 +3472,19 @@ process_vm_constraints (location_t location,
}
   else
{
- /* Functions called via pointers are not yet supported.  */
- return void_node;
+ while (FUNCTION_TYPE != TREE_CODE (function))
+   function = TREE_TYPE (function);
+
+ args = TREE_PURPOSE (TYPE_ARG_TYPES (function));
+
+ if (!args)
+   {
+ /* FIXME: this can happen when forming composite types for the
+conditional operator.  */
+ return void_node;
+   }
}
+  gcc_assert (PARM_DECL == TREE_CODE (args));
 }
 
   for (struct instrument_data* d = *instr_vec; d; d = d->next)
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c 
b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c
new file mode 100644
index 000..b9af87f6338
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c
@@ -0,0 +1,78 @@
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include 
+#include 
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+
+
+void foo1(void (*p)(int n, char (*a)[n]))
+{
+   char A0[3];
+   (*p)(3, );
+TRY(   (*p)(4, ); ) // 4 != 3
+}
+
+void b0(int n, char (*a)[n]) { }
+
+
+int n;
+
+void foo2(void (*p)(int n, char (*a)[n]))
+{
+   n = 4;
+   char A0[3];
+   (*p)(3, );
+ERROR( (*p)(4, ); ) // 4 != 3
+}
+
+void foo3(void (*p)(int n0, char (*a)[n]))
+{
+   n = 4;
+   char A0[3];
+ERROR( (*p)(3, ); ) // 4 != 3
+ERROR( (*p)(4, ); ) // 4 != 3 
+}
+
+void foo4(void (*p)(int n, char (*a)[n]))
+{
+   n = 3;
+   char A0[3];
+   (*p)(3, );
+ERROR( (*p)(4, ); ) // 4 != 3
+}
+
+
+void foo5(void (*p)(int n0, char (*a)[n]))
+{
+   n = 3;
+   char A0[3];
+   (*p)(3, );
+   (*p)(4, );
+}
+
+
+void b1(int n0, char (*a)[n]) { }
+
+
+
+int main()
+{
+   signal(SIGILL, handler);
+
+   foo1();
+
+   foo2();
+   foo3(); // we should diagnose mismatch and run-time discrepancies
+
+   foo4();
+   foo5(); // we should diagnose mismatch and run-time discrepancies
+}
+
+
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c 
b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c
new file mode 100644
index 000..4ec326af06c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c
@@ -0,0 +1,78 @@
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include 
+#include 
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+
+
+void foo1(void (*p)(int n, char (*a)[n]))
+{
+   char 

[PATCH 2/4] c: runtime checking for assigment of VM types 2/4

2023-11-18 Thread Martin Uecker



Support instrumentation of function arguments for functions
called via a declaration.  We can support only simple size
expressions without side effects, because the run-time
instrumentation is done before the call, but the expressions
are evaluated in the callee.

gcc/c:
* c-typeck.cc (process_vm_constraints): Add support
for instrumenting function arguments.
(convert_arguments): Instrument function arguments.
(convert_for_assigmnent): Adapt.

gcc/testsuide/gcc.dg:
* vla-bounds-func-1.c: Update.
* vla-bounds-func-2.c: New test.
* vla-bounds-func-3.c: New test.
* vla-bounds-func-4.c: New test.
* vla-bounds-func-5.c: New test.
* vla-bounds-func-6.c: New test.
* vla-bounds-func-7.c: New test.
* vla-bounds-func-8.c: New test.
* vla-bounds-func-9.c: New test.
* vla-bounds-func-10.c: New test.
* vla-bounds-func-11.c: New test.
* vla-bounds-func-12.c: New test.
* vla-bounds-func-13.c: New test.
* vla-bounds-func-14.c: New test.
* vla-bounds-func-15.c: New test.
* vla-bounds-func-16.c: New test.
* vla-bounds-func-17.c: New test.
* vla-bounds-func-18.c: New test.
* vla-bounds-func-19.c: New test.
* vla-bounds-func-20.c: New test.
---
 gcc/c/c-typeck.cc | 151 +++---
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c  |   4 +-
 gcc/testsuite/gcc.dg/vla-bounds-func-10.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-11.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-12.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-13.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-14.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-15.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-16.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-17.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-18.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-19.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-2.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-20.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-3.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-4.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-5.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-6.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-7.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-8.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-9.c  |  99 ++
 21 files changed, 1641 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-10.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-11.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-12.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-13.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-14.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-15.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-16.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-17.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-18.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-19.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-20.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-5.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-6.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-7.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-8.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-9.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index cb5887b6255..b65fc450940 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1067,19 +1067,13 @@ common_type (tree t1, tree t2)
 /* Instrument assignment of variably modified types.  */
 
 static tree
-c_instrument_vm_assign (location_t loc, tree a, tree b)
+c_instrument_vm_assign (location_t loc, tree a, tree b, tree as, tree bs)
 {
   gcc_assert (flag_vla_bounds);
 
   gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
   gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
 
-  tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
-  tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
-
-  as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
-  bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
-
   tree t = build2 (NE_EXPR, boolean_type_node, as, bs);
   tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 
0);
 
@@ -3286,7 +3280,8 @@ static tree
 convert_argument (location_t ploc, tree function, tree fundecl,
  tree type, tree origtype, tree val, tree valtype,
  bool npc, tree rname, int parmnum, int argnum,
- 

[PATCH 1/4] c: runtime checking for assigment of VM types 1/4

2023-11-18 Thread Martin Uecker



When checking compatibility of types during assignment, collect
all pairs of types where the outermost bound needs to match at
run-time.  This list is then processed to add runtime checks for
each bound.

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

gcc/c:
* c-typeck.cc (struct instrument_data): New structure.
(comp_target_types_instr convert_for_assignment_instrument): New
interfaces for existing functions.
(struct comptypes_data): Add instrumentation.
(comptypes_check_enum_int_intr): New interface.
(comptypes_check_enum_int): Old interface (calls new).
(comptypes_internal): Collect VLA types needed for UBSan.
(comp_target_types_instr): New interface.
(comp_target_types): Old interface (calls new).
(function_types_compatible_p): No instrumentation for function
arguments.
(process_vm_constraints): New function.
(convert_argument): Adapt.
(convert_for_assignment_instrument): New interface.
(convert_for_assignment): Instrument assignments.
(c_instrument_vm_assign): Helper function.
(process_vm_constraints): Helper function.

gcc/doc/:
* invoke.texi (fvla-bounds): Document new flag.

gcc/testsuite:
* gcc.dg/vla-bounds-1.c: New test.
* gcc.dg/vla-bounds-assign-1.c: New test.
* gcc.dg/vla-bounds-assign-2.c: New test.
* gcc.dg/vla-bounds-assign-3.c: New test.
* gcc.dg/vla-bounds-assign-4.c: New test.
* gcc.dg/vla-bounds-func-1.c: New test.
* gcc.dg/vla-bounds-init-1.c: New test.
* gcc.dg/vla-bounds-init-2.c: New test.
* gcc.dg/vla-bounds-init-3.c: New test.
* gcc.dg/vla-bounds-init-4.c: New test.
* gcc.dg/vla-bounds-nest-1.c: New test.
* gcc.dg/vla-bounds-nest-2.c: New test.
* gcc.dg/vla-bounds-ret-1.c: New test.
* gcc.dg/vla-bounds-ret-2.c: New test.
---
 gcc/c-family/c.opt |   4 +
 gcc/c/c-typeck.cc  | 171 ++---
 gcc/doc/invoke.texi|  15 ++
 gcc/testsuite/gcc.dg/vla-bounds-1.c|  85 ++
 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 133 
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c   |  56 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-1.c   | 125 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-2.c   | 125 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-3.c   | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-4.c   | 125 +++
 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c   |  39 +
 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c   |  33 
 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c| 132 
 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c| 133 
 17 files changed, 1661 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index b10c6057cd1..29bc0956181 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2280,6 +2280,10 @@ fvisibility-ms-compat
 C++ ObjC++ Var(flag_visibility_ms_compat)
 Changes visibility to match Microsoft Visual Studio by default.
 
+fvla-bounds
+C Var(flag_vla_bounds)
+Emit run-time consistency checks for variably-modified types.
+
 fvtable-gc
 C++ ObjC++ WarnRemoved
 No longer supported.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1dbb4471a88..cb5887b6255 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -93,11 +93,13 @@ static tree qualify_type (tree, tree);
 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,
   

C runtime checking for assigment of VM types

2023-11-18 Thread Martin Uecker


This is another revised series for checking for
bounds consistency when assigning VM types.


Based on feedback, I disentangled this from UBSan for 
a three reasons:

- I think it makes sense as a stand-alone feature
similar to other run-time instrumentation features
GCC already has.

- Not all checks are strictly speaking for UB, i.e. it
triggers for strictly conforming code which has
inconsistent bounds.  For this feature, it makes 
sense to assume that bounds are correct (and GCC warns 
about inconsistently declared bounds by default already
for a while).

- So far, there is no upstream support in libubsan
which we could use.



Bootstrapped and regression tested on x86_64.


Martin









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

2023-11-16 Thread Martin Uecker






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

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 262b04c582f..2255fb66bb2 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;
@@ -427,7 +434,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);
@@ -435,7 +443,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);
@@ -503,9 +512,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_isoc23 && !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.  */
@@ -520,7 +581,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), 

[PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-16 Thread Martin Uecker




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/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-6.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/c23-tag-alias-3.c: New test.
* gcc.dg/c23-tag-alias-4.c: New test.
* gcc.dg/c23-tag-alias-5.c: New test.
* gcc.dg/c23-tag-alias-6.c: New test.
* gcc.dg/c23-tag-alias-7.c: New test.
* gcc.dg/c23-tag-alias-8.c: New test.
* gcc.dg/gnu23-tag-alias-1.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/c23-tag-2.c |  4 +-
 gcc/testsuite/gcc.dg/c23-tag-5.c |  5 +-
 gcc/testsuite/gcc.dg/c23-tag-alias-1.c   | 48 +
 gcc/testsuite/gcc.dg/c23-tag-alias-2.c   | 73 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-3.c   | 48 +
 gcc/testsuite/gcc.dg/c23-tag-alias-4.c   | 73 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-5.c   | 30 
 gcc/testsuite/gcc.dg/c23-tag-alias-6.c   | 77 
 gcc/testsuite/gcc.dg/c23-tag-alias-7.c   | 86 ++
 gcc/testsuite/gcc.dg/c23-tag-alias-8.c   | 90 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c | 33 +
 15 files changed, 648 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e5d48c3fa56..d0a405087c3 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -634,6 +634,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;
@@ -9646,6 +9676,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_isoc23)
+{
+  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 c8f49aa2370..738afbad770 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) && 

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

2023-11-16 Thread Martin Uecker




Allow redefinition of enum types and enumerators.  Diagnose
nested redefinitions including redefinitions in the enum
specifier for enum types with fixed underlying type.

gcc/c:
* c-tree.h (c_parser_enum_specifier): Add parameter.
* c-decl.cc (start_enum): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.
* c-parser.cc (c_parser_enum_specifier): Remember when
seen is from an enum type which is not yet defined.

gcc/testsuide/:
* gcc.dg/c23-tag-enum-1.c: New test.
* gcc.dg/c23-tag-enum-2.c: New test.
* gcc.dg/c23-tag-enum-3.c: New test.
* gcc.dg/c23-tag-enum-4.c: New test.
* gcc.dg/c23-tag-enum-5.c: New test.
---
 gcc/c/c-decl.cc   | 65 +++
 gcc/c/c-parser.cc |  5 ++-
 gcc/c/c-tree.h|  3 +-
 gcc/c/c-typeck.cc |  5 ++-
 gcc/testsuite/gcc.dg/c23-tag-enum-1.c | 56 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-2.c | 23 ++
 gcc/testsuite/gcc.dg/c23-tag-enum-3.c |  7 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-4.c | 22 +
 gcc/testsuite/gcc.dg/c23-tag-enum-5.c | 18 
 9 files changed, 192 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 194dd595334..e5d48c3fa56 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2114,9 +2114,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_isoc23
+ && 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;
 }
 
@@ -3277,8 +3292,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;
@@ -9737,7 +9755,7 @@ layout_array_type (tree t)
 
 tree
 start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
-   tree fixed_underlying_type)
+   tree fixed_underlying_type, bool potential_nesting_p)
 {
   tree enumtype = NULL_TREE;
   location_t enumloc = UNKNOWN_LOCATION;
@@ -9749,9 +9767,26 @@ 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 (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
+{
+  /* If the type is currently being defined or if we have seen an
+incomplete version which is now complete, this is a nested
+redefinition.  The later happens if the redefinition occurs
+inside the enum specifier itself.  */
+  if (C_TYPE_BEING_DEFINED (enumtype)
+ || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
+   error_at (loc, "nested redefinition of %", name);
+
+ /* For C23 we allow redefinitions.  We set to zero and check for
+   consistency later.  */
+  if (flag_isoc23 && 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)
{
@@ -9779,9 +9814,6 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,

[PATCH 1/4] c23: tag compatibility rules for struct and unions

2023-11-16 Thread Martin Uecker



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/c23-enum-7.c: Remove warning.
* gcc.dg/c23-tag-1.c: New test.
* gcc.dg/c23-tag-2.c: New deactivated test.
* gcc.dg/c23-tag-3.c: New test.
* gcc.dg/c23-tag-4.c: New test.
* gcc.dg/c23-tag-5.c: New deactivated test.
* gcc.dg/c23-tag-6.c: New test.
* gcc.dg/c23-tag-7.c: New test.
* gcc.dg/c23-tag-8.c: New test.
* gcc.dg/gnu23-tag-1.c: New test.
* gcc.dg/gnu23-tag-2.c: New test.
* gcc.dg/gnu23-tag-3.c: New test.
* gcc.dg/gnu23-tag-4.c: New test.
---
 gcc/c/c-decl.cc| 62 ---
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 38 +
 gcc/testsuite/gcc.dg/c23-enum-7.c  |  6 +--
 gcc/testsuite/gcc.dg/c23-tag-1.c   | 67 ++
 gcc/testsuite/gcc.dg/c23-tag-2.c   | 43 +++
 gcc/testsuite/gcc.dg/c23-tag-3.c   | 16 +++
 gcc/testsuite/gcc.dg/c23-tag-4.c   | 26 
 gcc/testsuite/gcc.dg/c23-tag-5.c   | 33 +++
 gcc/testsuite/gcc.dg/c23-tag-6.c   | 25 +++
 gcc/testsuite/gcc.dg/c23-tag-7.c   | 12 ++
 gcc/testsuite/gcc.dg/c23-tag-8.c   | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-2.c | 19 +
 gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 +
 gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 ++
 16 files changed, 411 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64d3a941cb9..194dd595334 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2039,6 +2039,28 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+
+/* Subroutine of finish_struct.  For a tagged type, it finds the
+   declaration for a visible tag declared in the the same scope
+   if such a declaration exists.  */
+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
@@ -8573,11 +8595,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_isoc23)
+   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,
@@ -8782,6 +8807,14 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 
   if (name != NULL_TREE)
 ref = lookup_tag (code, name, true, );
+
+  /* For C23, even if we already have a completed definition,
+ we do not use it. We will check for consistency later.
+ If we are in a nested 

c23 type compatibility rules, v3

2023-11-16 Thread Martin Uecker


Joseph,

this is another revised series for the C23 rules for type
compatibility.

1/4 c23: tag compatibility rules for struct and unions
2/4 c23: tag compatibility rules for enums
3/4 c23: aliasing of compatible tagged types
4/4 c23: construct composite type for tagged types


The first two were revised to address the nesting (and
other) issues you pointed out.

For 3 and 4 I only changed c2x to c23 and moved some
tests around. 3 wasn't reviewed so far and 4 still
needs some more work from my side.


Bootstrapped and regression tested on x86_64.


Martin








Re: [PATCH] Reduce false positives for -Wnonnull for VLA parameters [PR98541]

2023-11-06 Thread Martin Uecker
Am Montag, dem 06.11.2023 um 21:01 -0700 schrieb Jeff Law:
> 
> On 11/6/23 20:58, Hans-Peter Nilsson wrote:
> > > From: Martin Uecker 
> > > Date: Tue, 31 Oct 2023 20:05:09 +0100
> > 
> > >  Reduce false positives for -Wnonnull for VLA parameters [PR98541]
> > >  
> > >  This patch limits the warning about NULL arguments to VLA
> > >  parameters declared [static n].
> > >  
> > >  PR c/98541
> > >  
> > >  gcc/
> > >  * gimple-ssa-warn-access.cc
> > >  (pass_waccess::maybe_check_access_sizes): For VLA bounds
> > >  in parameters, only warn about null pointers with 'static'.
> > >  
> > >  gcc/testsuite:
> > >  * gcc.dg/Wnonnull-4: Adapt test.
> > >  * gcc.dg/Wstringop-overflow-40.c: Adapt test.
> > 
> > This patch caused a testsuite regression: there's now an
> > "excess error" failure for gcc.dg/Wnonnull-4.c for 32-bit
> > targets (and 64-bit targets testing with a "-m32" option)
> > after your r14-5115-g6e9ee44d96e5.  It's logged as PR112419.
> It caused failures for just about every target ;(  Presumably it worked 
> on x86_64...

I do not think this is a true regression
just a problem with the test on 32-bit which somehow surfaced
due to the change.

The excess error is:

FAIL: gcc.dg/Wnonnull-4.c (test for excess errors)
Excess errors:
/home/tcwg-buildslave/workspace/tcwg_gnu_6/abe/snapshots/gcc.git~master/gcc/testsuite/gcc.dg/Wnonnull-4.c:144:3:
 warning: 'fda_n_5' specified size 4294967256 exceeds maximum object size
2147483647 [-Wstringop-overflow=]

I think the warning was suppressed before due to the other (nonnull)
warning which I removed in this case.

I think the simple fix might be to to turn off -Wstringop-overflow.

Link to the change:
https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=6e9ee44d96e5bda8808dd9d8ccf58d2525383f6b


Martin







> 
> jeff



Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-03 Thread Martin Uecker
Am Freitag, dem 03.11.2023 um 07:22 +0100 schrieb Jakub Jelinek:
> On Fri, Nov 03, 2023 at 07:07:36AM +0100, Martin Uecker wrote:
> > Am Donnerstag, dem 02.11.2023 um 17:28 -0700 schrieb Bill Wendling:
> > > On Thu, Nov 2, 2023 at 1:36 PM Qing Zhao  wrote:
> > > > 
> > > > Thanks a lot for raising these issues.
> > > > 
> > > > If I understand correctly,  the major question we need to answer is:
> > > > 
> > > > For the following example: (Jakub mentioned this  in an early message)
> > > > 
> > > >   1 struct S { int a; char b __attribute__((counted_by (a))) []; };
> > > >   2 struct S s;
> > > >   3 s.a = 5;
> > > >   4 char *p = [2];
> > > >   5 int i1 = __builtin_dynamic_object_size (p, 0);
> > > >   6 s.a = 3;
> > > >   7 int i2 = __builtin_dynamic_object_size (p, 0);
> > > > 
> > > > Should the 2nd __bdos call (line 7) get
> > > > A. the latest value of s.a (line 6) for it’s size?
> > > > Or  B. the value when the s.b was referenced (line 3, line 4)?
> > > > 
> > > I personally think it should be (A). The user is specifically
> > > indicating that the size has somehow changed, and the compiler should
> > > behave accordingly.
> > 
> > 
> > One potential problem for A apart from the potential impact on
> > optimization is that the information may get lost more
> > easily. Consider:
> > 
> > char *p = [2];
> > f();
> > int i = __bdos(p, 0);
> > 
> > If the compiler can not see into 'f', the information is lost
> > because f may have changed the size.
> 
> Why?  It doesn't really matter.  The options are
> A. p is at [2] associated with  and int type (or size of int
>or whatever); .ACCESS_WITH_SIZE can't be pure, but sure, for aliasing
>POV we can describe it with more detail that it doesn't modify anything
>in the pointed structure, just escapes the pointer; __bdos can stay
>leaf I believe; and when expanding __bdos later on, it would just
>dereference the associated pointer at that point (note, __bdos is
>pure, so it has vuse but not vdef and can load from memory); if
>f changes s.a, no problem, __bdos will load the changed value in there

Ah, I right. Because of the reload it doesn't matter. 
Thank you for the explanation!

Martin

> B. if .ACCESS_WITH_SIZE associates the pointer with the s.a value from that
>point, .ACCESS_WITH_SIZE can be const, but obviously if f changes s.a,
>__bdos later will use s.a value from the [2] spot



Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-03 Thread Martin Uecker
Am Donnerstag, dem 02.11.2023 um 17:28 -0700 schrieb Bill Wendling:
> On Thu, Nov 2, 2023 at 1:36 PM Qing Zhao  wrote:
> > 
> > Thanks a lot for raising these issues.
> > 
> > If I understand correctly,  the major question we need to answer is:
> > 
> > For the following example: (Jakub mentioned this  in an early message)
> > 
> >   1 struct S { int a; char b __attribute__((counted_by (a))) []; };
> >   2 struct S s;
> >   3 s.a = 5;
> >   4 char *p = [2];
> >   5 int i1 = __builtin_dynamic_object_size (p, 0);
> >   6 s.a = 3;
> >   7 int i2 = __builtin_dynamic_object_size (p, 0);
> > 
> > Should the 2nd __bdos call (line 7) get
> > A. the latest value of s.a (line 6) for it’s size?
> > Or  B. the value when the s.b was referenced (line 3, line 4)?
> > 
> I personally think it should be (A). The user is specifically
> indicating that the size has somehow changed, and the compiler should
> behave accordingly.


One potential problem for A apart from the potential impact on
optimization is that the information may get lost more
easily. Consider:

char *p = [2];
f();
int i = __bdos(p, 0);

If the compiler can not see into 'f', the information is lost
because f may have changed the size.

And if I understand it correctly, if the pointers escapes
with .ACCESS_WITH_SIZE, then this is already true for:

char *p = [2];
g();
int i = __bdos(p, 0);


If we make it UB to change the size, then I guess we could
also delay this choice.  Or we implement B but have a UBSan
option based on A that only verifies at run-time that the size 
did not change.


Martin


> 
> > A should be more convenient for the user to use the dynamic array feature.
> > With B, the user has to modify the source code (to add code to “re-obtain”
> > the pointer after the size was adjusted at line 6) as mentioned by Richard.
> > 
> > This depends on how we design the new internal function .ACCESS_WITH_SIZE
> > 
> > 1. Size is passed by value to .ACCESS_WITH_SIZE as we currently designed.
> > 
> > PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
> > 
> > 2. Size is passed by reference to .ACCESS_WITH_SIZE as Jakub suggested.
> > 
> > PTR = .ACCESS_WITH_SIZE(PTR, , TYPEOFSIZE, ACCESS_MODE)
> > 
> > With 1, We can only provide B, the user needs to modify the source code to 
> > get the full feature of dynamic array;
> > With 2, We can provide  A, the user will get full support to the dynamic 
> > array without restrictions in the source code.
> > 
> My understanding of ACCESS_WITH_SIZE is that it's there to add an
> explicit reference to SIZE so that the optimizers won't reorder the
> code incorrectly. If that's the case, then it should act as if
> ACCESS_WITH_SIZE wasn't even there (i.e. it's just a pointer
> dereference into the FAM). We get that with (2) it appears. It would
> be a major headache to make the user go throughout their code base to
> ensure that SIZE was either unmodified, or if it was that extra code
> must be added to ensure the expected behavior.
> 
> > However, We have to pay additional cost for supporting A by using 2, which 
> > includes:
> > 
> > 1. .ACCESS_WITH_SIZE will become an escape point, which will further impact 
> > the IPA optimizations, more runtime overhead.
> > Then .ACCESS_WTH_SIZE will not be CONST, right? But it will still be 
> > PURE?
> > 
> > 2. __builtin_dynamic_object_size will NOT be LEAF anymore.  This will also 
> > impact some IPA optimizations, more runtime overhead.
> > 
> > I think the following are the factors that make the decision:
> > 
> > 1. How big the performance impact?
> > 2. How important the dynamic array feature? Is adding some user 
> > restrictions as Richard mentioned feasible to support this feature?
> > 
> > Maybe we can implement 1 first, if the full support to the dynamic array is 
> > needed, we can add 2 then?
> > Or, we can implement both, and compare the performance difference, then 
> > decide?
> > 
> > Qing
> > 



Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-02 Thread Martin Uecker
Am Donnerstag, dem 02.11.2023 um 13:50 + schrieb Qing Zhao:
> 
> > On Nov 2, 2023, at 3:57 AM, Richard Biener  
> > wrote:
> > 
> > On Wed, Nov 1, 2023 at 3:47 PM Qing Zhao  wrote:
> > > 
> > > 
> > > 
> > > > On Oct 31, 2023, at 6:14 PM, Joseph Myers  
> > > > wrote:
> > > > 
> > > > On Tue, 31 Oct 2023, Qing Zhao wrote:
> > > > 
> > > > > 2.3 A new semantic requirement in the user documentation of 
> > > > > "counted_by"
> > > > > 
> > > > > For the following structure including a FAM with a counted_by 
> > > > > attribute:
> > > > > 
> > > > > struct A
> > > > > {
> > > > >  size_t size;
> > > > >  char buf[] __attribute__((counted_by(size)));
> > > > > };
> > > > > 
> > > > > for any object with such type:
> > > > > 
> > > > > struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > sizeof(char));
> > > > > 
> > > > > The setting to the size field should be done before the first 
> > > > > reference
> > > > > to the FAM field.
> > > > > 
> > > > > Such requirement to the user will guarantee that the first reference 
> > > > > to
> > > > > the FAM knows the size of the FAM.
> > > > > 
> > > > > We need to add this additional requirement to the user document.
> > > > 
> > > > Make sure the manual is very specific about exactly when size is
> > > > considered to be an accurate representation of the space available for 
> > > > buf
> > > > (given that, after malloc or realloc, it's going to be temporarily
> > > > inaccurate).  If the intent is that inaccurate size at such a time means
> > > > undefined behavior, say so explicitly.
> > > 
> > > Yes, good point. We need to define this clearly in the beginning.
> > > We need to explicit say that
> > > 
> > > the size of the FAM is defined by the latest “counted_by” value. And it’s 
> > > an undefined behavior when the size field is not defined when the FAM is 
> > > referenced.
> > > 
> > > Is the above good enough?
> > > 
> > > 
> > > > 
> > > > > 2.4 Replace FAM field accesses with the new function ACCESS_WITH_SIZE
> > > > > 
> > > > > In C FE:
> > > > > 
> > > > > for every reference to a FAM, for example, "obj->buf" in the small 
> > > > > example,
> > > > > check whether the corresponding FIELD_DECL has a "counted_by" 
> > > > > attribute?
> > > > > if YES, replace the reference to "obj->buf" with a call to
> > > > > .ACCESS_WITH_SIZE (obj->buf, obj->size, -1);
> > > > 
> > > > This seems plausible - but you should also consider the case of static
> > > > initializers - remember the GNU extension for statically allocated 
> > > > objects
> > > > with flexible array members (unless you're not allowing it with
> > > > counted_by).
> > > > 
> > > > static struct A x = { sizeof "hello", "hello" };
> > > > static char *y = 
> > > > 
> > > > I'd expect that to be valid - and unless you say such a usage is 
> > > > invalid,
> > > 
> > > At this moment, I think that this should be valid.
> > > 
> > > I,e, the following:
> > > 
> > > struct A
> > > {
> > > size_t size;
> > > char buf[] __attribute__((counted_by(size)));
> > > };
> > > 
> > > static struct A x = {sizeof "hello", "hello”};
> > > 
> > > Should be valid, and x.size represents the number of elements of x.buf.
> > > Both x.size and x.buf are initialized statically.
> > > 
> > > > you should avoid the replacement in such a static initializer context 
> > > > when
> > > > the FAM reference is to an object with a constant address (if
> > > > .ACCESS_WITH_SIZE would not act as an lvalue whose address is a constant
> > > > expression; if it works fine as a constant-address lvalue, then the
> > > > replacement would be OK).
> > > 
> > > Then if such usage for the “counted_by” is valid, we need to replace the 
> > > FAM
> > > reference by a call to  .ACCESS_WITH_SIZE as well.
> > > Otherwise the “counted_by” relationship will be lost to the Middle end.
> > > 
> > > With the current definition of .ACCESS_WITH_SIZE
> > > 
> > > PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
> > > 
> > > Isn’t the PTR (return value of the call) a LVALUE?
> > 
> > You probably want to specify that when a pointer to the array is taken the
> > pointer has to be to the first array element (or do we want to mangle the
> > 'size' accordingly for the instrumentation?).
> 
> Yes. Will add this into the user documentation.

This shouldn't be necessary. The object-size pass
can track pointer arithmeti if it comes after
inserting the .ACCESS_WITH_SIZE.

https://godbolt.org/z/fvc3aoPfd

> 
> >  You also want to specify that
> > the 'size' associated with such pointer is assumed to be unchanging and
> > after changing the size such pointer has to be re-obtained.
> 
> What do you mean by “re-obtained”? 
> 
> >  Plus that
> > changes to the allocated object/size have to be performed through an
> > lvalue where the containing type and thus the 'counted_by' attribute is
> > visible.
> 
> Through an lvalue with the containing type?
> 
> Yes, will add this too. 

I do not understand this.  It shouldn't matter how
it is 

Re: Help: which routine in C FE I should look at for the reference to a FAM field?

2023-11-01 Thread Martin Uecker
Am Mittwoch, dem 01.11.2023 um 18:14 + schrieb Qing Zhao:
> Joseph and Martin,
> 
> For the task to replace every reference to a FAM field with an call to 
> .ACCESS_WITH_SIZE, 
> Where in the C FE I should look at?
> 
> Thanks a lot for the help.
> 
> 

build_component_ref in c_decl.cc

Martin

> Qing



Re: [PING] [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-11-01 Thread Martin Uecker
Am Dienstag, dem 31.10.2023 um 22:19 + schrieb Joseph Myers:
> On Tue, 31 Oct 2023, Martin Uecker wrote:
> 
> > > +   if (TREE_CODE (arg) == INTEGER_CST
> > > +   && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
> 
> What if TYPE_SIZE_UNIT (ttl) is not an INTEGER_CST?  I don't see any tests 
> of the case of assigning to a pointer to a variably sized type.
> 

Right. Thanks! Revised version attached.

Martin



c: Add Walloc-size to warn about insufficient size in allocations [PR71219]

Add option Walloc-size that warns about allocations that have
insufficient storage for the target type of the pointer the
storage is assigned to. Added to Wextra.

PR c/71219
gcc:
* doc/invoke.texi: Document -Walloc-size option.

gcc/c-family:

* c.opt (Walloc-size): New option.

gcc/c:
* c-typeck.cc (convert_for_assignment): Add warning.

gcc/testsuite:

* gcc.dg/Walloc-size-1.c: New test.
* gcc.dg/Walloc-size-2.c: New test.

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44b9c862c14..29d3d789a49 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -331,6 +331,10 @@ Walloca
 C ObjC C++ ObjC++ Var(warn_alloca) Warning
 Warn on any use of alloca.
 
+Walloc-size
+C ObjC Var(warn_alloc_size) Warning LangEnabledBy(C ObjC, Wextra)
+Warn when allocating insufficient storage for the target type of the assigned 
pointer.
+
 Walloc-size-larger-than=
 C ObjC C++ LTO ObjC++ Var(warn_alloc_size_limit) Joined Host_Wide_Int ByteSize 
Warning Init(HOST_WIDE_INT_MAX)
 -Walloc-size-larger-than=   Warn for calls to allocation functions 
that
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 0de4662bfc6..16fadfb5468 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -7347,6 +7347,34 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
"request for implicit conversion "
"from %qT to %qT not permitted in C++", rhstype, type);
 
+  /* Warn of new allocations that are not big enough for the target
+type.  */
+  tree fndecl;
+  if (warn_alloc_size
+ && TREE_CODE (rhs) == CALL_EXPR
+ && (fndecl = get_callee_fndecl (rhs)) != NULL_TREE
+ && DECL_IS_MALLOC (fndecl))
+   {
+ tree fntype = TREE_TYPE (fndecl);
+ tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
+ tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs);
+ if (alloc_size)
+   {
+ tree args = TREE_VALUE (alloc_size);
+ int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
+ /* For calloc only use the second argument.  */
+ if (TREE_CHAIN (args))
+   idx = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ tree arg = CALL_EXPR_ARG (rhs, idx);
+ if (TREE_CODE (arg) == INTEGER_CST
+ && INTEGER_CST == TREE_CODE (TYPE_SIZE_UNIT (ttl))
+ && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
+warning_at (location, OPT_Walloc_size, "allocation of "
+"insufficient size %qE for type %qT with "
+"size %qE", arg, ttl, TYPE_SIZE_UNIT (ttl));
+   }
+   }
+
   /* See if the pointers point to incompatible address spaces.  */
   asl = TYPE_ADDR_SPACE (ttl);
   asr = TYPE_ADDR_SPACE (ttr);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5a9284d635c..815a33d4b87 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8138,6 +8138,16 @@ always leads to a call to another @code{cold} function 
such as wrappers of
 C++ @code{throw} or fatal error reporting functions leading to @code{abort}.
 @end table
 
+@opindex Wno-alloc-size
+@opindex Walloc-size
+@item -Walloc-size
+Warn about calls to allocation functions decorated with attribute
+@code{alloc_size} that specify insufficient size for the target type of
+the pointer the result is assigned to, including those to the built-in
+forms of the functions @code{aligned_alloc}, @code{alloca},
+@code{calloc},
+@code{malloc}, and @code{realloc}.
+
 @opindex Wno-alloc-zero
 @opindex Walloc-zero
 @item -Walloc-zero
diff --git a/gcc/testsuite/gcc.dg/Walloc-size-1.c 
b/gcc/testsuite/gcc.dg/Walloc-size-1.c
new file mode 100644
index 000..61806f58192
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloc-size-1.c
@@ -0,0 +1,36 @@
+/* Tests the warnings for insufficient allocation size.
+   { dg-do compile }
+   { dg-options "-Walloc-size" }
+ * */
+#include 
+#include 
+
+struct b { int x[10]; };
+
+void fo0(void)
+{
+struct b *p = malloc(sizeof *p);
+}
+
+void fo1(void)
+{
+struct b *p = malloc(sizeof p);/* { dg-wa

Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-01 Thread Martin Uecker
Am Mittwoch, dem 01.11.2023 um 14:47 + schrieb Qing Zhao:
> 
> > On Oct 31, 2023, at 6:14 PM, Joseph Myers  wrote:
> > 
> > On Tue, 31 Oct 2023, Qing Zhao wrote:
> > 
> > > 2.3 A new semantic requirement in the user documentation of "counted_by"
> > > 
> > > For the following structure including a FAM with a counted_by attribute:
> > > 
> > >  struct A
> > >  {
> > >   size_t size;
> > >   char buf[] __attribute__((counted_by(size)));
> > >  };
> > > 
> > > for any object with such type:
> > > 
> > >  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * sizeof(char));
> > > 
> > > The setting to the size field should be done before the first reference 
> > > to the FAM field.
> > > 
> > > Such requirement to the user will guarantee that the first reference to 
> > > the FAM knows the size of the FAM.
> > > 
> > > We need to add this additional requirement to the user document.
> > 
> > Make sure the manual is very specific about exactly when size is 
> > considered to be an accurate representation of the space available for buf 
> > (given that, after malloc or realloc, it's going to be temporarily 
> > inaccurate).  If the intent is that inaccurate size at such a time means 
> > undefined behavior, say so explicitly.
> 
> Yes, good point. We need to define this clearly in the beginning. 
> We need to explicit say that 
> 
> the size of the FAM is defined by the latest “counted_by” value. And it’s an 
> undefined behavior when the size field is not defined when the FAM is 
> referenced.

It is defined by the latest "counted_by" value before x.buf
is referenced, but not the latest before x.buf is dereferenced.

> 
> Is the above good enough?
> 
> 
> > 
> > > 2.4 Replace FAM field accesses with the new function ACCESS_WITH_SIZE
> > > 
> > > In C FE:
> > > 
> > > for every reference to a FAM, for example, "obj->buf" in the small 
> > > example,
> > >  check whether the corresponding FIELD_DECL has a "counted_by" attribute?
> > >  if YES, replace the reference to "obj->buf" with a call to
> > >  .ACCESS_WITH_SIZE (obj->buf, obj->size, -1); 
> > 
> > This seems plausible - but you should also consider the case of static 
> > initializers - remember the GNU extension for statically allocated objects 
> > with flexible array members (unless you're not allowing it with 
> > counted_by).
> > 
> > static struct A x = { sizeof "hello", "hello" };
> > static char *y = 
> > 
> > I'd expect that to be valid - and unless you say such a usage is invalid, 
> 
> At this moment, I think that this should be valid.
> 
> I,e, the following:
> 
> struct A
> {
>  size_t size;
>  char buf[] __attribute__((counted_by(size)));
> };
> 
> static struct A x = {sizeof "hello", "hello”};
> 
> Should be valid, and x.size represents the number of elements of x.buf. 
> Both x.size and x.buf are initialized statically. 

Joseph is talking about the compile-time initialization of y.

> 
> > you should avoid the replacement in such a static initializer context when 
> > the FAM reference is to an object with a constant address (if 
> > .ACCESS_WITH_SIZE would not act as an lvalue whose address is a constant 
> > expression; if it works fine as a constant-address lvalue, then the 
> > replacement would be OK).
> 
> Then if such usage for the “counted_by” is valid, we need to replace the FAM 
> reference by a call to  .ACCESS_WITH_SIZE as well.
> Otherwise the “counted_by” relationship will be lost to the Middle end. 
> 
> With the current definition of .ACCESS_WITH_SIZE
> 
> PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
> 
> Isn’t the PTR (return value of the call) a LVALUE? 

The question is whether we get an address constant
that can be used for compile-time initialization.

I think it would be good to collect a list of test
cases and to include this example.

Martin

> 
> Qing
> > 
> > -- 
> > Joseph S. Myers
> > jos...@codesourcery.com
> 



RFC [PATCH] c: Add missing cases where vla sizes are not instrumented by UBSan [PR98608]

2023-11-01 Thread Martin Uecker



Here is a patch that adds the missing cases for vla size instrumentation.
This now includes all cases where a type with size < 0 is created,
which is already UB and not just cases where a VLA is allocated.  But
a VLA can be allocated based on an typedef, which is also now
indirectly protected in this way.

I moved the instrumentation from the size itself as its own term into 
the expression that evaluate size expressions for side effects. This
avoids confusing other warning code that looks at the size expressions
(-Wvla-parameter).

There is one open question though:  How to to treat n == 0? 

Here I preliminary changed this to n > 0 (also for the existing case),
because when also detecting n == 0 this tools especially when
instrumenting all the types becomes basically useless because of 
the very common (and unproblematic) use of n == 0.  

But strictly speaking n == 0 is also UB and as pointed out in  PR98609
the error message is then not entirely accurate because it says
non-positive and not negative. I do not think it is confusing though
because it is still always correct.

One could consider splitting it up into vla-bound / vla-bound-strict,
but changing the error message would require further upstream changes
and dealing with this far exceeds the time I can afford contributing
to this this.

Another complication is that we ran out of bits for sanitizer flags in
unsigned int, so this would also require more changes.

Any advice?


I think it would be important to have complete UBSan coverage for all
size and bounds issues related to VM types and it would be nice to
get this in GCC 14. (I find this extremely useful in my projects).

Martin




c: Add missing cases where vla sizes are not instrumented by UBSan [PR98608]

Add vla-bound instrumentation for all VLAs including VLAs in parameters
and fields, but allow zero-sized errors.

Bootstrapped and regression tested on x86.

PR c/98608

gcc/c:
* c-decl.cc (grokdeclarator): Instrument all VLAs.

gcc/c-family:
* c-ubsan.cc (ubsan_instrument_vla): Do not include zero length.

gcc/testsuite:
* gcc.dg/ubsan/pr89608.c: New test.
* gcc.dg/ubsan/vla-1.c: New test.
* gcc.dg/ubsan/vla-2.c: New test.
* gcc.dg/ubsan/vla-3.c: New test.
* c-c++-common/ubsan/vla-1.c: Adapt.

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index b2c58c65d97..8983ede0166 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -313,7 +313,7 @@ ubsan_instrument_vla (location_t loc, tree size)
   tree type = TREE_TYPE (size);
   tree t, tt;
 
-  t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
+  t = fold_build2 (LT_EXPR, boolean_type_node, size, build_int_cst (type, 0));
   if (flag_sanitize_trap & SANITIZE_VLA)
 tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
   else
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 7a145bed281..752a65d6729 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -7201,16 +7201,20 @@ grokdeclarator (const struct c_declarator *declarator,
   with known value.  */
this_size_varies = size_varies = true;
warn_variable_length_array (name, size);
-   if (sanitize_flags_p (SANITIZE_VLA)
-   && current_function_decl != NULL_TREE
-   && decl_context == NORMAL)
+   if (sanitize_flags_p (SANITIZE_VLA))
  {
/* Evaluate the array size only once.  */
size = save_expr (size);
size = c_fully_fold (size, false, NULL);
-   size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size),
-   ubsan_instrument_vla (loc, size),
-   size);
+   tree instr = ubsan_instrument_vla (loc, size);
+   /* We have to build this in the right order, so
+  instrumentation is done before the size can
+  be used in other parameters.  */
+   if (*expr)
+ *expr = build2 (COMPOUND_EXPR, TREE_TYPE (instr),
+ *expr, instr);
+   else
+ *expr = instr;
  }
  }
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c 
b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index c97465edae1..cc441ffc80b 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -110,9 +110,7 @@ main (void)
 /* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive 
value -1\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive 
value 

[PATCH] Reduce false positives for -Wnonnull for VLA parameters [PR98541]

2023-10-31 Thread Martin Uecker


This is a revised part of previously posted patch which
I split up. C FE changes which another false positive
were already merged, but I still need approval for this
 middle-end change.  It would be nice to get this in,
because it fixes some rather annoying (for me atleast)
false positive warnings with no easy workaround.

In the following example,

int foo(int n, float matrix[n], float opt[n]);
foo(n, matrix, NULL);

GCC warns about NULL iff n > 0.  This is problematic for
several reasons:
1. It causes false positives (and I turn off -Wnonnull
in one of my projects for this reason)
2. It is inconsistent with regular arrays where there is no
warning in this case.
3. The size parameter is sometimes shared (as in this example)
so passing zero to avoid the warning is only possible by
making the code more complex.
4. Passing zero as a workaround is technically UB.


(The original author of the warning code, Martin S seemed to 
agree with this change according to this discussion in Bugzilla.)



Reduce false positives for -Wnonnull for VLA parameters [PR98541]

This patch limits the warning about NULL arguments to VLA
parameters declared [static n].

PR c/98541

gcc/
* gimple-ssa-warn-access.cc
(pass_waccess::maybe_check_access_sizes): For VLA bounds
in parameters, only warn about null pointers with 'static'.

gcc/testsuite:
* gcc.dg/Wnonnull-4: Adapt test.
* gcc.dg/Wstringop-overflow-40.c: Adapt test.

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index e439d1b9b68..8b734295f09 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3477,27 +3477,14 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, 
tree fndecl, tree fntype,
 
   if (integer_zerop (ptr))
{
- if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0)
+ if (!access.second.internal_p
+ && sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0)
{
  /* Warn about null pointers with positive sizes.  This is
 different from also declaring the pointer argument with
 attribute nonnull when the function accepts null pointers
 only when the corresponding size is zero.  */
- if (access.second.internal_p)
-   {
- const std::string argtypestr
-   = access.second.array_as_string (ptrtype);
-
- if (warning_at (loc, OPT_Wnonnull,
- "argument %i of variable length "
- "array %s is null but "
- "the corresponding bound argument "
- "%i value is %s",
- ptridx + 1, argtypestr.c_str (),
- sizidx + 1, sizstr))
-   arg_warned = OPT_Wnonnull;
-   }
- else if (warning_at (loc, OPT_Wnonnull,
+ if (warning_at (loc, OPT_Wnonnull,
   "argument %i is null but "
   "the corresponding size argument "
   "%i value is %s",
diff --git a/gcc/testsuite/gcc.dg/Wnonnull-4.c 
b/gcc/testsuite/gcc.dg/Wnonnull-4.c
index 2c1c45a9856..1f14fbba45d 100644
--- a/gcc/testsuite/gcc.dg/Wnonnull-4.c
+++ b/gcc/testsuite/gcc.dg/Wnonnull-4.c
@@ -27,9 +27,9 @@ void test_fca_n (int r_m1)
   T (  0);
 
   // Verify positive bounds.
-  T (  1);  // { dg-warning "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 1" }
-  T (  9);  // { dg-warning "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 9" }
-  T (max);  // { dg-warning "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is \\d+" }
+  T (  1);  // { dg-bogus "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 1" }
+  T (  9);  // { dg-bogus "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 9" }
+  T (max);  // { dg-bogus "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is \\d+" }
 }
 
 
@@ -55,9 +55,9 @@ void test_fsa_x_n (int r_m1)
   T (  0);
 
   // Verify positive bounds.
-  T (  1);  // { dg-warning "argument 2 of variable length array 
'short int\\\[]\\\[n]' is null but the corresponding bound argument 1 value is 
1" }
-  T (  9);  // { dg-warning "argument 2 of variable length array 
'short int\\\[]\\\[n]' is null but the corresponding bound argument 1 value is 
9" }
-  T (max);  // { dg-warning "argument 2 of variable length array 
'short int\\\[]\\\[n]' is 

[PING] [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-10-31 Thread Martin Uecker
Am Montag, dem 18.09.2023 um 23:26 +0200 schrieb Martin Uecker:
> 
> Compared to the previous version I changed the name of the
> warning to "Walloc-size" which matches "Wanalyzer-allocation-size"
> but is still in line with the other -Walloc-something warnings
> we have. I also added it to Wextra.
> 
> I found PR71219 that requests the warning and points out that 
> it is recommended by the C secure coding guidelines and added
> the PR to the commit log  (although the version with cast is not
> diagnosed so far.)  
> 
> I did not have time to implement the extensions suggested
> on the list,  i.e. warn when the size is not a multiple
> of the size of the type and warn for if the size is not
> suitable for a flexible array member. (this is also a bit
> more complicated than it seems)
> 
> Bootstrapped and regression tested on x86_64.
> 
> 
> Martin
> 
> 
> Add option Walloc-size that warns about allocations that have
> insufficient storage for the target type of the pointer the
> storage is assigned to.
> 
>   PR c/71219
> gcc:
>   * doc/invoke.texi: Document -Walloc-size option.
> 
> gcc/c-family:
> 
>   * c.opt (Walloc-size): New option.
> 
> gcc/c:
>   * c-typeck.cc (convert_for_assignment): Add warning.
> 
> gcc/testsuite:
> 
>   * gcc.dg/Walloc-size-1.c: New test.
> ---
>  gcc/c-family/c.opt   |  4 
>  gcc/c/c-typeck.cc| 27 +
>  gcc/doc/invoke.texi  | 10 
>  gcc/testsuite/gcc.dg/Walloc-size-1.c | 36 
>  4 files changed, 77 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/Walloc-size-1.c
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 7348ad42ee0..9ba08a1fb6d 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -319,6 +319,10 @@ Walloca
>  C ObjC C++ ObjC++ Var(warn_alloca) Warning
>  Warn on any use of alloca.
>  
> +Walloc-size
> +C ObjC Var(warn_alloc_size) Warning
> +Warn when allocating insufficient storage for the target type of the 
> assigned pointer.
> +
>  Walloc-size-larger-than=
>  C ObjC C++ LTO ObjC++ Var(warn_alloc_size_limit) Joined Host_Wide_Int 
> ByteSize Warning Init(HOST_WIDE_INT_MAX)
>  -Walloc-size-larger-than= Warn for calls to allocation functions 
> that
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index e2bfd2caf85..c759c6245ed 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -7384,6 +7384,33 @@ convert_for_assignment (location_t location, 
> location_t expr_loc, tree type,
>   "request for implicit conversion "
>   "from %qT to %qT not permitted in C++", rhstype, type);
>  
> +  /* Warn of new allocations that are not big enough for the target
> +  type.  */
> +  tree fndecl;
> +  if (warn_alloc_size
> +   && TREE_CODE (rhs) == CALL_EXPR
> +   && (fndecl = get_callee_fndecl (rhs)) != NULL_TREE
> +   && DECL_IS_MALLOC (fndecl))
> + {
> +   tree fntype = TREE_TYPE (fndecl);
> +   tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
> +   tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs);
> +   if (alloc_size)
> + {
> +   tree args = TREE_VALUE (alloc_size);
> +   int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
> +   /* For calloc only use the second argument.  */
> +   if (TREE_CHAIN (args))
> + idx = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
> +   tree arg = CALL_EXPR_ARG (rhs, idx);
> +   if (TREE_CODE (arg) == INTEGER_CST
> +   && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
> +  warning_at (location, OPT_Walloc_size, "allocation of "
> +  "insufficient size %qE for type %qT with "
> +  "size %qE", arg, ttl, TYPE_SIZE_UNIT (ttl));
> + }
> + }
> +
>/* See if the pointers point to incompatible address spaces.  */
>asl = TYPE_ADDR_SPACE (ttl);
>asr = TYPE_ADDR_SPACE (ttr);
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 33befee7d6b..a4fbcf5e1b5 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8086,6 +8086,16 @@ always leads to a call to another @code{cold} function 
> such as wrappers of
>  C++ @code{throw} or fatal error reporting functions leading to @code{abort}.
>  @end table
>  
> +@opindex Wno-alloc-size
> +@opindex Walloc-size
> +@item -Walloc-size
> +Warn about calls to allocation functions decorated 

Re: [PATCH] tree-optimization/109334: Improve computation for access attribute

2023-10-28 Thread Martin Uecker


Thanks, Sid!

(one comment below)

Am Donnerstag, dem 26.10.2023 um 07:51 -0400 schrieb Siddhesh Poyarekar:
> On 2023-10-26 04:37, Martin Uecker wrote:

> 
> > /* ... and either PARM is void * or has a type that is complete and 
> > has a
> >  constant size... */
> > && ((typesize && poly_int_tree_p (typesize))
> > @@ -1587,10 +1587,14 @@ parm_object_size (struct object_size_info *osi, 
> > tree var)
> > unsigned argpos = 0;
> >   
> > /* ... then walk through the parameters to pick the size parameter 
> > and
> > -safely scale it by the type size if needed.  */
> > +safely scale it by the type size if needed.
> > +
> > +TODO: we could also compute the size of VLAs where the size is
> > +given by a function parameter.  */
> 
> Isn't this testcase h() in builtin-dynamic-object-size-20.c?  If you're 
> referring to testcase i(), then maybe "where the size is given by a 
> non-trivial function of a function parameter, e.g.
> fn (size_t n, char buf[dummy(n)])."

h() is supported.  For i() we would need something as
__builtin_access__with_size to record the result of dummy().

But the comment refers to the simpler case:

fn (size_t n, char (*buf)[n])
[[gnu::access(read_write, 2, 1)]]

This doesn't work because buf[n] does not have constant
size, but it could be made to work more easily because
the size is directly given by a function argument.

Martin


> 
> > for (arg = fnargs; arg; arg = TREE_CHAIN (arg), ++argpos)
> > -   if (argpos == access->sizarg && INTEGRAL_TYPE_P (TREE_TYPE (arg)))
> > +   if (argpos == access->sizarg)
> >   {
> > +   gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (arg)));
> > sz = get_or_create_ssa_default_def (cfun, arg);
> > if (sz != NULL_TREE)
> >   {
> > 
> 
> We rely on the frontend to make sure that the arg at sizarg is an 
> integral type.  OK.
> 
> Overall the change looks OK with a few nits I pointed out above.
> 
> Thanks,
> Sid



  1   2   3   >