Re: [V1][PATCH 2/3] Use the element_count atribute info in builtin object size [PR108896].

2023-05-27 Thread Martin Uecker via Gcc-patches


Thank you for working on this!


Here are a couple of comments:

How is the size for an object with FAM defined? 

There are at least three possible choices:

offset(..) + N * sizeof
sizeof(..) + N * sizeof
or the size of a struct with the replacement array.

Or is this not relevant here?


I would personally prefer an attribute which does
not use a string, but uses C expressions, so that
one could write something like this (although I would
limit it initially to the most simple case) 

struct {
  struct bar { int n; }* ptr;
  int buf[] [[element_count(.ptr->n + 3)]];
};

Of course, we could still support this later even
if we use a string now.

Martin




Am Donnerstag, dem 25.05.2023 um 16:14 + schrieb Qing Zhao:
> 2023-05-17 Qing Zhao 
> 
> gcc/ChangeLog:
> 
>   PR C/108896
>   * tree-object-size.cc (addr_object_size): Use the element_count
>   attribute info.
>   * tree.cc (component_ref_has_element_count_p): New function.
>   (component_ref_get_element_count): New function.
>   * tree.h (component_ref_has_element_count_p): New prototype.
>   (component_ref_get_element_count): New prototype.
> 
> gcc/testsuite/ChangeLog:
> 
>   PR C/108896
>   * gcc.dg/flex-array-element-count-2.c: New test.
> ---
>  .../gcc.dg/flex-array-element-count-2.c   | 56 +++
>  gcc/tree-object-size.cc   | 37 ++--
>  gcc/tree.cc   | 93 +++
>  gcc/tree.h| 10 ++
>  4 files changed, 189 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/flex-array-element-count-2.c
> 
> diff --git a/gcc/testsuite/gcc.dg/flex-array-element-count-2.c 
> b/gcc/testsuite/gcc.dg/flex-array-element-count-2.c
> new file mode 100644
> index 000..5a280e8c731
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/flex-array-element-count-2.c
> @@ -0,0 +1,56 @@
> +/* test the attribute element_count and its usage in
> + * __builtin_dynamic_object_size.  */ 
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +#include "builtin-object-size-common.h"
> +
> +#define expect(p, _v) do { \
> +size_t v = _v; \
> +if (p == v) \
> + __builtin_printf ("ok:  %s == %zd\n", #p, p); \
> +else \
> + {  \
> +   __builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +   FAIL (); \
> + } \
> +} while (0);
> +
> +struct flex {
> +  int b;
> +  int c[];
> +} *array_flex;
> +
> +struct annotated {
> +  int b;
> +  int c[] __attribute__ ((element_count ("b")));
> +} *array_annotated;
> +
> +void __attribute__((__noinline__)) setup (int normal_count, int attr_count)
> +{
> +  array_flex
> += (struct flex *)malloc (sizeof (struct flex)
> ++ normal_count *  sizeof (int));
> +  array_flex->b = normal_count;
> +
> +  array_annotated
> += (struct annotated *)malloc (sizeof (struct annotated)
> + + attr_count *  sizeof (int));
> +  array_annotated->b = attr_count;
> +
> +  return;
> +}
> +
> +void __attribute__((__noinline__)) test ()
> +{
> +expect(__builtin_dynamic_object_size(array_flex->c, 1), -1);
> +expect(__builtin_dynamic_object_size(array_annotated->c, 1),
> +array_annotated->b * sizeof (int));
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +  setup (10,10);   
> +  test ();
> +  DONE ();
> +}
> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> index 9a936a91983..f9aadd59054 100644
> --- a/gcc/tree-object-size.cc
> +++ b/gcc/tree-object-size.cc
> @@ -585,6 +585,7 @@ addr_object_size (struct object_size_info *osi, 
> const_tree ptr,
>    if (pt_var != TREE_OPERAND (ptr, 0))
>  {
>    tree var;
> +  tree element_count_ref = NULL_TREE;
>  
> 
>    if (object_size_type & OST_SUBOBJECT)
>   {
> @@ -600,11 +601,12 @@ addr_object_size (struct object_size_info *osi, 
> const_tree ptr,
>   var = TREE_OPERAND (var, 0);
>     if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
>   var = TREE_OPERAND (var, 0);
> -   if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
> +   if (! component_ref_has_element_count_p (var)
> +  && ((! TYPE_SIZE_UNIT (TREE_TYPE (var))
>     || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
>     || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST
>     && tree_int_cst_lt (pt_var_size,
> -   TYPE_SIZE_UNIT (TREE_TYPE (var)
> +   TYPE_SIZE_UNIT (TREE_TYPE (var)))
>   var = pt_var;
>     else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
>   {
> @@ -612,6 +614,7 @@ addr_object_size (struct object_size_info *osi, 
> const_tree ptr,
>     /* For >fld, compute object size if fld isn't a flexible array
>    member.  */
>     bool is_flexible_array_mem_ref = false;
> +
>     while (v && v != pt_var)
>     

[C PATCH] -Wstringop-overflow for parameters with forward-declared sizes

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


This is a minor change so that parameter that have
forward declarations for with -Wstringop-overflow.


Bootstrapped and regression tested on x86_64. 



c: -Wstringop-overflow for parameters with forward-declared sizes

Warnings from -Wstringop-overflow do not appear for parameters declared
as VLAs when the bound refers to a parameter forward declaration. This
is fixed by splitting the loop that passes through parameters into two,
first only recording the positions of all possible size expressions
and then processing the parameters.

PR c/109970

gcc/c-family:

* c-attribs.cc (build_attr_access_from_parms): Split loop to first
record all parameters.

gcc/testsuite:

* gcc.dg/pr109970.c: New test.

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 072cfb69147..e2792ca6898 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -5278,6 +5278,15 @@ build_attr_access_from_parms (tree parms, bool 
skip_voidptr)
   tree argtype = TREE_TYPE (arg);
   if (DECL_NAME (arg) && INTEGRAL_TYPE_P (argtype))
arg2pos.put (arg, argpos);
+}
+
+  argpos = 0;
+  for (tree arg = parms; arg; arg = TREE_CHAIN (arg), ++argpos)
+{
+  if (!DECL_P (arg))
+   continue;
+
+  tree argtype = TREE_TYPE (arg);
 
   tree argspec = DECL_ATTRIBUTES (arg);
   if (!argspec)
diff --git a/gcc/testsuite/gcc.dg/pr109970.c b/gcc/testsuite/gcc.dg/pr109970.c
new file mode 100644
index 000..d234e10455f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109970.c
@@ -0,0 +1,15 @@
+/* PR109970
+ * { dg-do compile }
+ * { dg-options "-Wstringop-overflow" }
+ * */
+
+void bar(int x, char buf[x]);
+void foo(int x; char buf[x], int x);
+
+int main()
+{
+   char buf[10];
+   bar(11, buf);   /* { dg-warning "accessing 11 bytes in a region of size 
10" } */
+   foo(buf, 11);   /* { dg-warning "accessing 11 bytes in a region of size 
10" } */
+}
+




Re: [committed] testsuite: Require trampolines for nestev-vla tests

2023-05-25 Thread Martin Uecker via Gcc-patches


Thanks! I will try to not forget this next time.

Am Donnerstag, dem 25.05.2023 um 21:20 +0300 schrieb Dimitar Dimitrov:
> Three recent test cases declare nested C functions, so they fail on
> targets lacking support for trampolines. Fix by adding the necessary
> filter.
> 
> Committed as obvious.
> 
> gcc/testsuite/ChangeLog:
> 
>   * gcc.dg/nested-vla-1.c: Require effective target trampolines.
>   * gcc.dg/nested-vla-2.c: Ditto.
>   * gcc.dg/nested-vla-3.c: Ditto.
> 
> CC: Martin Uecker 
> Signed-off-by: Dimitar Dimitrov 
> ---
>  gcc/testsuite/gcc.dg/nested-vla-1.c | 1 +
>  gcc/testsuite/gcc.dg/nested-vla-2.c | 1 +
>  gcc/testsuite/gcc.dg/nested-vla-3.c | 1 +
>  3 files changed, 3 insertions(+)
> 
> diff --git a/gcc/testsuite/gcc.dg/nested-vla-1.c 
> b/gcc/testsuite/gcc.dg/nested-vla-1.c
> index 5b62c2c213a..d1b3dc3c5f8 100644
> --- a/gcc/testsuite/gcc.dg/nested-vla-1.c
> +++ b/gcc/testsuite/gcc.dg/nested-vla-1.c
> @@ -1,5 +1,6 @@
>  /* { dg-do run } */
>  /* { dg-options "-std=gnu99" } */
> +/* { dg-require-effective-target trampolines } */
>  
> 
>  
> 
>  int main()
> diff --git a/gcc/testsuite/gcc.dg/nested-vla-2.c 
> b/gcc/testsuite/gcc.dg/nested-vla-2.c
> index d83c90a0b16..294b01d370e 100644
> --- a/gcc/testsuite/gcc.dg/nested-vla-2.c
> +++ b/gcc/testsuite/gcc.dg/nested-vla-2.c
> @@ -1,5 +1,6 @@
>  /* { dg-do run } */
>  /* { dg-options "-std=gnu99" } */
> +/* { dg-require-effective-target trampolines } */
>  
> 
>  
> 
>  int main()
> diff --git a/gcc/testsuite/gcc.dg/nested-vla-3.c 
> b/gcc/testsuite/gcc.dg/nested-vla-3.c
> index 1ffb482da3b..d2ba04adab8 100644
> --- a/gcc/testsuite/gcc.dg/nested-vla-3.c
> +++ b/gcc/testsuite/gcc.dg/nested-vla-3.c
> @@ -1,5 +1,6 @@
>  /* { dg-do run } */
>  /* { dg-options "-std=gnu99" } */
> +/* { dg-require-effective-target trampolines } */
>  
> 
>  
> 
>  int main()




Re: [C PATCH v3] Fix ICEs related to VM types in C 2/2

2023-05-23 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 23.05.2023 um 10:18 +0200 schrieb Richard Biener:
> On Tue, May 23, 2023 at 8:24 AM Martin Uecker 
> wrote:
> > 
> > Am Dienstag, dem 23.05.2023 um 08:13 +0200 schrieb Richard Biener:
> > > On Mon, May 22, 2023 at 7:24 PM Martin Uecker via Gcc-patches
> > >  wrote:
> > > > 
> > > > 
> > > > 
> > > > This version contains the middle-end changes for PR109450
> > > > and test cases as before.  The main middle-end change is that
> > > > we use gimplify_type_sizes also for parameters and remove
> > > > the special code that also walked into pointers (which is
> > > > incorrect).
> > > > 
> > > > In addition, in the C FE this patch now also adds DECL_EXPR
> > > > for vm-types which are pointed-to by parameters declared
> > > > as arrays.  The new function created contains the exact
> > > > code previously used only for regular pointers, and is
> > > > now also called for parameters declared as arrays.
> > > > 
> > > > 
> > > > Martin
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > >     Fix ICEs related to VM types in C 2/2 [PR109450]
> > > > 
> > > >     Size expressions were sometimes lost and not gimplified
> > > > correctly,
> > > >     leading to ICEs and incorrect evaluation order.  Fix this
> > > > by 1) not
> > > >     recursing pointers when gimplifying parameters in the
> > > > middle-end
> > > >     (the code is merged with gimplify_type_sizes), which is
> > > > incorrect
> > > >     because it might access variables declared later for
> > > > incomplete
> > > >     structs, and 2) adding a decl expr for variably-modified
> > > > arrays
> > > >     that are pointed to by parameters declared as arrays.
> > > > 
> > > >     PR c/109450
> > > > 
> > > >     gcc/
> > > >     * c/c-decl.cc (add_decl_expr): New function.
> > > >     (grokdeclarator): Add decl expr for size expression
> > > > in
> > > >     types pointed to by parameters declared as arrays.
> > > >     * function.cc (gimplify_parm_type): Remove
> > > > function.
> > > >     (gimplify_parameters): Call gimplify_parm_sizes.
> > > >     * gimplify.cc (gimplify_type_sizes): Make function
> > > > static.
> > > >     (gimplify_parm_sizes): New function.
> > > > 
> > > >     gcc/testsuite/
> > > >     * gcc.dg/pr109450-1.c: New test.
> > > >     * gcc.dg/pr109450-2.c: New test.
> > > >     * gcc.dg/vla-26.c: New test.
> > > > 
> > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > > > index 494d3cf1747..c35347734b2 100644
> > > > --- a/gcc/c/c-decl.cc
> > > > +++ b/gcc/c/c-decl.cc
> > > > @@ -6490,6 +6490,55 @@ smallest_type_quals_location (const
> > > > location_t *locations,
> > > >    return loc;
> > > >  }
> > > > 
> > > > +
> > > > +/* We attach an artificial TYPE_DECL to pointed-to type
> > > > +   and arrange for it to be included in a DECL_EXPR.  This
> > > > +   forces the sizes evaluation at a safe point and ensures it
> > > > +   is not deferred until e.g. within a deeper conditional
> > > > context.
> > > > +
> > > > +   PARM contexts have no enclosing statement list that
> > > > +   can hold the DECL_EXPR, so we need to use a BIND_EXPR
> > > > +   instead, and add it to the list of expressions that
> > > > +   need to be evaluated.
> > > > +
> > > > +   TYPENAME contexts do have an enclosing statement list,
> > > > +   but it would be incorrect to use it, as the size should
> > > > +   only be evaluated if the containing expression is
> > > > +   evaluated.  We might also be in the middle of an
> > > > +   expression with side effects on the pointed-to type size
> > > > +   "arguments" prior to the pointer declaration point and
> > > > +   the fake TYPE_DECL in the enclosing context would force
> > > > +   the size evaluation prior to the side effects.  We
> > > > therefore
> > &

Re: [C PATCH v3] Fix ICEs related to VM types in C 2/2

2023-05-23 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 23.05.2023 um 08:13 +0200 schrieb Richard Biener:
> On Mon, May 22, 2023 at 7:24 PM Martin Uecker via Gcc-patches
>  wrote:
> > 
> > 
> > 
> > This version contains the middle-end changes for PR109450
> > and test cases as before.  The main middle-end change is that
> > we use gimplify_type_sizes also for parameters and remove
> > the special code that also walked into pointers (which is
> > incorrect).
> > 
> > In addition, in the C FE this patch now also adds DECL_EXPR
> > for vm-types which are pointed-to by parameters declared
> > as arrays.  The new function created contains the exact
> > code previously used only for regular pointers, and is
> > now also called for parameters declared as arrays.
> > 
> > 
> > Martin
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > Fix ICEs related to VM types in C 2/2 [PR109450]
> > 
> > Size expressions were sometimes lost and not gimplified correctly,
> > leading to ICEs and incorrect evaluation order.  Fix this by 1) not
> > recursing pointers when gimplifying parameters in the middle-end
> > (the code is merged with gimplify_type_sizes), which is incorrect
> > because it might access variables declared later for incomplete
> > structs, and 2) adding a decl expr for variably-modified arrays
> > that are pointed to by parameters declared as arrays.
> > 
> > PR c/109450
> > 
> > gcc/
> > * c/c-decl.cc (add_decl_expr): New function.
> > (grokdeclarator): Add decl expr for size expression in
> > types pointed to by parameters declared as arrays.
> > * function.cc (gimplify_parm_type): Remove function.
> > (gimplify_parameters): Call gimplify_parm_sizes.
> > * gimplify.cc (gimplify_type_sizes): Make function static.
> > (gimplify_parm_sizes): New function.
> > 
> > gcc/testsuite/
> > * gcc.dg/pr109450-1.c: New test.
> > * gcc.dg/pr109450-2.c: New test.
> > * gcc.dg/vla-26.c: New test.
> > 
> > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > index 494d3cf1747..c35347734b2 100644
> > --- a/gcc/c/c-decl.cc
> > +++ b/gcc/c/c-decl.cc
> > @@ -6490,6 +6490,55 @@ smallest_type_quals_location (const location_t 
> > *locations,
> >    return loc;
> >  }
> > 
> > +
> > +/* We attach an artificial TYPE_DECL to pointed-to type
> > +   and arrange for it to be included in a DECL_EXPR.  This
> > +   forces the sizes evaluation at a safe point and ensures it
> > +   is not deferred until e.g. within a deeper conditional context.
> > +
> > +   PARM contexts have no enclosing statement list that
> > +   can hold the DECL_EXPR, so we need to use a BIND_EXPR
> > +   instead, and add it to the list of expressions that
> > +   need to be evaluated.
> > +
> > +   TYPENAME contexts do have an enclosing statement list,
> > +   but it would be incorrect to use it, as the size should
> > +   only be evaluated if the containing expression is
> > +   evaluated.  We might also be in the middle of an
> > +   expression with side effects on the pointed-to type size
> > +   "arguments" prior to the pointer declaration point and
> > +   the fake TYPE_DECL in the enclosing context would force
> > +   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)
> > +{
> > +  tree bind = NULL_TREE;
> > +  if (decl_context == TYPENAME || decl_context == PARM || decl_context == 
> > FIELD)
> > +{
> > +  bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE, 
> > NULL_TREE);
> > +  TREE_SIDE_EFFECTS (bind) = 1;
> > +  BIND_EXPR_BODY (bind) = push_stmt_list ();
> > +  push_scope ();
> > +}
> > +
> > +  tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
> > +  pushdecl (decl);
> > +  DECL_ARTIFICIAL (decl) = 1;
> > +  add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
> > +  TYPE_NAME (type) = decl;
> > +
> > +  if (bind)
> > +{
> > +  pop_scope ();
> > +  BIND_EXPR_BODY (bind) = pop_stmt_list (BIND_EXPR_BODY (bind));
> > +  if (*expr)
> > +   *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, bind);
> > +  else
> 

[C PATCH v3] Fix ICEs related to VM types in C 2/2

2023-05-22 Thread Martin Uecker via Gcc-patches



This version contains the middle-end changes for PR109450
and test cases as before.  The main middle-end change is that
we use gimplify_type_sizes also for parameters and remove
the special code that also walked into pointers (which is
incorrect).  

In addition, in the C FE this patch now also adds DECL_EXPR
for vm-types which are pointed-to by parameters declared
as arrays.  The new function created contains the exact
code previously used only for regular pointers, and is
now also called for parameters declared as arrays.


Martin







Fix ICEs related to VM types in C 2/2 [PR109450]

Size expressions were sometimes lost and not gimplified correctly,
leading to ICEs and incorrect evaluation order.  Fix this by 1) not
recursing pointers when gimplifying parameters in the middle-end
(the code is merged with gimplify_type_sizes), which is incorrect
because it might access variables declared later for incomplete
structs, and 2) adding a decl expr for variably-modified arrays
that are pointed to by parameters declared as arrays.

PR c/109450

gcc/
* c/c-decl.cc (add_decl_expr): New function.
(grokdeclarator): Add decl expr for size expression in
types pointed to by parameters declared as arrays.
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_parm_sizes.
* gimplify.cc (gimplify_type_sizes): Make function static.
(gimplify_parm_sizes): New function.

gcc/testsuite/
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/vla-26.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 494d3cf1747..c35347734b2 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6490,6 +6490,55 @@ smallest_type_quals_location (const location_t 
*locations,
   return loc;
 }
 
+
+/* We attach an artificial TYPE_DECL to pointed-to type
+   and arrange for it to be included in a DECL_EXPR.  This
+   forces the sizes evaluation at a safe point and ensures it
+   is not deferred until e.g. within a deeper conditional context.
+
+   PARM contexts have no enclosing statement list that
+   can hold the DECL_EXPR, so we need to use a BIND_EXPR
+   instead, and add it to the list of expressions that
+   need to be evaluated.
+
+   TYPENAME contexts do have an enclosing statement list,
+   but it would be incorrect to use it, as the size should
+   only be evaluated if the containing expression is
+   evaluated.  We might also be in the middle of an
+   expression with side effects on the pointed-to type size
+   "arguments" prior to the pointer declaration point and
+   the fake TYPE_DECL in the enclosing context would force
+   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)
+{
+  tree bind = NULL_TREE;
+  if (decl_context == TYPENAME || decl_context == PARM || decl_context == 
FIELD)
+{
+  bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE, 
NULL_TREE);
+  TREE_SIDE_EFFECTS (bind) = 1;
+  BIND_EXPR_BODY (bind) = push_stmt_list ();
+  push_scope ();
+}
+
+  tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
+  pushdecl (decl);
+  DECL_ARTIFICIAL (decl) = 1;
+  add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
+  TYPE_NAME (type) = decl;
+
+  if (bind)
+{
+  pop_scope ();
+  BIND_EXPR_BODY (bind) = pop_stmt_list (BIND_EXPR_BODY (bind));
+  if (*expr)
+   *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, bind);
+  else
+   *expr = bind;
+}
+}
+
 /* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
@@ -7474,58 +7523,9 @@ grokdeclarator (const struct c_declarator *declarator,
 
   This is expected to happen automatically when the pointed-to
   type has a name/declaration of it's own, but special attention
-  is required if the type is anonymous.
-
-  We attach an artificial TYPE_DECL to such pointed-to type
-  and arrange for it to be included in a DECL_EXPR.  This
-  forces the sizes evaluation at a safe point and ensures it
-  is not deferred until e.g. within a deeper conditional context.
-
-  PARM contexts have no enclosing statement list that
-  can hold the DECL_EXPR, so we need to use a BIND_EXPR
-  instead, and add it to the list of expressions that
-  need to be evaluated.
-
-  TYPENAME contexts do have an enclosing statement list,
-  but it would be incorrect to use it, as the size should
-  only be evaluated if the containing expression is
-  

[C PATCH v3] Fix ICEs related to VM types in C 1/2

2023-05-22 Thread Martin Uecker via Gcc-patches


Hi Joseph,

I had to create another revision of the patch because of some
case I had overlooked (vm-types pointed-to by parameters
declared as I arrays).  I splitted the patch up in two parts
for easier reviewing.  The first part only has the FE changes
and most of the tests.  The only minor change is that I replaced
a bug number because there was a duplicate and that I added
the specific example from this bug report (PR70418) as another
test. Since this half of the patch was already reviewed, I will
commit it tomorrow if there are no comments.

The second part contains the middle-end changes and the new
FE fix you haven't seen.

Both patches bootstrapped and regression tested on x86. 


Martin







Fix ICEs related to VM types in C 1/2 [PR70418, PR107557, PR108423]

Size expressions were sometimes lost and not gimplified correctly, leading 
to
ICEs and incorrect evaluation order.  Fix this by 1) not recursing into
pointers when gimplifying parameters in the middle-end (the code is merged 
with
gimplify_type_sizes), which is incorrect because it might access variables
declared later for incomplete structs, and 2) tracking size expressions for
struct/union members correctly, 3) emitting code to evaluate size 
expressions
for missing cases (nested functions, empty declarations, and 
structs/unions).

PR c/70418
PR c/106465
PR c/107557
PR c/108423

gcc/
* c/c-decl.cc (start_decl): Make sure size expression are
evaluated only in correct context.
(grokdeclarator): Size expression in fields may need a bind
expression, make sure DECL_EXPR is always created.
(grokfield, declspecs_add_type): Pass along size expressions.
(finish_struct): Remove unneeded DECL_EXPR.
(start_function): Evaluate size expressions for nested functions.
* c/c-parser.cc (c_parser_struct_declarations,
c_parser_struct_or_union_specifier): Pass along size expressions.
(c_parser_declaration_or_fndef): Evaluate size expression.
(c_parser_objc_at_property_declaration,
c_parser_objc_class_instance_variables): Adapt.

gcc/testsuite/
* gcc.dg/nested-vla-1.c: New test.
* gcc.dg/nested-vla-2.c: New test.
* gcc.dg/nested-vla-3.c: New test.
* gcc.dg/pr70418.c: New test.
* gcc.dg/pr106465.c: New test.
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.
* gcc.dg/pr108423-6.c: New test.
* gcc.dg/typename-vla-2.c: New test.
* gcc.dg/typename-vla-3.c: New test.
* gcc.dg/typename-vla-4.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 94ce760b55e..494d3cf1747 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5364,7 +5364,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))
@@ -7498,7 +7499,8 @@ grokdeclarator (const struct c_declarator *declarator,
&& c_type_variably_modified_p (type))
  {
tree bind = NULL_TREE;
-   if (decl_context == TYPENAME || decl_context == PARM)
+   if (decl_context == TYPENAME || decl_context == PARM
+   || decl_context == FIELD)
  {
bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
   NULL_TREE, NULL_TREE);
@@ -7507,10 +7509,11 @@ grokdeclarator (const struct c_declarator *declarator,
push_scope ();
  }
tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-   DECL_ARTIFICIAL (decl) = 1;
pushdecl (decl);
-   finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE);
+   DECL_ARTIFICIAL (decl) = 1;
+   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, 
decl));
TYPE_NAME (type) = decl;
+
if (bind)
  {
pop_scope ();
@@ -8709,7 +8712,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 tree
 grokfield (location_t loc,
   struct c_declarator *declarator, struct c_declspecs *declspecs,
-  tree 

[C PATCH] Remove dead code related to type compatibility across TUs.

2023-05-19 Thread Martin Uecker via Gcc-patches


Repost for stage 1.


C: Remove dead code related to type compatibility across TUs.

Code to detect struct/unions across the same TU is not needed
anymore. Code for determining compatibility of tagged types is
preserved as it will be used for C2X. Some errors in the unused
code are fixed.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c/
* c-decl.cc (set_type_context): Remove.
(pop_scope, diagnose_mismatched_decls, pushdecl):
Remove dead code.
* c-typeck.cc (comptypes_internal): Remove dead code.
(same_translation_unit_p): Remove.
(tagged_types_tu_compatible_p): Some fixes.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index f63c1108ab5..70345b4b019 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -1155,16 +1155,6 @@ update_label_decls (struct c_scope *scope)
 }
 }
 
-/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT.  */
-
-static void
-set_type_context (tree type, tree context)
-{
-  for (type = TYPE_MAIN_VARIANT (type); type;
-   type = TYPE_NEXT_VARIANT (type))
-TYPE_CONTEXT (type) = context;
-}
-
 /* Exit a scope.  Restore the state of the identifier-decl mappings
that were in effect when this scope was entered.  Return a BLOCK
node containing all the DECLs in this scope that are of interest
@@ -1253,7 +1243,6 @@ pop_scope (void)
case ENUMERAL_TYPE:
case UNION_TYPE:
case RECORD_TYPE:
- set_type_context (p, context);
 
  /* Types may not have tag-names, in which case the type
 appears in the bindings list with b->id NULL.  */
@@ -1364,12 +1353,7 @@ pop_scope (void)
 the TRANSLATION_UNIT_DECL.  This makes same_translation_unit_p
 work.  */
  if (scope == file_scope)
-   {
  DECL_CONTEXT (p) = context;
- if (TREE_CODE (p) == TYPE_DECL
- && TREE_TYPE (p) != error_mark_node)
-   set_type_context (TREE_TYPE (p), context);
-   }
 
  gcc_fallthrough ();
  /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
@@ -2318,21 +2302,18 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
{
  if (DECL_INITIAL (olddecl))
{
- /* If both decls are in the same TU and the new declaration
-isn't overriding an extern inline reject the new decl.
-In c99, no overriding is allowed in the same translation
-unit.  */
- if ((!DECL_EXTERN_INLINE (olddecl)
-  || DECL_EXTERN_INLINE (newdecl)
-  || (!flag_gnu89_inline
-  && (!DECL_DECLARED_INLINE_P (olddecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES (olddecl)))
-  && (!DECL_DECLARED_INLINE_P (newdecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES (newdecl
- )
- && same_translation_unit_p (newdecl, olddecl))
+ /* If the new declaration isn't overriding an extern inline
+reject the new decl. In c99, no overriding is allowed
+in the same translation unit.  */
+ if (!DECL_EXTERN_INLINE (olddecl)
+ || DECL_EXTERN_INLINE (newdecl)
+ || (!flag_gnu89_inline
+ && (!DECL_DECLARED_INLINE_P (olddecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES (olddecl)))
+ && (!DECL_DECLARED_INLINE_P (newdecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES (newdecl)
{
  auto_diagnostic_group d;
  error ("redefinition of %q+D", newdecl);
@@ -3360,18 +3341,11 @@ pushdecl (tree x)
 type to the composite of all the types of that declaration.
 After the consistency checks, it will be reset to the
 composite of the visible types only.  */
-  if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
- && b->u.type)
+  if (b && b->u.type)
TREE_TYPE (b->decl) = b->u.type;
 
-  /* The point of the same_translation_unit_p check here is,
-we want to detect a duplicate decl for a construct like
-foo() { extern bar(); } ... static bar();  but not if
-they are in different translation units.  In any case,
-the static does not go in the externals scope.  */
-  if (b
- && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
- && duplicate_decls (x, b->decl))
+  /* the static does not go in the externals scope.  */
+  if (b && duplicate_decls (x, b->decl))
   

[C PATCH v2] Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]

2023-05-19 Thread Martin Uecker via Gcc-patches


Thanks Joseph! 

Revised version attached. Ok?


But I wonder whether we generally need to do something 
about

  sizeof *x

when x is NULL or not initialized. This is quite commonly
used in C code and if the type is not of variable size,
it is also unproblematic.  So the UB for variable size is
unfortunate and certainly also affects existing code in
the wild.  In practice it does not seem to cause
problems because there is no lvalue conversion and this
then seems to work.  Maybe we document this as an 
extension?  (and make sure in the C FE that it
works)  This would also make this idiom valid:

char (*buf)[n] = malloc(sizeof *buf);

Or if we do not want to do this, then I think we should
add some warnings (and UBSan check for null pointer)
which currently do not exist:

https://godbolt.org/z/fhWMKvYc8

Martin




Am Donnerstag, dem 18.05.2023 um 21:46 + schrieb Joseph Myers:
> On Thu, 18 May 2023, Martin Uecker via Gcc-patches wrote:
> 
> > +  /* we still have to evaluate size expressions */
> 
> Comments should start with a capital letter and end with ".  ".
> 
> > diff --git a/gcc/testsuite/gcc.dg/nested-vla-1.c 
> > b/gcc/testsuite/gcc.dg/nested-vla-1.c
> > new file mode 100644
> > index 000..408a68524d8
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/nested-vla-1.c
> > @@ -0,0 +1,37 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=gnu99" } */
> 
> I'm concerned with various undefined behavior in this and other tests; 
> they look very fragile, relying on some optimizations and not others 
> taking place.  I think they should be adjusted to avoid undefined behavior 
> if all the evaluations from the abstract machine (in particular, of sizeof 
> operands with variable size) take place, and other undefined behavior from 
> calling functions through function pointers with incompatible type.
> 
> > +   struct bar { char x[++n]; } (*bar2)(void) = bar;/* { dg-warning 
> > "incompatible pointer type" } */
> > +
> > +   if (2 != n)
> > +   __builtin_abort();
> > +
> > +   if (2 != sizeof((*bar2)()))
> > +   __builtin_abort();
> 
> You're relying on the compiler not noticing that a function is being 
> called through an incompatible type and thus not turning the call (which 
> should be evaluated, because the operand of sizeof has a type with 
> variable size) into a call to abort.
> 
> > diff --git a/gcc/testsuite/gcc.dg/nested-vla-2.c 
> > b/gcc/testsuite/gcc.dg/nested-vla-2.c
> > new file mode 100644
> > index 000..504eec48c80
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/nested-vla-2.c
> > @@ -0,0 +1,33 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=gnu99" } */
> > +
> > +
> > +int main()
> > +{
> > +   int n = 1;
> > +
> > +   typeof(char (*)[++n]) bar(void) { }
> > +
> > +   if (2 != n)
> > +   __builtin_abort();
> > +
> > +   if (2 != sizeof(*bar()))
> > +   __builtin_abort();
> 
> In this test, *bar() is evaluated, i.e. an undefined pointer is 
> dereferenced; it would be better to return a valid pointer to a 
> sufficiently large array to avoid that undefined behavior.
> 
> > diff --git a/gcc/testsuite/gcc.dg/pr106465.c 
> > b/gcc/testsuite/gcc.dg/pr106465.c
> > new file mode 100644
> > index 000..b03e2442f12
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr106465.c
> > @@ -0,0 +1,86 @@
> > +/* PR c/106465
> > + * { dg-do run }
> > + * { dg-options "-std=gnu99" }
> > + * */
> > +
> > +int main()
> > +{
> > +   int n = 3;
> > +   
> > +   void g1(int m, struct { char p[++m]; }* b)  /* { dg-warning 
> > "anonymous struct" } */
> > +   {
> > +   if (3 != m)
> > +   __builtin_abort();
> > +
> > +   if (3 != sizeof(b->p))
> > +   __builtin_abort();
> > +   }
> 
> > +   g1(2, (void*)0);
> 
> Similarly, this is dereferencing a null pointer in the evaluated operand 
> of sizeof.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 90d7cd27cd5..f63c1108ab5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5378,7 +5378,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MA

[PING] [C PATCH] Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]

2023-05-18 Thread Martin Uecker via Gcc-patches



Ping. Ok, for trunk?

Bootstrapped and tested on x86_64-linux-gnu with no regressions.



Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]

Size expressions were sometimes lost and not gimplified correctly, leading 
to
ICEs and incorrect evaluation order.  Fix this by 1) not recursing into
pointers when gimplifying parameters in the middle-end (the code is merged 
with
gimplify_type_sizes), which is incorrect because it might access variables
declared later for incomplete structs, and 2) tracking size expressions for
struct/union members correctly, 3) emitting code to evaluate size 
expressions
for missing cases (nested functions, empty declarations, and 
structs/unions).

PR c/106465
PR c/107557
PR c/108423
PR c/109450

gcc/
* c/c-decl.cc (start_decl): Make sure size expression are
evaluated only in correct context.
(grokdeclarator): Size expression in fields may need a bind
expression, make sure DECL_EXPR is always created.
(grokfield, declspecs_add_type): Pass along size expressions.
(finish_struct): Remove unneeded DECL_EXPR.
(start_function): Evaluate size expressions for nested functions.
* c/c-parser.cc (c_parser_struct_declarations,
c_parser_struct_or_union_specifier): Pass along size expressions.
(c_parser_declaration_or_fndef): Evaluate size expression.
(c_parser_objc_at_property_declaration,
c_parser_objc_class_instance_variables): Adapt.
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_parm_sizes.
* gimplify.cc (gimplify_type_sizes): Make function static.
(gimplify_parm_sizes): New function.

gcc/testsuite/
* gcc.dg/nested-vla-1.c: New test.
* gcc.dg/nested-vla-2.c: New test.
* gcc.dg/nested-vla-3.c: New test.
* gcc.dg/pr106465.c: New test.
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.
* gcc.dg/pr108423-6.c: New test.
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/typename-vla-2.c: New test.
* gcc.dg/typename-vla-3.c: New test.
* gcc.dg/typename-vla-4.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 90d7cd27cd5..f63c1108ab5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5378,7 +5378,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))
@@ -7510,7 +7511,8 @@ grokdeclarator (const struct c_declarator *declarator,
&& c_type_variably_modified_p (type))
  {
tree bind = NULL_TREE;
-   if (decl_context == TYPENAME || decl_context == PARM)
+   if (decl_context == TYPENAME || decl_context == PARM
+   || decl_context == FIELD)
  {
bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
   NULL_TREE, NULL_TREE);
@@ -7519,10 +7521,11 @@ grokdeclarator (const struct c_declarator *declarator,
push_scope ();
  }
tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-   DECL_ARTIFICIAL (decl) = 1;
pushdecl (decl);
-   finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE);
+   DECL_ARTIFICIAL (decl) = 1;
+   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, 
decl));
TYPE_NAME (type) = decl;
+
if (bind)
  {
pop_scope ();
@@ -8721,7 +8724,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 tree
 grokfield (location_t loc,
   struct c_declarator *declarator, struct c_declspecs *declspecs,
-  tree width, tree *decl_attrs)
+  tree width, tree *decl_attrs, tree *expr)
 {
   tree value;
 
@@ -8778,7 +8781,7 @@ grokfield (location_t loc,
 }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
- width ?  : NULL, decl_attrs, NULL, NULL,
+ width ? 

[committed, gcc 12] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-05-09 Thread Martin Uecker via Gcc-patches



Bootstrapped and regression tested on x86-64.



Fix ICE related to implicit access attributes for VLA arguments [PR105660]

When constructing the specifier string when merging an access attribute
that encodes information about VLA arguments, the string was constructed
in random order by iterating through a hash table. Fix this by iterating
though the list of arguments.

PR c/105660

gcc/Changelog
* c-family/c-attribs.cc (append_access_attr): Use order
of arguments when construction string.
(append_access_attr_idxs): Rename and make static.
* c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.

gcc/testsuite/ChangeLog:
* gcc.dg/pr105660-1.c: New test.
* gcc.dg/pr105660-2.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 4667f6de311..072cfb69147 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
char *attrstr,
   rdwr_map cur_idxs;
   init_attr_rdwr_indices (_idxs, attrs);
 
+  tree args = TYPE_ARG_TYPES (node[0]);
+  int argpos = 0;
   std::string spec;
-  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
+  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
 {
-  const auto  = *it;
+  const attr_access* const newa = new_idxs.get (argpos);
+
+  if (!newa)
+   continue;
 
   /* The map has two equal entries for each pointer argument that
 has an associated size argument.  Process just the entry for
 the former.  */
-  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
+  if ((unsigned)argpos != newa->ptrarg)
continue;
 
-  const attr_access* const cura = cur_idxs.get (newaxsref.first);
+  const attr_access* const cura = cur_idxs.get (argpos);
   if (!cura)
{
  /* The new attribute needs to be added.  */
- tree str = newaxsref.second.to_internal_string ();
+ tree str = newa->to_internal_string ();
  spec += TREE_STRING_POINTER (str);
  continue;
}
@@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
   /* The new access spec refers to an array/pointer argument for
 which an access spec already exists.  Check and diagnose any
 conflicts.  If no conflicts are found, merge the two.  */
-  const attr_access* const newa = 
 
   if (!attrstr)
{
@@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
continue;
 
   /* Merge the CURA and NEWA.  */
-  attr_access merged = newaxsref.second;
+  attr_access merged = *newa;
 
   /* VLA seen in a declaration takes precedence.  */
   if (cura->minsize == HOST_WIDE_INT_M1U)
@@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
 
 /* Convenience wrapper for the above.  */
 
-tree
-append_access_attr (tree node[3], tree attrs, const char *attrstr,
-   char code, HOST_WIDE_INT idxs[2])
+static tree
+append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
+char code, HOST_WIDE_INT idxs[2])
 {
   char attrspec[80];
   int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
@@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
  attributes specified on previous declarations of the same type
  and if not, concatenate the two.  */
   const char code = attr_access::mode_chars[mode];
-  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
 return NULL_TREE;
 
@@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
 {
   /* Repeat for the previously declared type.  */
   attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
-  new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
return NULL_TREE;
 
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 29efce3f2c0..a6fb95b1e80 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3617,6 +3617,8 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
+ gcc_assert (curvbl);
+
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/pr105660-1.c 
b/gcc/testsuite/gcc.dg/pr105660-1.c
new file mode 100644
index 000..d4454f04c43
--- /dev/null
+++ 

Re: Re: GCC 12.2.1 Status Report (2023-05-02), branch frozen for release

2023-05-04 Thread Martin Uecker via Gcc-patches
Am Donnerstag, dem 04.05.2023 um 09:53 + schrieb Richard Biener:
> On Thu, 4 May 2023, Martin Uecker wrote:
> 
> > 
> > Can I please get permission for fixing this ICE?
> > 
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-April/616221.html
> 
> Please wait until after the branch is unfrozen.  When patches were
> approved for trunk and they are regressions there's no further
> approval needed to backport them (but of course bootstrap & testing
> is required on the branches backported to).

Ok, thanks - good to know! Next time I just push important
fixes for regressions approved for trunk.   But does this mean
we need to wait for about a year to get this fix into 12? 
This would be a bit unfortunate for this problem I think.

Martin



Re: Re: GCC 12.2.1 Status Report (2023-05-02), branch frozen for release

2023-05-04 Thread Martin Uecker via Gcc-patches


Can I please get permission for fixing this ICE?

https://gcc.gnu.org/pipermail/gcc-patches/2023-April/616221.html



Martin





PING [C PATCH - backport 12] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-04-30 Thread Martin Uecker via Gcc-patches


Ok for 12.3 ? 

Am Mittwoch, dem 19.04.2023 um 18:39 +0200 schrieb Martin Uecker:
> Ok to cherrypick for 12?   It is in GCC 13 and fixes an
> annoying ICE.
> 
> Martin
> 
> 
> 
> Here is a fix for PR105660.
> 
> Bootstrapped and regression tested on x86-64.
> 
> 
> Fix ICE related to implicit access attributes for VLA arguments [PR105660]
> 
> 
> When constructing the specifier string when merging an access attribute
> that encodes information about VLA arguments, the string was constructed
> in random order by iterating through a hash table. Fix this by iterating
> though the list of arguments.
> 
> 
> PR c/105660
> 
> 
> gcc/Changelog
> * c-family/c-attribs.cc (append_access_attr): Use order
> of arguments when construction string.
> (append_access_attr_idxs): Rename and make static.
> * c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.
> 
> 
> gcc/testsuite/ChangeLog:
> * gcc.dg/pr105660-1.c: New test.
> * gcc.dg/pr105660-2.c: New test.
> 
> 
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index 4667f6de311..072cfb69147 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>    rdwr_map cur_idxs;
>    init_attr_rdwr_indices (_idxs, attrs);
>  
> 
> +  tree args = TYPE_ARG_TYPES (node[0]);
> +  int argpos = 0;
>    std::string spec;
> -  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
> +  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
>  {
> -  const auto  = *it;
> +  const attr_access* const newa = new_idxs.get (argpos);
> +
> +  if (!newa)
> + continue;
>  
> 
>    /* The map has two equal entries for each pointer argument that
>    has an associated size argument.  Process just the entry for
>    the former.  */
> -  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
> +  if ((unsigned)argpos != newa->ptrarg)
>   continue;
>  
> 
> -  const attr_access* const cura = cur_idxs.get (newaxsref.first);
> +  const attr_access* const cura = cur_idxs.get (argpos);
>    if (!cura)
>   {
>     /* The new attribute needs to be added.  */
> -   tree str = newaxsref.second.to_internal_string ();
> +   tree str = newa->to_internal_string ();
>     spec += TREE_STRING_POINTER (str);
>     continue;
>   }
> @@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>    /* The new access spec refers to an array/pointer argument for
>    which an access spec already exists.  Check and diagnose any
>    conflicts.  If no conflicts are found, merge the two.  */
> -  const attr_access* const newa = 
>  
> 
>    if (!attrstr)
>   {
> @@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>   continue;
>  
> 
>    /* Merge the CURA and NEWA.  */
> -  attr_access merged = newaxsref.second;
> +  attr_access merged = *newa;
>  
> 
>    /* VLA seen in a declaration takes precedence.  */
>    if (cura->minsize == HOST_WIDE_INT_M1U)
> @@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>  
> 
>  /* Convenience wrapper for the above.  */
>  
> 
> -tree
> -append_access_attr (tree node[3], tree attrs, const char *attrstr,
> - char code, HOST_WIDE_INT idxs[2])
> +static tree
> +append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
> +  char code, HOST_WIDE_INT idxs[2])
>  {
>    char attrspec[80];
>    int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
> @@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
> args, int flags,
>   attributes specified on previous declarations of the same type
>   and if not, concatenate the two.  */
>    const char code = attr_access::mode_chars[mode];
> -  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
> +  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, 
> idxs);
>    if (!new_attrs)
>  return NULL_TREE;
>  
> 
> @@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
> args, int flags,
>  {
>    /* Repeat for the previously declared type.  */
>    attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
> -  new_attrs = append_access_attr (node, attrs, attrstr

Re: [PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-04-20 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 04.04.2023 um 19:31 -0600 schrieb Jeff Law:
> 
> On 4/3/23 13:34, Martin Uecker via Gcc-patches wrote:
> > 
> > 
> > With the relatively new warnings (11..) affecting VLA bounds,
> > I now get a lot of false positives with -Wall. In general, I find
> > the new warnings very useful, but they seem a bit too
> > aggressive and some minor tweaks are needed, otherwise they are
> > too noisy.  This patch suggests two changes:
> > 
> > 1. For VLA bounds non-null is implied only when 'static' is
> > used (similar to clang) and not already when a bound > 0 is
> > specified:
> > 
> > int foo(int n, char buf[static n]);
> > 
> > int foo(10, 0); // warning with 'static' but not without.
> > 
> > 
> > (It also seems problematic to require a size of 0 to indicate
> > that the pointer may be null, because 0 is not allowed in
> > ISO C as a size. It is also inconsistent to how arrays with
> > static bound behave.)
> > 
> > There seems to be agreement about this change in PR98541.
> > 
> > 
> > 2. GCC always warns when the number of unspecified
> > bounds is different between two declarations:
> > 
> > int foo(int n, char buf[*]);
> > int foo(int n, char buf[n]);
> > 
> > or
> > 
> > int foo(int n, char buf[n]);
> > int foo(int n, char buf[*]);
> > 
> > But the first version is useful if the size expression
> > can not be specified in a header (e.g. because it uses
> > a macro or variable not available there) and there is
> > currently no easy way to avoid this.  The warning for
> > both cases was by design,  but I suggest to limit the
> > warning to the second case.
> > 
> > Note that the logic currently applied by GCC is too
> > simplistic anyway, as GCC does not warn for
> > 
> > int foo(int x, int y, double m[*][y]);
> > int foo(int x, int y, double m[x][*]);
> > 
> > because the number of specified / unspecified bounds
> > is the same.  So I suggest to go with the attached
> > patch now and add  more precise warnings later
> > if there is more experience with these warning
> > in gernal and if this then still seems desirable.
> > 
> > 
> > Martin
> > 
> > 
> >  Less warnings for parameters declared as arrays [PR98541, PR98536]
> >  
> > 
> > 
> > 
> >  To avoid false positivies, tune the warnings for parameters declared
> >  as arrays with size expressions.  Only warn about null arguments with
> >  'static'.  Also do not warn when more bounds are specified in the new
> >  declaration than before.
> >  
> > 
> > 
> > 
> >  PR c/98541
> >  PR c/98536
> >  
> > 
> > 
> > 
> >  c-family/
> >  * c-warn.cc (warn_parm_array_mismatch): Do not warn if more
> >  bounds are specified.
> >  
> > 
> > 
> > 
> >  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.
> >  * gcc.dg/Wvla-parameter-4.c: Adapt test.
> >  * gcc.dg/attr-access-2.c: Adapt test.
> Neither appears to be a regression.  Seems like it should defer to gcc-14.

Then ok for trunk now?

Martin






[C PATCH - backport 12] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-04-19 Thread Martin Uecker via Gcc-patches


Ok to cherrypick for 12?   It is in GCC 13 and fixes an
annoying ICE.

Martin



Here is a fix for PR105660.

Bootstrapped and regression tested on x86-64.


Fix ICE related to implicit access attributes for VLA arguments [PR105660]

When constructing the specifier string when merging an access attribute
that encodes information about VLA arguments, the string was constructed
in random order by iterating through a hash table. Fix this by iterating
though the list of arguments.

PR c/105660

gcc/Changelog
* c-family/c-attribs.cc (append_access_attr): Use order
of arguments when construction string.
(append_access_attr_idxs): Rename and make static.
* c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.

gcc/testsuite/ChangeLog:
* gcc.dg/pr105660-1.c: New test.
* gcc.dg/pr105660-2.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 4667f6de311..072cfb69147 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
char *attrstr,
   rdwr_map cur_idxs;
   init_attr_rdwr_indices (_idxs, attrs);
 
+  tree args = TYPE_ARG_TYPES (node[0]);
+  int argpos = 0;
   std::string spec;
-  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
+  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
 {
-  const auto  = *it;
+  const attr_access* const newa = new_idxs.get (argpos);
+
+  if (!newa)
+   continue;
 
   /* The map has two equal entries for each pointer argument that
 has an associated size argument.  Process just the entry for
 the former.  */
-  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
+  if ((unsigned)argpos != newa->ptrarg)
continue;
 
-  const attr_access* const cura = cur_idxs.get (newaxsref.first);
+  const attr_access* const cura = cur_idxs.get (argpos);
   if (!cura)
{
  /* The new attribute needs to be added.  */
- tree str = newaxsref.second.to_internal_string ();
+ tree str = newa->to_internal_string ();
  spec += TREE_STRING_POINTER (str);
  continue;
}
@@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
   /* The new access spec refers to an array/pointer argument for
 which an access spec already exists.  Check and diagnose any
 conflicts.  If no conflicts are found, merge the two.  */
-  const attr_access* const newa = 
 
   if (!attrstr)
{
@@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
continue;
 
   /* Merge the CURA and NEWA.  */
-  attr_access merged = newaxsref.second;
+  attr_access merged = *newa;
 
   /* VLA seen in a declaration takes precedence.  */
   if (cura->minsize == HOST_WIDE_INT_M1U)
@@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
 
 /* Convenience wrapper for the above.  */
 
-tree
-append_access_attr (tree node[3], tree attrs, const char *attrstr,
-   char code, HOST_WIDE_INT idxs[2])
+static tree
+append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
+char code, HOST_WIDE_INT idxs[2])
 {
   char attrspec[80];
   int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
@@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
  attributes specified on previous declarations of the same type
  and if not, concatenate the two.  */
   const char code = attr_access::mode_chars[mode];
-  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
 return NULL_TREE;
 
@@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
 {
   /* Repeat for the previously declared type.  */
   attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
-  new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
return NULL_TREE;
 
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 29efce3f2c0..a6fb95b1e80 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3617,6 +3617,8 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
+ gcc_assert (curvbl);
+
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/pr105660-1.c 

Re: Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]

2023-04-11 Thread Martin Uecker via Gcc-patches
Am Mittwoch, dem 12.04.2023 um 00:32 + schrieb Joseph Myers:
> On Tue, 11 Apr 2023, Martin Uecker via Gcc-patches wrote:
> 
> > Ok, here is another attempt on fixing issues with size expression.
> > Not all are regressions, but it does not make sense to try to split
> > it up.
> 
> This wording implies this is version 2 or later of the patch, could you 
> please give a reference to whatever previous patch posting / discussion 
> there may have been?

The previous one was the following for PR107557 and PR108423.

https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611562.html

While revising it I realized that recursing for parameter
when gimplifying is incorrect for the same reason as recursing in
other cases (see the comment in gimplify_type_sizes). This lead
to PR109450.

> 
> > Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, 
> > PR109450]
> 
> 108424 seems to be the wrong PR number.

This should be: PR108423


Martin





Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]

2023-04-11 Thread Martin Uecker via Gcc-patches



Ok, here is another attempt on fixing issues with size expression.
Not all are regressions, but it does not make sense to try to split
it up.

Martin



Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, 
PR109450]

Size expressions were sometimes lost and not gimplified correctly, 
leading to
ICEs and incorrect evaluation order.  Fix this by 1) not recursing into
pointers when gimplifying parameters in the middle-end (the code is 
merged with
gimplify_type_sizes), which is incorrect because it might access 
variables
declared later for incomplete structs, and 2) tracking size expressions 
for
struct/union members correctly, 3) emitting code to evaluate size 
expressions
for missing cases (nested functions, empty declarations, and 
structs/unions).

PR c/106465
PR c/107557
PR c/108423
PR c/109450

gcc/
* c/c-decl.cc (start_decl): Make sure size expression are
evaluated only in correct context.
(grokdeclarator): Size expression in fields may need a bind
expression, make sure DECL_EXPR is always created.
(grokfield, declspecs_add_type): Pass along size expressions.
(finish_struct): Remove unneeded DECL_EXPR.
(start_function): Evaluate size expressions for nested functions.
* c/c-parser.cc (c_parser_struct_declarations,
c_parser_struct_or_union_specifier): Pass along size expressions.
(c_parser_declaration_or_fndef): Evaluate size expression.
(c_parser_objc_at_property_declaration,
c_parser_objc_class_instance_variables): Adapt.
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_parm_sizes.
* gimplify.cc (gimplify_type_sizes): Make function static.
(gimplify_parm_sizes): New function.

gcc/testsuite/
* gcc.dg/nested-vla-1.c: New test.
* gcc.dg/nested-vla-2.c: New test.
* gcc.dg/nested-vla-3.c: New test.
* gcc.dg/pr106465.c: New test.
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.
* gcc.dg/pr108423-6.c: New test.
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/typename-vla-2.c: New test.
* gcc.dg/typename-vla-3.c: New test.
* gcc.dg/typename-vla-4.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e537d33f398..c76cbb3115f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5371,7 +5371,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))
@@ -7500,7 +7501,8 @@ grokdeclarator (const struct c_declarator *declarator,
&& c_type_variably_modified_p (type))
  {
tree bind = NULL_TREE;
-   if (decl_context == TYPENAME || decl_context == PARM)
+   if (decl_context == TYPENAME || decl_context == PARM
+   || decl_context == FIELD)
  {
bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
   NULL_TREE, NULL_TREE);
@@ -7509,10 +7511,9 @@ grokdeclarator (const struct c_declarator *declarator,
push_scope ();
  }
tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-   DECL_ARTIFICIAL (decl) = 1;
-   pushdecl (decl);
-   finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE);
+   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, 
decl));
TYPE_NAME (type) = decl;
+
if (bind)
  {
pop_scope ();
@@ -8711,7 +8712,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 tree
 grokfield (location_t loc,
   struct c_declarator *declarator, struct c_declspecs *declspecs,
-  tree width, tree *decl_attrs)
+  tree width, tree *decl_attrs, tree *expr)
 {
   tree value;
 
@@ -8768,7 +8769,7 @@ grokfield (location_t loc,
 }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
- width ?  : NULL, decl_attrs, NULL, NULL,
+ width ?  : NULL, decl_attrs, expr, NULL,
  DEPRECATED_NORMAL);
 
   finish_decl (value, loc, NULL_TREE, 

Re: [PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-04-05 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 04.04.2023 um 19:31 -0600 schrieb Jeff Law:
> 
> On 4/3/23 13:34, Martin Uecker via Gcc-patches wrote:
> > 
> > 
> > With the relatively new warnings (11..) affecting VLA bounds,
> > I now get a lot of false positives with -Wall. In general, I find
> > the new warnings very useful, but they seem a bit too
> > aggressive and some minor tweaks are needed, otherwise they are
> > too noisy.  This patch suggests two changes:
> > 
> > 1. For VLA bounds non-null is implied only when 'static' is
> > used (similar to clang) and not already when a bound > 0 is
> > specified:
> > 
> > int foo(int n, char buf[static n]);
> > 
> > int foo(10, 0); // warning with 'static' but not without.
> > 
> > 
> > (It also seems problematic to require a size of 0 to indicate
> > that the pointer may be null, because 0 is not allowed in
> > ISO C as a size. It is also inconsistent to how arrays with
> > static bound behave.)
> > 
> > There seems to be agreement about this change in PR98541.
> > 
> > 
> > 2. GCC always warns when the number of unspecified
> > bounds is different between two declarations:
> > 
> > int foo(int n, char buf[*]);
> > int foo(int n, char buf[n]);
> > 
> > or
> > 
> > int foo(int n, char buf[n]);
> > int foo(int n, char buf[*]);
> > 
> > But the first version is useful if the size expression
> > can not be specified in a header (e.g. because it uses
> > a macro or variable not available there) and there is
> > currently no easy way to avoid this.  The warning for
> > both cases was by design,  but I suggest to limit the
> > warning to the second case.
> > 
> > Note that the logic currently applied by GCC is too
> > simplistic anyway, as GCC does not warn for
> > 
> > int foo(int x, int y, double m[*][y]);
> > int foo(int x, int y, double m[x][*]);
> > 
> > because the number of specified / unspecified bounds
> > is the same.  So I suggest to go with the attached
> > patch now and add  more precise warnings later
> > if there is more experience with these warning
> > in gernal and if this then still seems desirable.
> > 
> > 
> > Martin
> > 
> > 
> >  Less warnings for parameters declared as arrays [PR98541, PR98536]
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  To avoid false positivies, tune the warnings for parameters declared
> >  as arrays with size expressions.  Only warn about null arguments with
> >  'static'.  Also do not warn when more bounds are specified in the new
> >  declaration than before.
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  PR c/98541
> >  PR c/98536
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  c-family/
> >  * c-warn.cc (warn_parm_array_mismatch): Do not warn if more
> >  bounds are specified.
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  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.
> >  * gcc.dg/Wvla-parameter-4.c: Adapt test.
> >  * gcc.dg/attr-access-2.c: Adapt test.
> Neither appears to be a regression.  Seems like it should defer to gcc-14.

The false positives are a regression relative to earlier version of GCC
because the warnings are completely new (since GCC 11).   I could bring
this back later, but this means there is another version of GCC where 
one might need to turn off these warnings.  My concern is also that
an otherwise very useful feature that brings some safety benefits gets
underused. 

Martin






[PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-04-03 Thread Martin Uecker via Gcc-patches



With the relatively new warnings (11..) affecting VLA bounds,
I now get a lot of false positives with -Wall. In general, I find
the new warnings very useful, but they seem a bit too
aggressive and some minor tweaks are needed, otherwise they are
too noisy.  This patch suggests two changes:

1. For VLA bounds non-null is implied only when 'static' is
used (similar to clang) and not already when a bound > 0 is
specified:

int foo(int n, char buf[static n]);

int foo(10, 0); // warning with 'static' but not without.


(It also seems problematic to require a size of 0 to indicate 
that the pointer may be null, because 0 is not allowed in
ISO C as a size. It is also inconsistent to how arrays with
static bound behave.) 

There seems to be agreement about this change in PR98541.


2. GCC always warns when the number of unspecified
bounds is different between two declarations:

int foo(int n, char buf[*]);
int foo(int n, char buf[n]);

or

int foo(int n, char buf[n]);
int foo(int n, char buf[*]);

But the first version is useful if the size expression
can not be specified in a header (e.g. because it uses
a macro or variable not available there) and there is
currently no easy way to avoid this.  The warning for
both cases was by design,  but I suggest to limit the
warning to the second case. 

Note that the logic currently applied by GCC is too
simplistic anyway, as GCC does not warn for

int foo(int x, int y, double m[*][y]);
int foo(int x, int y, double m[x][*]);

because the number of specified / unspecified bounds
is the same.  So I suggest to go with the attached
patch now and add  more precise warnings later
if there is more experience with these warning 
in gernal and if this then still seems desirable.


Martin


Less warnings for parameters declared as arrays [PR98541, PR98536]

To avoid false positivies, tune the warnings for parameters declared
as arrays with size expressions.  Only warn about null arguments with
'static'.  Also do not warn when more bounds are specified in the new
declaration than before.

PR c/98541
PR c/98536

c-family/
* c-warn.cc (warn_parm_array_mismatch): Do not warn if more
bounds are specified.

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.
* gcc.dg/Wvla-parameter-4.c: Adapt test.
* gcc.dg/attr-access-2.c: Adapt test.


diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 9ac43a1af6e..f79fb876142 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3599,23 +3599,13 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
  continue;
}
 
- if (newunspec != curunspec)
+ if (newunspec > curunspec)
{
  location_t warnloc = newloc, noteloc = origloc;
  const char *warnparmstr = newparmstr.c_str ();
  const char *noteparmstr = curparmstr.c_str ();
  unsigned warnunspec = newunspec, noteunspec = curunspec;
 
- if (newunspec < curunspec)
-   {
- /* If the new declaration has fewer unspecified bounds
-point the warning to the previous declaration to make
-it clear that that's the one to change.  Otherwise,
-point it to the new decl.  */
- std::swap (warnloc, noteloc);
- std::swap (warnparmstr, noteparmstr);
- std::swap (warnunspec, noteunspec);
-   }
  if (warning_n (warnloc, OPT_Wvla_parameter, warnunspec,
 "argument %u of type %s declared with "
 "%u unspecified variable bound",
@@ -3641,16 +3631,11 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
  continue;
}
}
-
   /* Iterate over the lists of VLA variable bounds, comparing each
-pair for equality, and diagnosing mismatches.  The case of
-the lists having different lengths is handled above so at
-this point they do .  */
-  for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
+pair for equality, and diagnosing mismatches.  */
+  for (tree newvbl = newa->size, curvbl = cura->size; newvbl && curvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
- gcc_assert (curvbl);
-
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
@@ -3663,7 +3648,6 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   and both are the same 

Re: [PATCH] gimplify size expressions in parameters for all types [PR107557] [PR108423]

2023-02-21 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 21.02.2023 um 14:21 + schrieb Richard Biener:
> On Tue, 21 Feb 2023, Martin Uecker wrote:
> 
> > 
> > 
> > Hi Richard,
> > 
> > can you look at this middle-end patch? It fixes two regressions.
> 
> But gimplify_type_sizes recurses itself, but in particular _not_
> for pointer types.  Iff recursing in parameter context is
> necessary and safe I'd rather have gimplify_type_sizes know that
> (bool for_param_p?) and do the recursion?
> 

I just want to point out that without the patch
gimplify_parm_sizes already does the recursion
into pointers  types. But other types are also
not reached. But maybe there was never a good
reason for this split?

I will try merging this all into gimplify_type_sizes.

Martin


> Richard.
> 
> > Martin
> > 
> > 
> > PS: I happy to do something about at variably_modified_type_p 
> > in the middle-end, if you have a recommendation.
> > 
> > 
> > 
> > 
> > Am Mittwoch, dem 08.02.2023 um 13:02 +0100 schrieb Martin Uecker:
> > > 
> > > Here is a fix for PR107557 and PR108423.
> > > 
> > > 
> > > Bootstrapped and regression tested on x86-64.
> > > 
> > > 
> > > 
> > > Gimplify more size expression in parameters [PR107557] and [PR108234]
> > > 
> > > 
> > > gimplify_parm_type only recursives into pointer type and
> > > size expressions in other types (e.g. function types) were
> > > not reached.
> > > 
> > > 
> > > PR c/107557
> > > PR c/108234
> > > 
> > > 
> > > gcc/Changelog
> > > * gcc/function.cc (gimplify_parm_type): Also recursive into
> > > non-pointer types.
> > > 
> > > 
> > > gcc/testsuite/ChangeLog:
> > > * gcc.dg/pr107557-1.c: New test.
> > > * gcc.dg/pr107557-2.c: New test.
> > > * gcc.dg/pr108423-1.c: New test.
> > > * gcc.dg/pr108423-2.c: New test.
> > > * gcc.dg/pr108423-3.c: New test.
> > > * gcc.dg/pr108423-4.c: New test.
> > > * gcc.dg/pr108423-5.c: New test.
> > > 
> > > 
> > > 
> > > 
> > > diff --git a/gcc/function.cc b/gcc/function.cc
> > > index cfc4d2f74af..d777348aeb4 100644
> > > --- a/gcc/function.cc
> > > +++ b/gcc/function.cc
> > > @@ -3880,20 +3880,15 @@ static tree
> > >  gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
> > >  {
> > >    tree t = *tp;
> > > -
> > >    *walk_subtrees = 0;
> > >    if (TYPE_P (t))
> > >  {
> > > -  if (POINTER_TYPE_P (t))
> > > - *walk_subtrees = 1;
> > > -  else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
> > > +  if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
> > >  && !TYPE_SIZES_GIMPLIFIED (t))
> > > - {
> > > -   gimplify_type_sizes (t, (gimple_seq *) data);
> > > -   *walk_subtrees = 1;
> > > - }
> > > -}
> > > + gimplify_type_sizes (t, (gimple_seq *) data);
> > >  
> > > 
> > > +  *walk_subtrees = 1;
> > > +}
> > >    return NULL;
> > >  }
> > >  
> > > 
> > > diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c 
> > > b/gcc/testsuite/gcc.dg/pr107557-1.c
> > > new file mode 100644
> > > index 000..88c248b6564
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.dg/pr107557-1.c
> > > @@ -0,0 +1,24 @@
> > > +/* PR107557
> > > + * { dg-do compile }
> > > + * { dg-options "-flto -fsanitize=undefined -fexceptions 
> > > -Wno-incompatible-pointer-types" }
> > > + */
> > > +
> > > +
> > > +int c[1][3*2];
> > > +int f(int * const m, int (**v)[*m * 2])
> > > +{
> > > + return &(c[0][*m]) == &((*v)[0][*m]);
> > > +}
> > > +int test(int n, int (*(*fn)(void))[n])
> > > +{
> > > + return (*fn())[0];
> > > +}
> > > +int main()
> > > +{
> > > + int m = 3;
> > > + int (*d)[3*2] = c;
> > > + int (*fn[m])(void);
> > > + return f(, ) + test(m, );
> > > +}
> > > +
> > > +
> > > diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c 
> > > b/gcc/testsuite/gcc.dg/pr107557-2.c
> > > new file mode 100644
> > > index 

Re: [PATCH] gimplify size expressions in parameters for all types [PR107557] [PR108423]

2023-02-21 Thread Martin Uecker via Gcc-patches



Hi Richard,

can you look at this middle-end patch? It fixes two regressions.

Martin


PS: I happy to do something about at variably_modified_type_p 
in the middle-end, if you have a recommendation.




Am Mittwoch, dem 08.02.2023 um 13:02 +0100 schrieb Martin Uecker:
> 
> Here is a fix for PR107557 and PR108423.
> 
> 
> Bootstrapped and regression tested on x86-64.
> 
> 
> 
> Gimplify more size expression in parameters [PR107557] and [PR108234]
> 
> 
> gimplify_parm_type only recursives into pointer type and
> size expressions in other types (e.g. function types) were
> not reached.
> 
> 
> PR c/107557
> PR c/108234
> 
> 
> gcc/Changelog
> * gcc/function.cc (gimplify_parm_type): Also recursive into
> non-pointer types.
> 
> 
> gcc/testsuite/ChangeLog:
> * gcc.dg/pr107557-1.c: New test.
> * gcc.dg/pr107557-2.c: New test.
> * gcc.dg/pr108423-1.c: New test.
> * gcc.dg/pr108423-2.c: New test.
> * gcc.dg/pr108423-3.c: New test.
> * gcc.dg/pr108423-4.c: New test.
> * gcc.dg/pr108423-5.c: New test.
> 
> 
> 
> 
> diff --git a/gcc/function.cc b/gcc/function.cc
> index cfc4d2f74af..d777348aeb4 100644
> --- a/gcc/function.cc
> +++ b/gcc/function.cc
> @@ -3880,20 +3880,15 @@ static tree
>  gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
>  {
>    tree t = *tp;
> -
>    *walk_subtrees = 0;
>    if (TYPE_P (t))
>  {
> -  if (POINTER_TYPE_P (t))
> - *walk_subtrees = 1;
> -  else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
> +  if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
>  && !TYPE_SIZES_GIMPLIFIED (t))
> - {
> -   gimplify_type_sizes (t, (gimple_seq *) data);
> -   *walk_subtrees = 1;
> - }
> -}
> + gimplify_type_sizes (t, (gimple_seq *) data);
>  
> 
> +  *walk_subtrees = 1;
> +}
>    return NULL;
>  }
>  
> 
> diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c 
> b/gcc/testsuite/gcc.dg/pr107557-1.c
> new file mode 100644
> index 000..88c248b6564
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr107557-1.c
> @@ -0,0 +1,24 @@
> +/* PR107557
> + * { dg-do compile }
> + * { dg-options "-flto -fsanitize=undefined -fexceptions 
> -Wno-incompatible-pointer-types" }
> + */
> +
> +
> +int c[1][3*2];
> +int f(int * const m, int (**v)[*m * 2])
> +{
> + return &(c[0][*m]) == &((*v)[0][*m]);
> +}
> +int test(int n, int (*(*fn)(void))[n])
> +{
> + return (*fn())[0];
> +}
> +int main()
> +{
> + int m = 3;
> + int (*d)[3*2] = c;
> + int (*fn[m])(void);
> + return f(, ) + test(m, );
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c 
> b/gcc/testsuite/gcc.dg/pr107557-2.c
> new file mode 100644
> index 000..2d26bb0b16a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr107557-2.c
> @@ -0,0 +1,23 @@
> +/* PR107557
> + * { dg-do compile }
> + * { dg-options "-flto -fsanitize=undefined -fexceptions 
> -Wno-incompatible-pointer-types" }
> + */
> +
> +
> +int c[1][3*2];
> +int f(int * const m, int (**(*v))[*m * 2])
> +{
> + return &(c[0][*m]) == &((*v)[0][*m]);   /* { dg-warning "lacks a cast" 
> } */
> +}
> +int test(int n, int (*(*(*fn))(void))[n])
> +{
> + return (*(*fn)())[0];
> +}
> +int main()
> +{
> + int m = 3;
> + int (*d)[3*2] = c;
> + int (*fn[m])(void);
> + return f(, ) + test(m, );
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/pr108423-1.c 
> b/gcc/testsuite/gcc.dg/pr108423-1.c
> new file mode 100644
> index 000..0c98d1d46b9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr108423-1.c
> @@ -0,0 +1,16 @@
> +/* PR108423
> + * { dg-do compile }
> + * { dg-options "-O2 -Wno-int-conversion -Wno-incompatible-pointer-types" }
> + */
> +int f (int n, int (**(*a)(void))[n])
> +{
> + return (*a())[0];
> +}
> +int g ()
> +{
> + int m = 3;
> + int (*a[m])(void);
> + return f(m, );
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/pr108423-2.c 
> b/gcc/testsuite/gcc.dg/pr108423-2.c
> new file mode 100644
> index 000..006e45a9629
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr108423-2.c
> @@ -0,0 +1,16 @@
> +/* PR108423
> + * { dg-do compile }
> + * { dg-options "-O2" }
> + */
> +
> +void f(int n, int (*a(void))[n])
> +{
> + (a())[0];
> +}
> +
> +void g(void)
> +{
> + int (*a(void

[C PATCH] Detect all variably modified types [PR108375]

2023-02-17 Thread Martin Uecker via Gcc-patches



Here is a patch for PR108375.

Bootstrapped and regession tested on x86_64-linux-gnu


Also there is a middle-end patch for PR107557 and PR108423:
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611562.html
and another C FE patch for PR105660:
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611817.html

All regressions.



C: Detect all variably modified types [PR108375]

Some variably modified types were not detected correctly.
Define C_TYPE_VARIABLY_MODIFIED via TYPE_LANG_FLAG 6 in the CFE.
This flag records whether a type is variably modified and is
set for all such types including arrays with variably modified
element type or structures and unions with variably modified
members. This is then used to detect such types in the C FE
and middle-end (via the existing language hook).

PR 108375

gcc/c/

* c/c-decl.c (decl_jump_unsafe): Use c_type_variably_modified_p.
(diagnose_mismatched_decl): Dito.
(warn_about_goto): Dito:
(c_check_switch_jump_warnings): Dito.
(finish_decl): Dito.
(finish_struct): Dito.
(grokdeclarator): Set C_TYPE_VARIABLY_MODIFIED.
(finish_struct): Set C_TYPE_VARIABLY_MODIFIED.
* c/c-objc-common.cc (c_var_mod_p): New function.
(c_var_unspec_p): Remove.
* c/c-objc-common.h: Set lang hook.
* c/c-parser.cc (c_parser_declararion_or_fndef): Use 
c_type_variably_modified_p.
(c_parser_typeof_specifier): Dito.
(c_parser_has_attribute_expression): Dito.
(c_parser_generic_selection): Dito.
* c/c-tree.h: Define C_TYPE_VARIABLY_MODIFIED and define 
c_var_mode_p.
* c/c-typeck.h: Remove c_vla_mod_p and use C_TYPE_VARIABLY_MODIFIED.

gcc/testsuite/

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


diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 20e7d1855bf..08078eadeb8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -683,7 +683,7 @@ decl_jump_unsafe (tree decl)
 
   /* Always warn about crossing variably modified types.  */
   if ((VAR_P (decl) || TREE_CODE (decl) == TYPE_DECL)
-  && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+  && c_type_variably_modified_p (TREE_TYPE (decl)))
 return true;
 
   /* Otherwise, only warn if -Wgoto-misses-init and this is an
@@ -2247,7 +2247,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  || warning_suppressed_p (olddecl, OPT_Wpedantic))
return true;  /* Allow OLDDECL to continue in use.  */
 
-  if (variably_modified_type_p (newtype, NULL))
+  if (c_type_variably_modified_p (newtype))
{
  error ("redefinition of typedef %q+D with variably modified type",
 newdecl);
@@ -3975,7 +3975,7 @@ static void
 warn_about_goto (location_t goto_loc, tree label, tree decl)
 {
   auto_diagnostic_group d;
-  if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+  if (c_type_variably_modified_p (TREE_TYPE (decl)))
 error_at (goto_loc,
  "jump into scope of identifier with variably modified type");
   else
@@ -4249,7 +4249,7 @@ c_check_switch_jump_warnings (struct c_spot_bindings 
*switch_bindings,
{
  auto_diagnostic_group d;
  bool emitted;
- if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE))
+ if (c_type_variably_modified_p (TREE_TYPE (b->decl)))
{
  saw_error = true;
  error_at (case_loc,
@@ -5862,7 +5862,7 @@ finish_decl (tree decl, location_t init_loc, tree init,
   if (TREE_CODE (decl) == TYPE_DECL)
 {
   if (!DECL_FILE_SCOPE_P (decl)
- && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+ && c_type_variably_modified_p (TREE_TYPE (decl)))
add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
 
   rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
@@ -6682,7 +6682,7 @@ grokdeclarator (const struct c_declarator *declarator,
 
   if ((decl_context == NORMAL || decl_context == FIELD)
   && current_scope == file_scope
-  && variably_modified_type_p (type, NULL_TREE))
+  && c_type_variably_modified_p (type))
 {
   if (name)
error_at (loc, "variably modified %qE at file scope", name);
@@ -6928,6 +6928,8 @@ grokdeclarator (const struct c_declarator *declarator,
  array_parm_static = false;
}
 
+  bool varmod = C_TYPE_VARIABLY_MODIFIED (type);
+
   switch (declarator->kind)
{
case cdk_attrs:
@@ -7282,8 +7284,7 @@ grokdeclarator (const struct c_declarator *declarator,
   variable size, so the enclosing shared array type
   must too.  */
if (size && TREE_CODE (size) == INTEGER_CST)
- type
- 

[C PATCH] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-02-12 Thread Martin Uecker via Gcc-patches


Here is a fix for PR105660.

Bootstrapped and regression tested on x86-64.


Fix ICE related to implicit access attributes for VLA arguments [PR105660]

When constructing the specifier string when merging an access attribute
that encodes information about VLA arguments, the string was constructed
in random order by iterating through a hash table. Fix this by iterating
though the list of arguments.

PR c/105660

gcc/Changelog
* c-family/c-attribs.cc (append_access_attr): Use order
of arguments when construction string.
(append_access_attr_idxs): Rename and make static.
* c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.

gcc/testsuite/ChangeLog:
* gcc.dg/pr105660-1.c: New test.
* gcc.dg/pr105660-2.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 4667f6de311..072cfb69147 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
char *attrstr,
   rdwr_map cur_idxs;
   init_attr_rdwr_indices (_idxs, attrs);
 
+  tree args = TYPE_ARG_TYPES (node[0]);
+  int argpos = 0;
   std::string spec;
-  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
+  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
 {
-  const auto  = *it;
+  const attr_access* const newa = new_idxs.get (argpos);
+
+  if (!newa)
+   continue;
 
   /* The map has two equal entries for each pointer argument that
 has an associated size argument.  Process just the entry for
 the former.  */
-  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
+  if ((unsigned)argpos != newa->ptrarg)
continue;
 
-  const attr_access* const cura = cur_idxs.get (newaxsref.first);
+  const attr_access* const cura = cur_idxs.get (argpos);
   if (!cura)
{
  /* The new attribute needs to be added.  */
- tree str = newaxsref.second.to_internal_string ();
+ tree str = newa->to_internal_string ();
  spec += TREE_STRING_POINTER (str);
  continue;
}
@@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
   /* The new access spec refers to an array/pointer argument for
 which an access spec already exists.  Check and diagnose any
 conflicts.  If no conflicts are found, merge the two.  */
-  const attr_access* const newa = 
 
   if (!attrstr)
{
@@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
continue;
 
   /* Merge the CURA and NEWA.  */
-  attr_access merged = newaxsref.second;
+  attr_access merged = *newa;
 
   /* VLA seen in a declaration takes precedence.  */
   if (cura->minsize == HOST_WIDE_INT_M1U)
@@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
 
 /* Convenience wrapper for the above.  */
 
-tree
-append_access_attr (tree node[3], tree attrs, const char *attrstr,
-   char code, HOST_WIDE_INT idxs[2])
+static tree
+append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
+char code, HOST_WIDE_INT idxs[2])
 {
   char attrspec[80];
   int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
@@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
  attributes specified on previous declarations of the same type
  and if not, concatenate the two.  */
   const char code = attr_access::mode_chars[mode];
-  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
 return NULL_TREE;
 
@@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
 {
   /* Repeat for the previously declared type.  */
   attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
-  new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
return NULL_TREE;
 
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 29efce3f2c0..a6fb95b1e80 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3617,6 +3617,8 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
+ gcc_assert (curvbl);
+
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/pr105660-1.c 
b/gcc/testsuite/gcc.dg/pr105660-1.c
new file mode 100644
index 000..d4454f04c43
--- /dev/null
+++ 

[PATCH] gimplify size expressions in parameters for all types [PR107557] [PR108423]

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



Here is a fix for PR107557 and PR108423.


Bootstrapped and regression tested on x86-64.



Gimplify more size expression in parameters [PR107557] and [PR108234]

gimplify_parm_type only recursives into pointer type and
size expressions in other types (e.g. function types) were
not reached.

PR c/107557
PR c/108234

gcc/Changelog
* gcc/function.cc (gimplify_parm_type): Also recursive into
non-pointer types.

gcc/testsuite/ChangeLog:
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.




diff --git a/gcc/function.cc b/gcc/function.cc
index cfc4d2f74af..d777348aeb4 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -3880,20 +3880,15 @@ static tree
 gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
 {
   tree t = *tp;
-
   *walk_subtrees = 0;
   if (TYPE_P (t))
 {
-  if (POINTER_TYPE_P (t))
-   *walk_subtrees = 1;
-  else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
+  if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
   && !TYPE_SIZES_GIMPLIFIED (t))
-   {
- gimplify_type_sizes (t, (gimple_seq *) data);
- *walk_subtrees = 1;
-   }
-}
+   gimplify_type_sizes (t, (gimple_seq *) data);
 
+  *walk_subtrees = 1;
+}
   return NULL;
 }
 
diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c 
b/gcc/testsuite/gcc.dg/pr107557-1.c
new file mode 100644
index 000..88c248b6564
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr107557-1.c
@@ -0,0 +1,24 @@
+/* PR107557
+ * { dg-do compile }
+ * { dg-options "-flto -fsanitize=undefined -fexceptions 
-Wno-incompatible-pointer-types" }
+ */
+
+
+int c[1][3*2];
+int f(int * const m, int (**v)[*m * 2])
+{
+   return &(c[0][*m]) == &((*v)[0][*m]);
+}
+int test(int n, int (*(*fn)(void))[n])
+{
+   return (*fn())[0];
+}
+int main()
+{
+   int m = 3;
+   int (*d)[3*2] = c;
+   int (*fn[m])(void);
+   return f(, ) + test(m, );
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c 
b/gcc/testsuite/gcc.dg/pr107557-2.c
new file mode 100644
index 000..2d26bb0b16a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr107557-2.c
@@ -0,0 +1,23 @@
+/* PR107557
+ * { dg-do compile }
+ * { dg-options "-flto -fsanitize=undefined -fexceptions 
-Wno-incompatible-pointer-types" }
+ */
+
+
+int c[1][3*2];
+int f(int * const m, int (**(*v))[*m * 2])
+{
+   return &(c[0][*m]) == &((*v)[0][*m]);   /* { dg-warning "lacks a cast" 
} */
+}
+int test(int n, int (*(*(*fn))(void))[n])
+{
+   return (*(*fn)())[0];
+}
+int main()
+{
+   int m = 3;
+   int (*d)[3*2] = c;
+   int (*fn[m])(void);
+   return f(, ) + test(m, );
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-1.c 
b/gcc/testsuite/gcc.dg/pr108423-1.c
new file mode 100644
index 000..0c98d1d46b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-1.c
@@ -0,0 +1,16 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2 -Wno-int-conversion -Wno-incompatible-pointer-types" }
+ */
+int f (int n, int (**(*a)(void))[n])
+{
+   return (*a())[0];
+}
+int g ()
+{
+   int m = 3;
+   int (*a[m])(void);
+   return f(m, );
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-2.c 
b/gcc/testsuite/gcc.dg/pr108423-2.c
new file mode 100644
index 000..006e45a9629
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-2.c
@@ -0,0 +1,16 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*a(void))[n])
+{
+   (a())[0];
+}
+
+void g(void)
+{
+   int (*a(void))[1];
+   f(1, a);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-3.c 
b/gcc/testsuite/gcc.dg/pr108423-3.c
new file mode 100644
index 000..c1987c42b40
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-3.c
@@ -0,0 +1,17 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*(*b)(void))[n])
+{
+sizeof (*(*b)());
+}
+
+int (*a(void))[1];
+
+void g(void)
+{
+   f(1, );
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-4.c 
b/gcc/testsuite/gcc.dg/pr108423-4.c
new file mode 100644
index 000..91336f3f283
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-4.c
@@ -0,0 +1,17 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*a(void))[n])
+{
+sizeof (*a());
+}
+
+int (*a(void))[1];
+
+void g(void)
+{
+   f(1, a);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-5.c 
b/gcc/testsuite/gcc.dg/pr108423-5.c
new file mode 100644
index 000..7e4fffb2870
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-5.c
@@ -0,0 +1,17 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*(*a)(void))[n])
+{
+sizeof ((*a)());
+}
+
+int (*a(void))[1];
+

[PATCH] regression tests for 103770 fixed on trunk

2022-12-22 Thread Martin Uecker via Gcc-patches


This adds regression tests for an ICE on valid code that
seems gone on trunk, but the cause is still unclear.

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



regressions tests for PR103770

This adds tests from bugzilla for PR103770 and duplicates.

testsuite/gcc.dg/
* pr103770.c: New test.
* pr103859.c: New test.
* pr105065.c: New test.


diff --git a/gcc/testsuite/gcc.dg/pr103770.c b/gcc/testsuite/gcc.dg/pr103770.c
new file mode 100644
index 000..f7867d1284c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr103770.c
@@ -0,0 +1,27 @@
+/* PR middle-end/103770 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct struct_s {
+   void* ptr;
+   void* ptr2;
+   void* ptr3;
+};
+
+struct struct_s struct_create(int N, const long vla[N]);
+
+void fun(int N)
+{
+   long vla[N];
+   struct struct_s st = struct_create(N, vla);
+}
+
+
+extern _Complex float g(int N, int dims[N]);
+
+void f(void)
+{
+   int dims[1];
+   _Complex float val = g(1, dims);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr103859.c b/gcc/testsuite/gcc.dg/pr103859.c
new file mode 100644
index 000..c58be5c15af
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr103859.c
@@ -0,0 +1,23 @@
+/* PR middle-end/103859 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef struct dcmplx dcmplx;
+
+struct dcmplx {
+  double re;
+  double im;
+};
+
+dcmplx horner(int n, dcmplx p[n], dcmplx x);
+
+int main(void)
+{
+  int i, n;
+  dcmplx x[n + 1], f[n + 1];
+
+  horner(n + 1, f, x[i]);
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr105065.c b/gcc/testsuite/gcc.dg/pr105065.c
new file mode 100644
index 000..da46d2bb4d8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr105065.c
@@ -0,0 +1,16 @@
+/* PR middle-end/105065 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef struct
+{
+   char filler[17];
+} big_struct;
+
+big_struct dummy(int size, char array[size]);
+
+int main()
+{
+   dummy(0, 0);
+}
+




[C PATCH] (for STAGE 1) UBSan instrumentation for assignment of VM types

2022-12-22 Thread Martin Uecker via Gcc-patches


Here is a first patch to add UBSan instrumentation to
assignment, return, initialization of pointers
to variably modified types. This is based on the
other patch I just sent. Separating these should make
reviewing easier.

Here, I did not add tests for function arguments as
this is more complicated, but this will follow...




c: UBSan instrumentation for assignment of VM types

This adds instrumentation that checks that corresponding
size expression in variably modified types evaluate to
the same value in assignment, function return, and
initialization.

gcc/c-family/
* c-ubsan.cc (ubsan_instrument_vm_assign): New.

gcc/c/
* c-typeck.cc (comptypes_check_enum_int_instr,
comptypes_check_enum_int): New interface for
instrumentation.
(comptypes_internal,convert_for_assignment):
Add instrumentation.
(comp_target_types_instr,comp_target_types): Add
new interface for instrumentation.

gcc/testsuite/gcc.dg/ubsan/
* vm-bounds-1.c: New test.
* vm-bounds-2.c: New test.

 

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index 360ba82250c..7de4e6e7057 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -334,6 +334,48 @@ ubsan_instrument_vla (location_t loc, tree size)
   return t;
 }
 
+/* Instrument assignment of variably modified types.  */
+
+tree
+ubsan_instrument_vm_assign (location_t loc, tree a, tree b)
+{
+  tree t, tt;
+
+  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);
+
+  t = build2 (NE_EXPR, boolean_type_node, as, bs);
+  if (flag_sanitize_trap & SANITIZE_VLA)
+tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+{
+  tree data = ubsan_create_data ("__ubsan_vm_data", 1, ,
+ubsan_type_descriptor (a, 
UBSAN_PRINT_ARRAY),
+ubsan_type_descriptor (b, 
UBSAN_PRINT_ARRAY),
+ubsan_type_descriptor (sizetype),
+NULL_TREE, NULL_TREE);
+  data = build_fold_addr_expr_loc (loc, data);
+  enum built_in_function bcode
+   = (flag_sanitize_recover & SANITIZE_VLA)
+ ? BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH
+ : BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH_ABORT;
+  tt = builtin_decl_explicit (bcode);
+  tt = build_call_expr_loc (loc, tt, 3, data,
+   ubsan_encode_value (as),
+   ubsan_encode_value (bs));
+}
+  t = build3 (COND_EXPR, void_type_node, t, tt, void_node);
+
+  return t;
+}
+
+
 /* Instrument missing return in C++ functions returning non-void.  */
 
 tree
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index 2f31ba36df4..327313c6684 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -26,6 +26,7 @@ extern tree ubsan_instrument_shift (location_t, enum 
tree_code, tree, tree);
 extern tree ubsan_instrument_vla (location_t, tree);
 extern tree ubsan_instrument_return (location_t);
 extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
+extern tree ubsan_instrument_vm_assign (location_t, tree, tree);
 extern bool ubsan_array_ref_instrumented_p (const_tree);
 extern void ubsan_maybe_instrument_array_ref (tree *, bool);
 extern void ubsan_maybe_instrument_reference (tree *);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ebc9ba88afe..a58b96083e9 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -93,6 +93,7 @@ static tree qualify_type (tree, tree);
 struct comptypes_data;
 static int tagged_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static int comp_target_types (location_t, tree, tree);
+static int comp_target_types_instr (location_t, tree, tree, tree *);
 static int function_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static int type_lists_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static tree lookup_field (tree, tree);
@@ -1053,6 +1054,9 @@ struct comptypes_data {
 
   bool enum_and_int_p;
   bool different_types_p;
+
+  location_t loc;
+  tree instrument_expr;
 };
 
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
@@ -1075,20 +1079,35 @@ comptypes (tree type1, tree type2)
 /* Like comptypes, but if it returns non-zero because enum and int are
compatible, it sets *ENUM_AND_INT_P to true.  */
 
-int
-comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
+static int
+comptypes_check_enum_int_instr (tree type1, tree type2, bool *enum_and_int_p, 
location_t loc, tree *instrument_expr)
 {
   int val;
 
   struct comptypes_data data = { };
+
+  data.loc = loc;
+
+  if (NULL != instrument_expr)
+   

[C PATCH] (for STAGE 1) Reorganize comptypes and related functions

2022-12-22 Thread Martin Uecker via Gcc-patches




Because I want to add another argument to comptypes
and co. for UBSan instrumentation and this then
starts to become a bit unwiedly, here is a patch to
reorganize and simplify this a bit. This can wait
until stage 1. (The cache can be simplified further
by allocating it on the stack, but this can be done
later).



c: Reorganize comptypes and related functions.

Move common arguments and a global variable (the
cache for type compatibility) used by comptypes
and childen into a single structure and pass a
pointer to it.

gcc/c/ 
* c/c-typeck.cc: (comptypes,comptypes_check_enum_int,
comptypes_check_different_types,comptypes_internal,
tagged_types_tu_compatible_p,function_types_compatible_p,
type_lists_compatible_p): Introduce a structure argument.
(alloc_tagged_tu_seen_cache,free_all_tagged_tu_seen_up_to):
Reorganize cache and remove tu from function names.



diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 47fa36f4ec8..ebc9ba88afe 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -90,12 +90,11 @@ static bool require_constexpr_value;
 
 static bool null_pointer_constant_p (const_tree);
 static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
-bool *);
+struct comptypes_data;
+static int tagged_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static int comp_target_types (location_t, tree, tree);
-static int function_types_compatible_p (const_tree, const_tree, bool *,
-   bool *);
-static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
+static int function_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
+static int type_lists_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec, tree,
  vec *, vec *, tree,
@@ -125,7 +124,7 @@ static tree find_init_member (tree, struct obstack *);
 static void readonly_warning (tree, enum lvalue_use);
 static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *, bool *);
+static int comptypes_internal (const_tree, const_tree, struct comptypes_data 
*data);
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -189,17 +188,16 @@ remove_c_maybe_const_expr (tree expr)
 
 /* This is a cache to hold if two types are compatible or not.  */
 
-struct tagged_tu_seen_cache {
-  const struct tagged_tu_seen_cache * next;
+struct tagged_seen_cache {
+  const struct tagged_seen_cache * next;
   const_tree t1;
   const_tree t2;
-  /* The return value of tagged_types_tu_compatible_p if we had seen
+  /* The return value of tagged_types_compatible_p if we had seen
  these two types already.  */
   int val;
 };
 
-static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
-static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache 
*);
+static void free_all_tagged_seen (const struct tagged_seen_cache *);
 
 /* Do `exp = require_complete_type (loc, exp);' to make sure exp
does not have an incomplete type.  (That includes void types.)
@@ -1049,6 +1047,14 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+struct comptypes_data {
+
+  const struct tagged_seen_cache *seen_base;
+
+  bool enum_and_int_p;
+  bool different_types_p;
+};
+
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations.  Return 2 if they are compatible
but a warning may be needed if you use them together.  */
@@ -1056,11 +1062,12 @@ common_type (tree t1, tree t2)
 int
 comptypes (tree type1, tree type2)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, NULL, NULL);
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, );
+
+  free_all_tagged_seen (data.seen_base);
 
   return val;
 }
@@ -1071,11 +1078,13 @@ comptypes (tree type1, tree type2)
 int
 comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, );
+  *enum_and_int_p = data.enum_and_int_p;
+
+  free_all_tagged_seen (data.seen_base);
 
   return val;
 }
@@ -1087,31 +1096,33 @@ int
 comptypes_check_different_types (tree type1, tree type2,
 bool *different_types_p)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val 

Re: [C PATCH] remove same_translation_unit_p

2022-12-21 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 20.12.2022 um 20:04 + schrieb Joseph Myers:
> On Tue, 20 Dec 2022, Martin Uecker via Gcc-patches wrote:
> 
> > Here is a patch to remove the unused function
> > same_translation_unit_p and related code. The
> > code to check for structural equivalency of
> > structs / unions is kept (with some fixes)
> > because it will be needed for C2X.
> 
> Could you repost this in development stage 1, since this is not a bug
> fix?

Sure, I will repost for stage 1.

I plan to send some other similar patches with
no functional change (with no expectation that they
get reviewed now) because I like to get some early
feedback rom Martin Liška on some UBsan changes
which are layered on top of them.


Martin






[C PATCH] remove same_translation_unit_p

2022-12-20 Thread Martin Uecker via Gcc-patches


Here is a patch to remove the unused function
same_translation_unit_p and related code. The
code to check for structural equivalency of
structs / unions is kept (with some fixes)
because it will be needed for C2X.



c: Remove dead code related to type compatibility across TUs. 

Code to detect struct/unions across the same TU is not needed
anymore. Code for determining compatibility of tagged types is
preserved as it will be used for C2X. Some errors in the unused
code are fixed.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c/
* c-decl.cc (set_type_context): Remove.
(pop_scope, diagnose_mismatched_decls, pushdecl):
Remove dead code.
* c-typeck.cc (comptypes_internal): Remove dead code.
(same_translation_unit_p): Remove.
(tagged_types_tu_compatible_p): Some fixes.




diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e47ca6718b3..307f7a09f5a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -1155,16 +1155,6 @@ update_label_decls (struct c_scope *scope)
 }
 }
 
-/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT.  */
-
-static void
-set_type_context (tree type, tree context)
-{
-  for (type = TYPE_MAIN_VARIANT (type); type;
-   type = TYPE_NEXT_VARIANT (type))
-TYPE_CONTEXT (type) = context;
-}
-
 /* Exit a scope.  Restore the state of the identifier-decl mappings
that were in effect when this scope was entered.  Return a BLOCK
node containing all the DECLs in this scope that are of interest
@@ -1253,7 +1243,6 @@ pop_scope (void)
case ENUMERAL_TYPE:
case UNION_TYPE:
case RECORD_TYPE:
- set_type_context (p, context);
 
  /* Types may not have tag-names, in which case the type
 appears in the bindings list with b->id NULL.  */
@@ -1361,12 +1350,7 @@ pop_scope (void)
 the TRANSLATION_UNIT_DECL.  This makes
same_translation_unit_p
 work.  */
  if (scope == file_scope)
-   {
  DECL_CONTEXT (p) = context;
- if (TREE_CODE (p) == TYPE_DECL
- && TREE_TYPE (p) != error_mark_node)
-   set_type_context (TREE_TYPE (p), context);
-   }
 
  gcc_fallthrough ();
  /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
@@ -2308,21 +2292,18 @@ diagnose_mismatched_decls (tree newdecl, tree
olddecl,
{
  if (DECL_INITIAL (olddecl))
{
- /* If both decls are in the same TU and the new
declaration
-isn't overriding an extern inline reject the new
decl.
-In c99, no overriding is allowed in the same
translation
-unit.  */
- if ((!DECL_EXTERN_INLINE (olddecl)
-  || DECL_EXTERN_INLINE (newdecl)
-  || (!flag_gnu89_inline
-  && (!DECL_DECLARED_INLINE_P (olddecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES
(olddecl)))
-  && (!DECL_DECLARED_INLINE_P (newdecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES
(newdecl
- )
- && same_translation_unit_p (newdecl, olddecl))
+ /* If the new declaration isn't overriding an extern
inline
+reject the new decl. In c99, no overriding is allowed
+in the same translation unit.  */
+ if (!DECL_EXTERN_INLINE (olddecl)
+ || DECL_EXTERN_INLINE (newdecl)
+ || (!flag_gnu89_inline
+ && (!DECL_DECLARED_INLINE_P (olddecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES
(olddecl)))
+ && (!DECL_DECLARED_INLINE_P (newdecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES
(newdecl)
{
  auto_diagnostic_group d;
  error ("redefinition of %q+D", newdecl);
@@ -3350,18 +3331,11 @@ pushdecl (tree x)
 type to the composite of all the types of that declaration.
 After the consistency checks, it will be reset to the
 composite of the visible types only.  */
-  if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b-
>decl))
- && b->u.type)
+  if (b && b->u.type)
TREE_TYPE (b->decl) = b->u.type;
 
-  /* The point of the same_translation_unit_p check here is,
-we want to detect a duplicate decl for a construct like
-foo() { extern bar(); } ... static bar();  but not if
-they are in different translation units.  In any case,
-the static does not go in the externals scope.  */
-  if (b
- && (TREE_PUBLIC (x) || 

Re: [PATCH] middle-end IFN_ASSUME support [PR106654]

2022-10-16 Thread Martin Uecker via Gcc-patches
Am Samstag, den 15.10.2022, 10:53 +0200 schrieb Jakub Jelinek:
> On Sat, Oct 15, 2022 at 10:07:46AM +0200, Martin Uecker wrote:
> > But why? Do we really want to encourage people to
> > write such code?
> 
> Of course these ++ cases inside of expressions are just obfuscation.
> But the point is to support using predicates that can be inlined and
> simplified into something really simple the optimizers can understand.

This makes sense,.

> The paper shows as useful e.g. being able to assert something is finite:
> [[assume (std::isfinite (x)]];
> and with the recent changes on the GCC side it is now or shortly will be
> possible to take advantage of such predicates.
> It is true that
> [[assume (__builtin_isfinite (x)]];
> could work if we check TREE_SIDE_EFFECTS on the GCC side because
> it is a const function, but that is a GNU extension, so the standard
> can't count with that.  std::isfinite isn't even marked const in libstdc++
> and one can figure that out during IPA propagation only.

Hm, that already seems to work with

if (!std::isfinite(x))
  __builtin_unreachable();

https://godbolt.org/z/hj3WrEhjb


> There are many similar predicates, or user could have some that are useful
> to his program.  And either in the end it wouldn't have side-effects
> but the compiler doesn't know, or would but those side-effects would be
> unimportant to the optimizations the compiler can derive from those.

I still have the feeling that relying on something
such as the pure and const attributes might then
be a better approach for this.

>From the standards point of view, this is OK
as GCC can just set its own rules as long as it is
a subset of what the standard allows.

> As the spec defines it well what happens with the side-effects and it
> is an attribute, not a function and the languages have non-evaluated
> contexts in other places, I don't see where a user confusion could come.

The user confusion might come when somebody writes
something such as [[assume(1 == ++i)]] and I expect
that people will start doing this once this works.


But I am also a a bit worried about the slipperly slope
of exploiting this more because what "would evaluate to true"
implies in case of I/O, atomic accesses, volatile accesses 
etc.  does not seem clear to me.   But maybe I am worrying
too much.


> We don't warn for sizeof (i++) and similar either.

Which is also confusing and clang does indeed
warn about it outside of macros and I think GCC
should too.

> __builtin_assume (i++) is a bad choice because it looks like a function
> call (after all, the compilers have many similar builtins) and its argument
> looks like normal argument to the function, so it is certainly unexpected
> that the side-effects aren't evaluated.

I agree.

Best
Martin




Re: [PATCH] middle-end IFN_ASSUME support [PR106654]

2022-10-15 Thread Martin Uecker via Gcc-patches
Am Freitag, den 14.10.2022, 23:20 +0200 schrieb Jakub Jelinek:
> On Fri, Oct 14, 2022 at 10:43:16PM +0200, Martin Uecker wrote:
> > Am Montag, den 10.10.2022, 10:54 +0200 schrieb Jakub Jelinek:
> > > Hi!
> > > 
> > > My earlier patches gimplify the simplest non-side-effects assumptions
> > > into if (cond) ; else __builtin_unreachable (); and throw the rest
> > > on the floor.
> > > The following patch attempts to do something with the rest too.
> > 
> > My recommendation would be to only process side-effect-free
> > assumptions and warn about the rest (clang does this for
> > __builtin_assume).   I do not think this is worth the
> 
> I think that is bad choice and makes it useless.

I think

[[assume(10 == i + 1)]]

could be useful as it is nicer syntax than

if (10 != i + 1)
  unreachable();

 but

[[assume(10 == i++)]]

is confusing / untestable and therefor seems a bit
dangerous. 

But we do not have to agree, I just stating my opinion
here. I would personally then suggest to have an
option for warning about side effects in assume.

> > complexity and I am not so sure the semantics of a
> > hypothetical evaluation are terribly well defined.
> 
> I think the C++23 paper is quite clear.  Yes, you can't verify it
> in debug mode, but there are many other UBs that are hard to verify
> through runtime instrumentation.

And none are good. Some are very useful though
(or even required in the context of C/C++). But I think
there should be a very good reason for adding more.

Personally, I do not see [[assume]] how side effects
is useful enough to justify adding another kind of
untestable UB.

Especially also because it has somewhat vaguely 
defined semantics. I don't know any formalization the
proposed semantics and the normative wording
"the converted expression would evaluate to true"
is probably good starting point for a PhD thesis.


> And, OpenMP has a similar feature (though, in that case it is even
> a stronger guarantee where something is guaranteed to hold across
> a whole region rather than just on its entry.
>
> > That you can not verify this properly by turning it
> > into traps in debug mode (as this would execute the
> > side effects) also makes this a terrible feature IMHO.
> > 
> > MSVC which this feature was based does not seem to make
> > much to sense to me: https://godbolt.org/z/4Ebar3G9b
> 
> So maybe their feature is different from what is in C++23,
> or is badly implemented?

The paper says as the first sentence in the abstract:

"We propose a standard facility providing the semantics
of existing compiler built-ins such as
__builtin_assume (Clang) and __assume (MSVC, ICC)."

But Clang does not support side effects and MSVC
is broken.  But yes, the paper then describes these
extended semantics for expression with side effects. 
According to the author this was based on discussions
with MSVC developers, but - to me - the fact that MSVC
still implements something else which does not seem
to make sense speaks against this feature.


> I think with what we have in the works for GCC we'll be able to optimize
> in
> int f(int i)
> {
>   [[assume(1 == i++)]];
>   return (1 == i++);
> }
> 
> int g(int i)
> {
>   [[assume(1 == ++i)]];
>   return (1 == ++i);
> }
> 
> extern int i;
> 
> int h(void) 
> {
>   [[assume(1 == ++i)]];
>   return (1 == ++i);
> }
> 
> 
> int k(int i)
> {
>   [[assume(42 == ++i)]];
>   return i;
> }
> at least f/g to return 1; and k to return 41;
> The h case might take a while to take advantage of.

But why? Do we really want to encourage people to
write such code?


Martin





Re: [PATCH] middle-end IFN_ASSUME support [PR106654]

2022-10-14 Thread Martin Uecker via Gcc-patches
Am Montag, den 10.10.2022, 10:54 +0200 schrieb Jakub Jelinek:
> Hi!
> 
> My earlier patches gimplify the simplest non-side-effects assumptions
> into if (cond) ; else __builtin_unreachable (); and throw the rest
> on the floor.
> The following patch attempts to do something with the rest too.

My recommendation would be to only process side-effect-free
assumptions and warn about the rest (clang does this for
__builtin_assume).   I do not think this is worth the
complexity and I am not so sure the semantics of a
hypothetical evaluation are terribly well defined.
That you can not verify this properly by turning it
into traps in debug mode (as this would execute the
side effects) also makes this a terrible feature IMHO.

MSVC which this feature was based does not seem to make
much to sense to me: https://godbolt.org/z/4Ebar3G9b


Martin



> For -O0, it actually throws even the simplest assumptions on the floor,
> we don't expect optimizations and the assumptions are there to allow
> optimizations.  Otherwise, it keeps the handling of the simplest
> assumptions as is, and otherwise arranges for the assumptions to be
> visible in the IL as
>   .ASSUME (_Z2f4i._assume.0, i_1(D));
> call where there is an artificial function like:
> bool _Z2f4i._assume.0 (int i)
> {
>   bool _2;
> 
>[local count: 1073741824]:
>   _2 = i_1(D) == 43;
>   return _2;
> 
> }
> with the semantics that there is UB unless the assumption function
> would return true.
> 
> Aldy, could ranger handle this?  If it sees .ASSUME call,
> walk the body of such function from the edge(s) to exit with the
> assumption that the function returns true, so above set _2 [true, true]
> and from there derive that i_1(D) [43, 43] and then map the argument
> in the assumption function to argument passed to IFN_ASSUME (note,
> args there are shifted by 1)?
> 
> During gimplification it actually gimplifies it into
>   D.2591 = .ASSUME ();
>   if (D.2591 != 0) goto ; else goto ;
>   :
>   {
> i = i + 1;
> D.2591 = i == 44;
>   }
>   :
>   .ASSUME (D.2591);
> with the condition wrapped into a GIMPLE_BIND (I admit the above isn't
> extra clean but it is just something to hold it from gimplifier until
> gimple low pass; it reassembles if (condition_never_true) { cond; };
> an alternative would be introduce GOMP_ASSUME statement that would have
> the guard var as operand and the GIMPLE_BIND as body, but for the
> few passes (tree-nested and omp lowering) in between that looked like
> an overkill to me) which is then pattern matched during gimple lowering
> and outlined into a separate function.  Variables declared inside of the
> condition (both static and automatic) just change context, automatic
> variables from the caller are turned into parameters (note, as the code
> is never executed, I handle this way even non-POD types, we don't need to
> bother pretending there would be user copy constructors etc. involved).
> 
> The assume_function artificial functions are then optimized until RTL
> expansion, which isn't done for them nor any later pass, on the other
> side bodies are not freed when done.
> 
> Earlier version of the patch has been successfully bootstrapped/regtested
> on x86_64-linux and i686-linux and all assume tests have passed even with
> this version.  Ok for trunk if it succeeds on another bootstrap/regtest?
> 
> There are a few further changes I'd like to do, like ignoring the
> .ASSUME calls in inlining size estimations (but haven't figured out where
> it is done), or for LTO arrange for the assume functions to be emitted
> in all partitions that reference those (usually there will be just one,
> unless code with the assumption got inlined, versioned etc.).
> 
> 2022-10-10  Jakub Jelinek  
> 
>   PR c++/106654
> gcc/
>   * function.h (struct function): Add assume_function bitfield.
>   * gimplify.cc (gimplify_call_expr): For -O0, always throw
>   away assumptions on the floor immediately.  Otherwise if the
>   assumption isn't simple enough, expand it into IFN_ASSUME
>   guarded block.
>   * gimple-low.cc (create_assumption_fn): New function.
>   (struct lower_assumption_data): New type.
>   (find_assumption_locals_r, assumption_copy_decl,
>   adjust_assumption_stmt_r, adjust_assumption_stmt_op,
>   lower_assumption): New functions.
>   (lower_stmt): Handle IFN_ASSUME guarded block.
>   * tree-ssa-ccp.cc (pass_fold_builtins::execute): Remove
>   IFN_ASSUME calls.
>   * lto-streamer-out.cc (output_struct_function_base): Pack
>   assume_function bit.
>   * lto-streamer-in.cc (input_struct_function_base): And unpack it.
>   * cgraphunit.cc (cgraph_node::expand): Don't verify assume_function
>   has TREE_ASM_WRITTEN set and don't release its body.
>   * cfgexpand.cc (pass_expand::execute): Don't expand assume_function
>   into RTL, just destroy loops and exit.
>   * internal-fn.cc (expand_ASSUME): Remove gcc_unreachable.
>   * passes.cc 

Re: [PATCH, CFE] N2863: Improved Rules for Tag Compatibility

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

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

Martin


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



[PATCH, CFE] N2863: Improved Rules for Tag Compatibility

2022-06-07 Thread Martin Uecker


Hello Joseph and all,


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

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

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

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

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

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

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

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

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

- There are certainly some issues I may have
overlooked.


Martin


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



diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 41a20bc625e..cd3164018f2 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2108,6 +2108,9 @@ Enum(strong_eval_order) String(some) Value(1)
 EnumValue
 Enum(strong_eval_order) String(all) Value(2)
 
+ftag-compat
+C Var(flag_tag_compat) Init(1)
+
 ftemplate-backtrace-limit=
 C++ ObjC++ Joined RejectNegative UInteger
Var(template_backtrace_limit) Init(10)
 Set the maximum number of template instantiation notes for a single
warning or error.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 5266a61b859..df208a310f9 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -599,6 +599,10 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static auto_vec all_structs;
+
 /* Information for the struct or union currently being parsed, or
NULL if not parsing a struct or union.  */
 static class c_struct_parse_info *struct_parse_info;
@@ -1354,8 +1358,8 @@ pop_scope (void)
  BLOCK_VARS (block) = extp;
}
  /* If this is the file scope set DECL_CONTEXT of each decl
to
-the TRANSLATION_UNIT_DECL.  This makes
same_translation_unit_p
-work.  */
+the TRANSLATION_UNIT_DECL.  */
+
  if (scope == file_scope)
{
  

Re: [PATCH 0/2] tree-optimization/104530 - proposed re-evaluation.

2022-02-23 Thread Martin Uecker via Gcc-patches
> 
> On 2/22/2022 10:57 AM, Jakub Jelinek via Gcc-patches wrote:
> > On Tue, Feb 22, 2022 at 12:39:28PM -0500, Andrew MacLeod wrote:
> >>> That is EH, then there are calls that might not return because they leave
> >>> in some other way (e.g. longjmp), or might loop forever, might exit, might
> >>> abort, trap etc.
> >> Generally speaking, calls which do not return should not now be a 
> >> problem...
> >> as long as they do not transfer control to somewhere else in the current
> >> function.
> > I thought all of those cases are very relevant to PR104530.
> > If we have:
> >_1 = ptr_2(D) == 0;
> >// unrelated code in the same bb
> >_3 = *ptr_2(D);
> > then in light of PR104288, we can optimize ptr_2(D) == 0 into true only if
> > there are no calls inside of "// unrelated code in the same bb"
> > or if all calls in "// unrelated code in the same bb" are guaranteed to
> > return exactly once.  Because, if there is a call in there which could
> > exit (that is the PR104288 testcase), or abort, or trap, or loop forever,
> > or throw externally, or longjmp or in any other non-UB way
> > cause the _1 = ptr_2(D) == 0; stmt to be invoked at runtime but
> > _3 = *ptr_2(D) not being invoked, then we can't optimize the earlier
> > comparison because ptr_2(D) could be NULL in a valid program.
> > While if there are no calls (and no problematic inline asms) and no trapping
> > insns in between, we can and PR104530 is asking that we continue to optimize
> > that.
> Right.  This is similar to some of the restrictions we deal with in the 
> path isolation pass.  Essentially we have a path, when traversed, would 
> result in a *0.  We would like to be able to find the edge upon-which 
> the *0 is control dependent and optimize the test so that it always went 
> to the valid path rather than the *0 path.
> 
> The problem is there may be observable side effects on the *0 path 
> between the test and the actual *0 -- including calls to nonreturning 
> functions, setjmp/longjmp, things that could trap, etc.  This case is 
> similar.  We can't back-propagate the non-null status through any 
> statements with observable side effects.

There are cases with volatile accesses where
this is currently not the case.

Also there is a proposal for C++ to require
an explicit std::observable fence to make sure
observable side effects are not undone by
later UB. (see the discussion about "reordering
of trapping operations and volatile" in
Janunary on the gcc list)

In my opinion it is much better if a compiler
makes sure to preserve observable side effects
even in code path with later UB (because the
behavior may otherwise be surprising and existing
code may be broken in a subtle way).  If I
understand you correctly, GCC intends to do
this.

Can we then also agree that the remaining volatile
cases used be fixed?


Martin







[C PATCH] Evaluate argument of sizeof that are structs of variable size.

2021-08-12 Thread Martin Uecker



Joseph,

here is the patch for c_expr_sizeof_type you had suggested.


Best,
Martin



Evaluate type arguments of sizeof that are structs of variable size [PR101838]

Evaluate type arguments of sizeof for all types of variable size
and not just for VLAs. This fixes PR101838 and some issues related 
to PR29970 where statement expressions need to be evaluated so that
the size is well defined.

2021-08-12  Martin Uecker  

gcc/c/
PR c/101838
PR c/29970
* c-typeck.c (c_expr_sizeof_type): Evaluate
size expressions for structs of variable size.

gcc/testsuite/
PR c/101838
* gcc.dg/vla-stexp-2.c: New test.
   




diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index c5bf3372321..eb5c87dc57a 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3022,8 +3022,14 @@ c_expr_sizeof_type (location_t loc, struct c_type_name 
*t)
   c_last_sizeof_loc = loc;
   ret.original_code = SIZEOF_EXPR;
   ret.original_type = NULL;
+  if (type == error_mark_node)
+{
+  ret.value = error_mark_node;
+  ret.original_code = ERROR_MARK;
+}
+  else
   if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
-  && c_vla_type_p (type))
+  && C_TYPE_VARIABLE_SIZE (type))
 {
   /* If the type is a [*] array, it is a VLA but is represented as
 having a size of zero.  In such a case we must ensure that
diff --git a/gcc/testsuite/gcc.dg/vla-stexp-2.c 
b/gcc/testsuite/gcc.dg/vla-stexp-2.c
new file mode 100644
index 000..4d4a15d34a6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-stexp-2.c
@@ -0,0 +1,33 @@
+/* PR101838-*/
+/* { dg-do run } */
+/* { dg-options "-Wpedantic -O0" } */
+
+
+int bar0(
+   int (*a)[*],
+   int (*b)[sizeof(*a)]
+);
+
+
+int bar(
+   struct f {  /* { dg-warning "will not be visible outside of 
this definition" } */
+   int a[*]; } v,  /* { dg-warning "variably modified type" } */
+   int (*b)[sizeof(struct f)]  // should not warn about zero size
+);
+
+int foo(void)
+{
+   int n = 0;
+   return sizeof(typeof(*({ n = 10; struct foo {   /* { dg-warning 
"braced-groups" } */
+   int x[n];   /* { dg-warning 
"variably modified type" } */
+   } x;  })));
+}
+
+
+int main()
+{
+   if (sizeof(struct foo { int x[10]; }) != foo())
+   __builtin_abort();
+
+   return 0;
+}



Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-09 Thread Martin Uecker



Am Montag, den 09.08.2021, 15:52 +0200 schrieb Eric Botcazou:
> > I think the patch makes sense but the comment says
> > 
> >  Java requires that we elaborated nodes in source order.  That
> >  means we must gimplify the inner expression followed by each
> > of
> >  the indices, in order.  But we can't gimplify the inner
> >  expression until we deal with any variable bounds, sizes, or
> >  positions in order to deal with PLACEHOLDER_EXPRs.
> > 
> > and I don't really understand that (not to say Java is no longer
> > supported
> > by GCC, but Ada does use PLACEHOLDER_EXPRs).  In fact the comment
> > suggests that we _should_ gimplify the inner expression first ...
> > at least
> > it seems to after your explanations ;)
> 
> We already gimplify the inner expression first, i.e. before indices
> and  operands, but we gimplify the "annotations" (special operands)
> before.
> 
> > Eric - do you know anything about this?
> 
> If the comment is right, then Martin's patch should break Ada indeed.
> 

Yes, it breaks Ada. I already found this out 
in the meanwhile.

But I do not understand how this works with the
PLACEHOLDER_EXPR.

My understanding of this is that this is for referring 
to some field of an outer struct which is then used in the
size expression, e.g. something like this (using
C syntax):

struct foo {
  int len;
  float (*x)[3][len];
};

And then for

struct foo* p;

p->x[1][1];  

we use the field 'len' of the struct pointed to by 'p'
the size expression.

But then why would you gimplify the size expression before
the base expression?  I would assume that you also want
to process the base expression first, because it is the
source of the struct which we access in the size expression.

Best,
Martin



















Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-03 Thread Martin Uecker
Am Dienstag, den 03.08.2021, 11:26 +0200 schrieb Richard Biener:
> On Tue, Aug 3, 2021 at 10:28 AM Martin Uecker  wrote:


> 
> Does the same issue arise with writing the testcases as
> 
>  ({ ... }) + i;
> 
> ?  How can we fix it then if you also need to support
> 
>  i + ({ ...});
> 
> ?

Here, the FE always moves the pointer to the right and
then produces something like:

*((int *) TARGET_EXPR  + ((sizetype) SAVE_EXPR  + 1) * 20);


So these are the cases which already work without
the path, although maybe it is wrong to have
the n in the SAVE_EXPR?

It gets gimplified to something like this,
which works:

  int[0:D.1959][0:D.1955] * D.1952;
  int n.0;
  sizetype D.1955;
  sizetype D.1959;
 
  {
int n;
int[0:D.1959][0:D.1955] * x;

n = 10;
n.0 = n;

...

_32 = (sizetype) n.0;
_33 = (sizetype) n.1;
_34 = _32 * _33;
_35 = _34 * 4;
x = __builtin_malloc (_35);
D.1952 = x;
  }
  _36 = (sizetype) n.0;
  _37 = _36 + 1;
  _38 = _37 * 20;
  _39 = D.1952 + _38;
 

For the array ref, the FE produces:


  (*TARGET_EXPR )[5][5];


With the patch, we get something like
the following in GIMPLE, which seems correct:

  int[0:D.1958][0:D.1954] * D.1951;
  int n.0;
  sizetype D.1954;

  {
int n;
int[0:D.1958][0:D.1954] * x;

n = 10;
n.0 = n;
 
_7 = (sizetype) n.0;
_8 = _7 * 4;
D.1956 = _8;

n.1 = n
 
_22 = (sizetype) n.0;
_23 = (sizetype) n.1;
_24 = _22 * _23;
_25 = _24 * 4;
x = __builtin_malloc (_25);
D.1951 = x;
  }
  _26 = D.1956 /[ex] 4;
  c = (*D.1951)[5]{lb: 0 sz: _26 * 4}[5];
 

MArtin



Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-03 Thread Martin Uecker



Am Dienstag, den 03.08.2021, 11:26 +0200 schrieb Richard Biener:
> On Tue, Aug 3, 2021 at 10:28 AM Martin Uecker 
> wrote:
> > 
> > Hi
> > Am Dienstag, den 03.08.2021, 10:10 +0200 schrieb Richard Biener:
> > > On Tue, Aug 3, 2021 at 7:32 AM Martin Uecker 
> > > wrote:
> > > > 
> > > > (resending from a different account, as emails seem to do not
> > > > go out from my other account at this time)
> > > > 
> > > > Am Montag, den 02.08.2021, 16:05 +0200 schrieb Martin Uecker:
> > > > > > On Sun, Aug 1, 2021 at 7:37 PM Uecker, Martin
> > > > > >  wrote:
> > > > > > > Here is an attempt to fix some old and annoying bugs
> > > > > > > related
> > > > > > > to VLAs and statement expressions. In particulary, this
> > > > > > > seems
> > > > > > > to fix the issues with variably-modified types which are
> > > > > > > returned from statement expressions (which works on
> > > > > > > clang),
> > > > > > > but there are still bugs remaining related to structs
> > > > > > > with VLA members (which seems to be a FE bug).
> > > > > > > 
> > > > > > > Of course, I might be doing something stupid...
> > > > > > 
> > > > > > How's evaluation order of (f())[g()] defined (with f
> > > > > > returning
> > > > > > a
> > > > > > pointer)?
> > > > > > Isn't that just f() + g()*sizeof(int) and thus undefined?
> > > > > 
> > > > > Yes, in C it is
> > > > > 
> > > > > f() + g()
> > > > > 
> > > > > and it is unsequenced. But the order of 'f' and 'g'
> > > > > is not relevant here and also the patch does not change
> > > > > it (the base expression is gimplified before the index).
> > > > > 
> > > > > Essentially, we have
> > > > > 
> > > > > ({ ... }) + g() * sizeof(X)
> > > > > 
> > > > > where X refers to a declaration in the statement expression.
> > > > > Without the patch the size expressions are gimplified before
> > > > > the base expression and also before the index expression.
> > > > > With the patch the ({ ... }) is gimplified also before the
> > > > > size expression.
> > > > > 
> > > > > > If it's undefined then I think the incoming GENERIC is ill-
> > > > > > defined.
> > > > > 
> > > > > I think it is OK because the arguments are evaluated
> > > > > before the operation.  Without the patch, parts of the
> > > > > operation (the size expressions) are gimplified before
> > > > > the arguments and this seems wrong to me.
> > > 
> > > But you said the evaluation order is undefined.
> > 
> > The evaluation order of the two arguments (base
> > and index) is undefined.  But the operation itself has
> > to happen after the arguments are evaluated like
> > the call to a is sequenced before f and g:
> > 
> > a(f(), g())
> > 
> > 
> > Computing the correct step size in the pointer
> > arithmetic is part of the operation itself and not
> > part of the evaluation of the arguments.
> > 
> > The problem here is that this part of the operation
> > is done before the arguments are evaluated, which
> > is a compiler bug.
> 
> Yes, but the bug is IMHO in the C frontend which inserts the
> DECL_EXPR at a wrong spot, not making sure it is evaluated before it
> is used.  Working around this deficiency in the gimplifier sounds
> incorrect.

The size if part of the type of the value which is 
returned from the compound  expression. 

So that there is a declaration involved was maybe
misleading in my example and explanation.  

So let me try again:

The size *expression* needs be be computed inside the 
statement expression (also because of side effects)
and then the result of this computation needs to 
returned together (as part of) the value returned 
by the statement expression. 

But the compilers tries to gimplify the size expression 
that  comes with the value already before the statement 
expression is evaluated. This can not work, no matter
what the front end does.

> 
> Does the same issue arise with writing the testcases as
> 
>  ({ ... }) + i;
> 
> ?  How can we fix it then if you also need to support
> 
>  i + ({ ...});
> 
> 
> ?

This already works correctly. I assume that here
the gimplifcation is  already  done in the right 
order.

But ARRAY_REF is handled as a separate case and
there it is wrong.

Martin

> 
> > > So IMHO the GENERIC is undefined in evaluating the size of sth
> > > that's not live?
> > > 
> > >  That said, given the statement expression
> > > result undergoes array to pointer decay doesn't this pointer
> > > refer to an object that ended its lifetime?
> > > "In a statement expression, any temporaries created within a
> > > statement are destroyed at that statement's end."
> > > That is, don't the testcases all invoke undefined behavior at
> > > runtime?
> > 
> > This is true for one of the test cases (where not having
> > an ICE is then
> > a QoI issue), but not for the others
> > where the object is allocated by
> > malloc and a pointer
> > to the object is returned from the statement
> > expression.
> > This is supposed to work.
> > 
> > 
> > Martin
> > 
> > 
> > 



Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-03 Thread Martin Uecker


Hi 
Am Dienstag, den 03.08.2021, 10:10 +0200 schrieb Richard Biener:
> On Tue, Aug 3, 2021 at 7:32 AM Martin Uecker  wrote:
> > 
> > 
> > (resending from a different account, as emails seem to do not
> > go out from my other account at this time)
> > 
> > Am Montag, den 02.08.2021, 16:05 +0200 schrieb Martin Uecker:
> > > > On Sun, Aug 1, 2021 at 7:37 PM Uecker, Martin
> > > >  wrote:
> > > > > 
> > > > > Here is an attempt to fix some old and annoying bugs related
> > > > > to VLAs and statement expressions. In particulary, this seems
> > > > > to fix the issues with variably-modified types which are
> > > > > returned from statement expressions (which works on clang),
> > > > > but there are still bugs remaining related to structs
> > > > > with VLA members (which seems to be a FE bug).
> > > > > 
> > > > > Of course, I might be doing something stupid...
> > > > 
> > > > How's evaluation order of (f())[g()] defined (with f returning
> > > > a
> > > > pointer)?
> > > > Isn't that just f() + g()*sizeof(int) and thus undefined?
> > > 
> > > Yes, in C it is
> > > 
> > > f() + g()
> > > 
> > > and it is unsequenced. But the order of 'f' and 'g'
> > > is not relevant here and also the patch does not change
> > > it (the base expression is gimplified before the index).
> > > 
> > > Essentially, we have
> > > 
> > > ({ ... }) + g() * sizeof(X)
> > > 
> > > where X refers to a declaration in the statement expression.
> > > Without the patch the size expressions are gimplified before
> > > the base expression and also before the index expression.
> > > With the patch the ({ ... }) is gimplified also before the
> > > size expression.
> > > 
> > > > If it's undefined then I think the incoming GENERIC is ill-
> > > > defined.
> > > 
> > > I think it is OK because the arguments are evaluated
> > > before the operation.  Without the patch, parts of the
> > > operation (the size expressions) are gimplified before
> > > the arguments and this seems wrong to me.
> 
> But you said the evaluation order is undefined.

The evaluation order of the two arguments (base
and index) is undefined.  But the operation itself has
to happen after the arguments are evaluated like
the call to a is sequenced before f and g:

a(f(), g())


Computing the correct step size in the pointer
arithmetic is part of the operation itself and not
part of the evaluation of the arguments.

The problem here is that this part of the operation
is done before the arguments are evaluated, which
is a compiler bug.

> So IMHO the GENERIC is undefined in evaluating the size of sth
> that's not live? 
>
>  That said, given the statement expression
> result undergoes array to pointer decay doesn't this pointer
> refer to an object that ended its lifetime?

> "In a statement expression, any temporaries created within a
> statement are destroyed at that statement's end."

> That is, don't the testcases all invoke undefined behavior at
> runtime?

This is true for one of the test cases (where not having
an ICE is then
a QoI issue), but not for the others
where the object is allocated by
malloc and a pointer
to the object is returned from the statement
expression.
This is supposed to work.


Martin





Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-02 Thread Martin Uecker



(resending from a different account, as emails seem to do not
go out from my other account at this time)

Am Montag, den 02.08.2021, 16:05 +0200 schrieb Martin Uecker:
> > On Sun, Aug 1, 2021 at 7:37 PM Uecker, Martin
> >  wrote:
> > > 
> > > 
> > > Here is an attempt to fix some old and annoying bugs related
> > > to VLAs and statement expressions. In particulary, this seems
> > > to fix the issues with variably-modified types which are
> > > returned from statement expressions (which works on clang),
> > > but there are still bugs remaining related to structs
> > > with VLA members (which seems to be a FE bug).
> > > 
> > > Of course, I might be doing something stupid...
> > 
> > How's evaluation order of (f())[g()] defined (with f returning a
> > pointer)?
> > Isn't that just f() + g()*sizeof(int) and thus undefined?
> 
> Yes, in C it is
> 
> f() + g()
> 
> and it is unsequenced. But the order of 'f' and 'g'
> is not relevant here and also the patch does not change 
> it (the base expression is gimplified before the index).
> 
> Essentially, we have
> 
> ({ ... }) + g() * sizeof(X) 
> 
> where X refers to a declaration in the statement expression.
> Without the patch the size expressions are gimplified before
> the base expression and also before the index expression. 
> With the patch the ({ ... }) is gimplified also before the
> size expression.
> 
> > If it's undefined then I think the incoming GENERIC is ill-defined.
> 
> I think it is OK because the arguments are evaluated 
> before the operation.  Without the patch, parts of the 
> operation (the size expressions) are gimplified before
> the arguments and this seems wrong to me.
> 
> 
> Martin
> 
> 
> 
> 



Re: [PATCH] Document that -fno-trampolines is for Ada only [PR100735]

2021-06-11 Thread Martin Uecker via Gcc-patches



> 
> Jeff et. al.
> 
> > On 9 Jun 2021, at 17:23, Jeff Law via Gcc-patches  
> > wrote:
> > On 5/25/2021 2:23 PM, Paul Eggert wrote:
> >> The GCC manual's documentation of -fno-trampolines was apparently
> >> written from an Ada point of view. However, when I read it I
> >> understandably mistook it to say that -fno-trampolines also works for
> >> C, C++, etc. It doesn't: it is silently ignored for these languages,
> >> and I assume for any language other than Ada.
> >> 
> >> This confusion caused me to go in the wrong direction in a Gnulib
> >> dicussion, as I mistakenly thought that entire C apps with nested
> >> functions could be compiled with -fno-trampolines and then use nested
> >> C functions in stack overflow handlers where the alternate stack
> >> is allocated via malloc. I was wrong, as this won't work on common
> >> platforms like x86-64 where malloc yields non-executable storage.
> >> 
> >> gcc/
> >> * doc/invoke.texi (Code Gen Options):
> >> * doc/tm.texi.in (Trampolines):
> >> Document that -fno-trampolines and -ftrampolines work
> >> only with Ada.
> > So Martin Uecker probably has the most state on this.  IIRC when we last 
> > discussed -fno-
> trampolines the belief was that it could be easily made to work independent 
> of the language, but
> that it was ultimately an ABI change.   That ultimately derailed plans to use 
> -fno-trampolines for
> other languages in the immediate term.
> 
> This is correct, it’s not technically too hard to make it work for another 
> language (I have a hack
> in my arm64-darwin branch that does this for gfortran).  As noted for most 
> ports it is an ABI
> break and thus not usable outside a such a work-around.
> 
> For the record (for the arm64-darwin port in the first instance), together 
> with some of my friends
> at embecosm we plan to implement a solution to the trampoline that does not 
> require executable
> stack and does not require an ABI break.  Perhaps such a solution will be of 
> interest to other
> ports that do not want executable stack.
> 
> We’re not quite ready to post the design yet - but will do so in the next few 
> weeks (all being
> well).
> 

For reference the discussion and PATCH for C can be found here:

https://gcc.gnu.org/legacy-ml/gcc-patches/2018-12/msg01532.html


FWIW: There is a proposal discussed in WG14 to add lambdas.

In this context a more general and portable solution to this
problem would also be useful. 

One related idea is to add a wider function pointer type
to C that includes a data pointer.  A regular function
pointer could be converted to the wider pointer but
back conversion only works if it originally was a
regular function pointer.  This pointer type could then
also be used for interoperablity with other languages
that have callable objects or closures.

If GCC could add something like this and there is then
implementation experience, we could later try to
standardize it. (there was also positive feedback
to this idea from some C++ people I spoke to)


Martin

 









Re: [RFC, PATCH] nonzero attribute, static array parameter

2015-07-23 Thread Martin Uecker

Hi Marek,

sorry for taking so long to respond.

Fri, 15 May 2015 15:38:43 +0200
Marek Polacek pola...@redhat.com:

 On Sat, May 09, 2015 at 09:42:23AM -0700, Martin Uecker wrote:
  here is a tentative patch to implement a new attribute nonzero,
  which is similar to nonnull, but is not a function attribute
  but a type attribute.
  
  One reason is that nonnull is awkward to use. For this reason,
  clang allows the use of nonnull in function parameters, but this
  is incompatible with old and current use of this attribute in gcc
  (though in a rather obscure use case).
  See: https://gcc.gnu.org/ml/gcc/2015-05/msg00077.html
  
 Sorry, I quite fail to see how such an attribute would be useful.

First of all, it makes it much simpler to implement the desired warnings
and ubsan checks when passing NULL as an array parameters with 'static'.
It avoids implementing all this argument walking code which is needed
for nonnull. If we do not want a nonzero attribute, could we then
consider an internal attribute (e.g. non zero)?

 It seems that the nonzero warning can only ever trigger when used
 on function parameters or on a return value, much as the nonnull / 
 returns_nonnull attributes. 

So far. But in the future this could be extended to other
cases where it makes sense.

 The difference is that you can use
 the nonzero attribute on a particular function parameter, but the
 nonnull attribute has this ability as well:
 
 __attribute__ ((nonnull (1))) void foo (int *, int *);
 void
 bar (void)
 {
   foo (0, 0);
 }

I know. But this is ugly, cumbersome, and fragile, and some uses
are incompatible with clang. That nonnull is mis-designed
has been pointed out before:

https://gcc.gnu.org/ml/gcc/2006-04/msg00551.html

 Unlike nonnull, nonzero attribute can be attached to a typedef, but
 it doesn't seem to buy you anything you couldn't do with the nonnull /
 returns_nonnull attributes.

It is much more expressive. A nonnull pointer _type_ seems really
useful to me. Many programming languages have something like this.

 The nonzero attribute can appertain even to integer types, not only
 pointer types.  Can you give an example where this would come in handy?
 It doesn't seem too useful to me.

One example:

void assert(__attribute__((nonzero)) int i);

would give a warning if it is already known at compile time
that the expression is zero.

 
 +void foo1(int x[__attribute__((nonzero))]);
 
 This looks weird, 

It does look weird. But this is already documented in this way:
https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax

The use of 'const' and 'static' in an array declarator as
defined by ISO C99 is already weird.

 the placement of the nonzero attribute here suggests
 that the array should have at least zero elements (the same that
 int x[static 0] does), but in fact it checks that the pointer passed
 to foo1 is non-NULL, i.e. something that could be easily achieved
 with the nonnull attribute.

In many case it would be much nicer to be able to declare a 
nonzero type and use it in interfaces instead of having to
add __attribute__((nonnull(1,2,5,8))) with exactly the right
numbers to a lot of prototypes.

  The other reason is that a nonzero type attribute is conceptually
  much simpler and at the same time more general than the existing
  nonnull and nonnull_return function attributes (and could replace
  both), e.g. we can define non-zero types and diagnose all stores
  of known constant 0 to variables of this type, use this for 
  computing better value ranges, etc.
  
 Why would that be useful?  What makes integer 0 special?

0 is special in many ways. In particular it represents false
in an if clause. Also, why artificially restrict it to pointers
when it is trivial to make it work for integers too?


Martin





[RFC, PATCH] nonzero attribute, static array parameter

2015-05-09 Thread Martin Uecker

Hi,

here is a tentative patch to implement a new attribute nonzero,
which is similar to nonnull, but is not a function attribute
but a type attribute.

One reason is that nonnull is awkward to use. For this reason,
clang allows the use of nonnull in function parameters, but this
is incompatible with old and current use of this attribute in gcc
(though in a rather obscure use case).
See: https://gcc.gnu.org/ml/gcc/2015-05/msg00077.html

The other reason is that a nonzero type attribute is conceptually
much simpler and at the same time more general than the existing
nonnull and nonnull_return function attributes (and could replace
both), e.g. we can define non-zero types and diagnose all stores
of known constant 0 to variables of this type, use this for 
computing better value ranges, etc.

This patch implements the attribute and adds a warning if a 
zero constant is passed as argument with nonzero type attribute.
Also infer_nonnull_range in gcc/gimple.c is extended to make use 
of the attribute (which in turn is used by ubsan).

In addition, in C the attribute is automatically added to
pointers declared as array parameters with static, e.g:

void foo(int a[static 5]);


Martin

(tested on x86_64-unknown-linux-gnu)






diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 77d9352..2f79344 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2015-05-09  Martin Uecker  uec...@eecs.berkeley.edu
+
+	* gcc/gimple.c (infer_nonnull_range): Process nonzero attribute.
+	* doc/invoki.texi
+
 2015-05-08  Jim Wilson  jim.wil...@linaro.org
 
 	* doc/install.texi (--enable-languages): Add missing jit and lto info.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 57f83c9..809ecf1 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-09  Martin Uecker  uec...@eecs.berkeley.edu
+
+	* c-common.c (handle_nonzero_attribute): New.
+	(check_function_nonzero): New.
+	(check_nonzero_arg): New.
+
 2015-05-08  Marek Polacek  pola...@redhat.com
 
 	PR c/64918
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 378f237..46fe749 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -380,6 +380,7 @@ static tree handle_deprecated_attribute (tree *, tree, tree, int,
 static tree handle_vector_size_attribute (tree *, tree, tree, int,
 	  bool *);
 static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nonzero_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
 static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
@@ -407,6 +408,7 @@ static tree handle_bnd_instrument (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
+static void check_nonzero_arg (void *, tree, unsigned HOST_WIDE_INT);
 static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
 static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
 static int resort_field_decl_cmp (const void *, const void *);
@@ -751,6 +753,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			  handle_tls_model_attribute, false },
   { nonnull,0, -1, false, true, true,
 			  handle_nonnull_attribute, false },
+  { nonzero,0, -1, false, true, false,
+  handle_nonzero_attribute, false },
   { nothrow,0, 0, true,  false, false,
 			  handle_nothrow_attribute, false },
   { may_alias,	  0, 0, false, true, false, NULL, false },
@@ -8940,6 +8944,26 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+
+/* Handle the nonzero attribute.  */
+static tree
+handle_nonzero_attribute (tree *node, tree ARG_UNUSED (name),
+			  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			  bool *no_add_attrs)
+{
+  tree n = *node;
+
+  if ((TREE_CODE (n) != POINTER_TYPE)
+   (TREE_CODE (n) != INTEGER_TYPE))
+{
+  warning (OPT_Wattributes, %qE attribute ignored, name);
+  *no_add_attrs = true;
+}
+
+  return NULL_TREE;
+}
+
+
 /* Handle the nonnull attribute.  */
 static tree
 handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
@@ -9016,6 +9040,34 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
+
+static void
+check_function_nonzero (const_tree fntype, int nargs, tree *argarray)
+{
+  if (TREE_CODE (fntype) != FUNCTION_TYPE) // C++ lambdas
+return;
+
+  function_args_iterator iter;
+  tree type;
+  int i = 0;
+
+  FOREACH_FUNCTION_ARGS (fntype, type, iter)
+{
+  if (i == nargs)
+	break;
+
+  tree a = lookup_attribute (nonzero, TYPE_ATTRIBUTES (type));
+
+  if (a != NULL_TREE)
+check_function_arguments_recurse (check_nonzero_arg, NULL,
+	  argarray[i], i + 1

Re: [PATCH] ubsan: improve bounds checking, add -fsanitize=bounds-strict

2015-03-02 Thread Martin Uecker

Marek Polacek pola...@redhat.com:
 On Fri, Feb 27, 2015 at 11:53:14AM -0800, Martin Uecker wrote:
  
  I tested Marek's proposed change and it works correctly,
  i.e. arrays which are not part of a struct are now
  instrumented when accessed through a pointer. This also
  means that the following case is diagnosed (correctly)
  as undefined behaviour as pointed out by Richard:
  
  int
  main (void)
  {
int *t = (int *) __builtin_malloc (sizeof (int) * 9);
int (*a)[3][3] = (int (*)[3][3])t;
(*a)[0][9] = 1;
  }
  
  
  I also wanted arrays which are the last elements of a
  struct which are not flexible-array members instrumented 
  correctly. So I added -fsantitize=bounds-strict which does
  this. It seems to do instrumentation similar to clang 
  with -fsanitize=bounds.
  
  Comments?
  
 Thanks for working on it.  So I think we should split this patch in
 two; one part is a bug fix (I've opened
 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65280) that could go
 into gcc 5 - that is, apply my fix along with test cases covering the
 new cases, and the second part is an addition of a new option for
 strict bounds checking - I'm afraid this part has to wait for gcc 6.
 
 I can take care of the first part and let you do the second part, which I
 could review.  Does that sound ok to you?

Thank you Marek! Sounds good to me.

Martin



Re: [PATCH] ubsan: improve bounds checking, add -fsanitize=bounds-strict

2015-03-01 Thread Martin Uecker

Bootstrap and regression tested on x86_64.

A ubsan-bootstrap for C and C++ works too (although there
are other unrelated runtime errors). 

I tried a bootstrap with -fsanitize=bounds-strict and 
there are indeed many additional runtime errors due the
struct hack with last array element of size 1 (or even 2). 
So Jakub and Richard were right and putting this into a 
separate option was the right thing to do.


Code-wise it seems to come just from a couple of places
such as  (rtl.h, tree.h, vec.h, sbitmap.h, ...).

Just to see how hard it would be to make this work with
strict bounds checking, I started doing this in my tree 
using a macro:

#define CAST_TO_POINTER(x) ((__typeof(x[0])*)(x))

For example,

#define RTL_CHECK1(RTX, N, C1) ((RTX)-u.fld[N])

then becomes

#define RTL_CHECK1(RTX, N, C1) \
(CAST_TO_POINTER((RTX)-u.fld)[N])

Doing this in a few places gets rid of most of the
errors rather quickly (getting rid of all errors would
be a bit more work).

If one allows VLAs one could also cast to an array of
the correct length:

#defined CAST_TO_VLA(x, len) (*(__typeof(x[0])(*)[len])x)

For example:

#define RTL_CHECK1(RTX, N, C1) \
(CAST_TO_VLA((RTX)-u.fld, GET_RTX_LENGTH( ... ))[N])

and have ubsan auto-generate the bound checking which
are now often manually added.

Martin





Martin Uecker uec...@eecs.berkeley.edu:
 
 I tested Marek's proposed change and it works correctly,
 i.e. arrays which are not part of a struct are now
 instrumented when accessed through a pointer. This also
 means that the following case is diagnosed (correctly)
 as undefined behaviour as pointed out by Richard:
 
 int
 main (void)
 {
   int *t = (int *) __builtin_malloc (sizeof (int) * 9);
   int (*a)[3][3] = (int (*)[3][3])t;
   (*a)[0][9] = 1;
 }
 
 
 I also wanted arrays which are the last elements of a
 struct which are not flexible-array members instrumented 
 correctly. So I added -fsantitize=bounds-strict which does
 this. It seems to do instrumentation similar to clang 
 with -fsanitize=bounds.
 
 Comments?
 
 (regression testing in progress, but ubsan-related
 tests all pass)
 
 diff --git a/gcc/ChangeLog b/gcc/ChangeLog
 index ec2cb69..cb6df20 100644
 --- a/gcc/ChangeLog
 +++ b/gcc/ChangeLog
 @@ -1,3 +1,11 @@
 +2015-02-27  Martin Uecker uec...@eecs.berkeley.edu
 +
 + * opts.c(common_handle_option): Add option for
 + -fsanitize=bounds-strict
 + * flag-types.h: Add SANITIZE_BOUNDS_STRICT
 + * doc/invoke.texi: Improve description for
 + -fsanitize=bounds and document -fsanitize=bounds-strict
 +
 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
 index ffa01c6..44a1761 100644
 --- a/gcc/c-family/ChangeLog
 +++ b/gcc/c-family/ChangeLog
 @@ -1,3 +1,9 @@
 +2015-02-27  Martin Uecker uec...@eecs.berkeley.edu
 +
 + * c-ubsan.c (ubsan_instrument_bounds): Instrument
 + arrays which are accessed directly through a pointer.
 + For strict checking, instrument last elements of a struct.
 +
 diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
 index 90d59c0..1a0e2da 100644
 --- a/gcc/c-family/c-ubsan.c
 +++ b/gcc/c-family/c-ubsan.c
 @@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
 *index,
tree type = TREE_TYPE (array);
tree domain = TYPE_DOMAIN (type);
  
 +  /* This also takes care of flexible array members. */
if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
  return NULL_TREE;
  
 @@ -301,10 +302,13 @@ ubsan_instrument_bounds (location_t loc, tree array, 
 tree *index,
  bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
build_int_cst (TREE_TYPE (bound), 1));
  
 -  /* Detect flexible array members and suchlike.  */
 +  /* Don't instrument arrays which are the last element of
 + a struct. */
tree base = get_base_address (array);
 -  if (base  (TREE_CODE (base) == INDIRECT_REF
 -|| TREE_CODE (base) == MEM_REF))
 +  if (!(flag_sanitize  SANITIZE_BOUNDS_STRICT)
 +   (TREE_CODE (array) == COMPONENT_REF)
 +   base  (TREE_CODE (base) == INDIRECT_REF
 + || TREE_CODE (base) == MEM_REF))
  {
tree next = NULL_TREE;
tree cref = array;
 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
 index ef4cc75..5a93757 100644
 --- a/gcc/doc/invoke.texi
 +++ b/gcc/doc/invoke.texi
 @@ -5704,8 +5704,15 @@ a++;
  @item -fsanitize=bounds
  @opindex fsanitize=bounds
  This option enables instrumentation of array bounds.  Various out of bounds
 -accesses are detected.  Flexible array members and initializers of variables
 -with static storage are not instrumented.
 +accesses are detected.  Accesses to arrays which are the last member of a
 +struct and initializers of variables with static storage are not 
 instrumented.
 +
 +@item -fsanitize=bounds-strict
 +@opindex fsanitize=bounds-strict
 +This option enables strict instrumentation of array bounds.  Most out of 
 bounds
 +accesses are detected including accesses to arrays which

[PATCH] ubsan: improve bounds checking, add -fsanitize=bounds-strict

2015-02-27 Thread Martin Uecker

I tested Marek's proposed change and it works correctly,
i.e. arrays which are not part of a struct are now
instrumented when accessed through a pointer. This also
means that the following case is diagnosed (correctly)
as undefined behaviour as pointed out by Richard:

int
main (void)
{
  int *t = (int *) __builtin_malloc (sizeof (int) * 9);
  int (*a)[3][3] = (int (*)[3][3])t;
  (*a)[0][9] = 1;
}


I also wanted arrays which are the last elements of a
struct which are not flexible-array members instrumented 
correctly. So I added -fsantitize=bounds-strict which does
this. It seems to do instrumentation similar to clang 
with -fsanitize=bounds.

Comments?

(regression testing in progress, but ubsan-related
tests all pass)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ec2cb69..cb6df20 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2015-02-27  Martin Uecker uec...@eecs.berkeley.edu
+
+   * opts.c(common_handle_option): Add option for
+   -fsanitize=bounds-strict
+   * flag-types.h: Add SANITIZE_BOUNDS_STRICT
+   * doc/invoke.texi: Improve description for
+   -fsanitize=bounds and document -fsanitize=bounds-strict
+
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index ffa01c6..44a1761 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2015-02-27  Martin Uecker uec...@eecs.berkeley.edu
+
+   * c-ubsan.c (ubsan_instrument_bounds): Instrument
+   arrays which are accessed directly through a pointer.
+   For strict checking, instrument last elements of a struct.
+
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 90d59c0..1a0e2da 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
   tree type = TREE_TYPE (array);
   tree domain = TYPE_DOMAIN (type);
 
+  /* This also takes care of flexible array members. */
   if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
 return NULL_TREE;
 
@@ -301,10 +302,13 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
 bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
 build_int_cst (TREE_TYPE (bound), 1));
 
-  /* Detect flexible array members and suchlike.  */
+  /* Don't instrument arrays which are the last element of
+ a struct. */
   tree base = get_base_address (array);
-  if (base  (TREE_CODE (base) == INDIRECT_REF
-  || TREE_CODE (base) == MEM_REF))
+  if (!(flag_sanitize  SANITIZE_BOUNDS_STRICT)
+   (TREE_CODE (array) == COMPONENT_REF)
+   base  (TREE_CODE (base) == INDIRECT_REF
+ || TREE_CODE (base) == MEM_REF))
 {
   tree next = NULL_TREE;
   tree cref = array;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ef4cc75..5a93757 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -5704,8 +5704,15 @@ a++;
 @item -fsanitize=bounds
 @opindex fsanitize=bounds
 This option enables instrumentation of array bounds.  Various out of bounds
-accesses are detected.  Flexible array members and initializers of variables
-with static storage are not instrumented.
+accesses are detected.  Accesses to arrays which are the last member of a
+struct and initializers of variables with static storage are not instrumented.
+
+@item -fsanitize=bounds-strict
+@opindex fsanitize=bounds-strict
+This option enables strict instrumentation of array bounds.  Most out of bounds
+accesses are detected including accesses to arrays which are the last member 
of a
+struct. Initializers of variables with static storage are not instrumented.
+
 
 @item -fsanitize=alignment
 @opindex fsanitize=alignment
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index bfdce44..c9ad4df 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -238,6 +238,7 @@ enum sanitize_code {
   SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1UL  19,
   SANITIZE_OBJECT_SIZE = 1UL  20,
   SANITIZE_VPTR = 1UL  21,
+  SANITIZE_BOUNDS_STRICT = 1UL  22,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
   | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
   | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
@@ -245,7 +246,7 @@ enum sanitize_code {
   | SANITIZE_NONNULL_ATTRIBUTE
   | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
   | SANITIZE_OBJECT_SIZE | SANITIZE_VPTR,
-  SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
+  SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST | 
SANITIZE_BOUNDS_STRICT
 };
 
 /* flag_vtable_verify initialization levels. */
diff --git a/gcc/opts.c b/gcc/opts.c
index 39c190d..7fe77fa 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1584,6 +1584,7 @@ common_handle_option (struct gcc_options *opts,
  { float-cast-overflow, SANITIZE_FLOAT_CAST,
sizeof float-cast-overflow - 1

Re: [PATCH] ubsan: remove bogus check for flexible array members

2015-02-26 Thread Martin Uecker
Am Thu, 26 Feb 2015 10:05:14 +0100
Jakub Jelinek ja...@redhat.com:

 On Thu, Feb 26, 2015 at 12:59:08AM -0800, Martin Uecker wrote:
   No, it is not bogus nor unnecessary.
   This isn't about just real flexible arrays, but similar constructs,
   C++ doesn't have flexible array members, nor C89, so people use the
   GNU extension of struct S { ... ; char a[0]; } instead, or
  
  The GNU extension is still allowed, i.e. not instrumented with
  the patch.
  
   use char a[1]; as the last member and still expect to be able to access
   s-a[i] for i  0 say on heap allocations etc.
  
  And this is broken code. I would argue that a user who uses the
  ubsan *expects* this to be diagnosed. Atleast I was surprised
  that it didn't catch more out-of-bounds accesses.
 
 So can you explain what a C++ programmer can do portably? 

Using broken code is not really portable either, because other
compilers diagnose this. Also, we are not talking about breaking
that code - they can simply continue to use that code. They could
just not expect ubsan to not diagnose it. This would make
them aware of the fact that their code is problematic - which is
exactly what I would expect from ubsan.

 It has neither
 flexible array members, nor without GNU extensions zero sized arrays.
 If the array size is constant, perhaps turn the struct into a template,
 but if it is variable?  Ditto for C89 code.
 The amount of code that uses this idiom in the wild is huge.

Ok, I will add an option then. Or should this be language dependent?

Maritn


Re: [PATCH] ubsan: remove bogus check for flexible array members

2015-02-26 Thread Martin Uecker
Marek Polacek pola...@redhat.com:

(Hi Marek and Jakub, I really appreciate your work on GCC and 
ubsan. I just want to add the minor enhancements necessary 
to make it really useful for me).

  And this is broken code. I would argue that a user who uses the
  ubsan *expects* this to be diagnosed. Atleast I was surprised
  that it didn't catch more out-of-bounds accesses.
  
 I wouldn't say broken, it's being used pretty often.  E.g.
 https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
 In ISO C90, you would have to give contents a length of 1

Ok, let's add an option then. But that it is common doesn't
mean it is not broken (especially since there is a legal
way to that with GCC and C99) and I think there should be a 
way to diagnose it with ubsan.

  If this is indeed intentional, we should:
  
  - document these exceptions
 
 See the link above + docs say for -fsanitize=bounds that Flexible array
 members are not instrumented.

Flexible array members should not be intrumented. But
what is suprising to the user and should be documented
is that other arrays (e.g. which hjust happen to be the
last in a struct) are not instrumented.

  - remove the misleading comment
 
 Which one?
 The /* Detect flexible array members and suchlike.  */ IMHO says
 exactly what's meant to be done.

The reason it confused me was because flexible array members never
see this code because the are catched by the 'if' condition
directly before. 

  - have test cases also for sizes  0
 
 Yes, we should have that.
 
  - fix it not to prevent instrumentation of all array accesses
through pointers (i.e. when the array is not a member of a struct)
 
 Yes, see the patch in my previous mail.

Thank you! I will test this and report back

  - have a configuration option (e.g. -fsanitize=strict-bounds)
 
 Yeah, something like that would be useful to have.  As Jakub
 mentioned, we discussed this in the past.  Probably GCC 6 stuff
 though.

I will look into this.

Martin



Re: [PATCH] ubsan: remove bogus check for flexible array members

2015-02-26 Thread Martin Uecker

Thu, 26 Feb 2015 07:36:54 +0100
Jakub Jelinek ja...@redhat.com:
 On Wed, Feb 25, 2015 at 10:01:07PM -0800, Martin Uecker wrote:
  this patch removes a bogus check for flexible array members
  which prevents array references to be instrumented in some
  interesting cases. Arrays accessed through pointers are now
  instrumented correctly.
  
  The check was unnecessary because flexible arrays are not 
  instrumented anyway because of
  TYPE_MAX_VALUE (domain) == NULL_TREE. 
 
 No, it is not bogus nor unnecessary.
 This isn't about just real flexible arrays, but similar constructs,
 C++ doesn't have flexible array members, nor C89, so people use the
 GNU extension of struct S { ... ; char a[0]; } instead, or

The GNU extension is still allowed, i.e. not instrumented with
the patch.

 use char a[1]; as the last member and still expect to be able to access
 s-a[i] for i  0 say on heap allocations etc.

And this is broken code. I would argue that a user who uses the
ubsan *expects* this to be diagnosed. Atleast I was surprised
that it didn't catch more out-of-bounds accesses.

If this is indeed intentional, we should:

- document these exceptions
- remove the misleading comment
- have test cases also for sizes  0
- fix it not to prevent instrumentation of all array accesses
  through pointers (i.e. when the array is not a member of a struct)
- have a configuration option (e.g. -fsanitize=strict-bounds)


 I think we were talking at some point about having a strict-bounds or
 something similar that would accept only real flexible array members and
 nothing else and be more pedantic, at the disadvantage of diagnosing tons
 of real-world code that is supported by GCC.

 Perhaps if the reference is just an array, not a struct containing
 flexible-array-member-like array, we could consider it strict always,
 but that is certainly not what your patch does.

Indeed, currently the patch tries to make -fsanitize=bounds detect what
the  standard considers undefined behaviour. At the moment, I do not
quite see why ubsan should be so permissive as you say.

But we can also add a new option -fsanitize=strict-bounds. Then I could
use this for my (real-world) projects.



  * c-family/c-ubsan.c (ubsan_instrument_bounds): Remove
 
 c-family/ shouldn't be in the ChangeLog entry, instead that part should go
 into c-family/ChangeLog.

  --- a/gcc/c-family/c-ubsan.c
  +++ b/gcc/c-family/c-ubsan.c
  @@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, 
  tree *index,
 tree type = TREE_TYPE (array);
 tree domain = TYPE_DOMAIN (type);
   
  +  /* This also takes care of flexilbe array members */
 
 Typo.
 
  +#ifdef __cplusplus
  +extern C void* malloc(unsigned long x);
  +#else
  +extern void* malloc(unsigned long x);
  +#endif
 
 Why are you declaring malloc (wrongly), when it isn't used?
 Malloc argument is size_t aka __SIZE_TYPE__, not unsigned long.

Left over from removing tests already done elsewhere.

Thank you for your comments,
Martin




[PATCH] ubsan: remove bogus check for flexible array members

2015-02-25 Thread Martin Uecker

Hi,

this patch removes a bogus check for flexible array members
which prevents array references to be instrumented in some
interesting cases. Arrays accessed through pointers are now
instrumented correctly.

The check was unnecessary because flexible arrays are not 
instrumented anyway because of
TYPE_MAX_VALUE (domain) == NULL_TREE. 


Regression tested.


2015-02-25  Martin Uecker uec...@eecs.berkeley.edu

gcc/

* c-family/c-ubsan.c (ubsan_instrument_bounds): Remove
bogus check for flexible array members.

gcc/testsuite/

* gcc.dg/ubsan/bounds-2.c: New
* c-c++-common/ubsan/bounds-8.c: New



diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 90d59c0..dba3bbc 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
   tree type = TREE_TYPE (array);
   tree domain = TYPE_DOMAIN (type);
 
+  /* This also takes care of flexilbe array members */
   if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
 return NULL_TREE;
 
@@ -301,36 +302,6 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
 bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
 build_int_cst (TREE_TYPE (bound), 1));
 
-  /* Detect flexible array members and suchlike.  */
-  tree base = get_base_address (array);
-  if (base  (TREE_CODE (base) == INDIRECT_REF
-  || TREE_CODE (base) == MEM_REF))
-{
-  tree next = NULL_TREE;
-  tree cref = array;
-
-  /* Walk all structs/unions.  */
-  while (TREE_CODE (cref) == COMPONENT_REF)
-   {
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
-   for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
-next  TREE_CODE (next) != FIELD_DECL;
-next = DECL_CHAIN (next))
- ;
- if (next)
-   /* Not a last element.  Instrument it.  */
-   break;
- /* Ok, this is the last field of the structure/union.  But the
-aggregate containing the field must be the last field too,
-recursively.  */
- cref = TREE_OPERAND (cref, 0);
-   }
-  if (!next)
-   /* Don't instrument this flexible array member-like array in non-strict
-  -fsanitize=bounds mode.  */
-return NULL_TREE;
-}
-
   /* Don't emit instrumentation in the most common cases.  */
   tree idx = NULL_TREE;
   if (TREE_CODE (*index) == INTEGER_CST)
diff --git a/gcc/testsuite/c-c++-common/ubsan/bounds-8.c 
b/gcc/testsuite/c-c++-common/ubsan/bounds-8.c
new file mode 100644
index 000..554693f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/bounds-8.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options -O3 -fsanitize=bounds } */
+/* Origin: Martin Uecker uec...@eecs.berkeley.edu */
+
+#ifdef __cplusplus
+extern C void* malloc(unsigned long x);
+#else
+extern void* malloc(unsigned long x);
+#endif
+
+void foo(int (*a)[3])
+{
+   (*a)[3] = 1;// error
+   a[0][0] = 1;// ok
+   a[1][0] = 1;// ok
+   a[1][4] = 1;// error
+}
+
+int main()
+{
+   int a[20];
+   foo((int (*)[3])a);
+}
+
+/* { dg-output index 3 out of bounds for type 'int 
\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r) } */
+/* { dg-output \[^\n\r]*index 4 out of bounds for type 'int \\\[3\\\]' } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-2.c 
b/gcc/testsuite/gcc.dg/ubsan/bounds-2.c
new file mode 100644
index 000..722c54e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-2.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options -O3 -fsanitize=bounds } */
+/* Origin: Martin Uecker uec...@eecs.berkeley.edu */
+
+extern void* malloc(unsigned long x);
+
+void foo(int n, int (*b)[n])
+{
+   (*b)[n] = 1;// error
+}
+
+int main()
+{
+   int a[20];
+   foo(3, (int (*)[3])a);
+}
+
+/* { dg-output index 3 out of bounds for type 'int \\\[\\\*\\\]' } */






Re: [PATCH][2/2] Improve array-bound warnings and VRP

2015-01-27 Thread Martin Uecker


Richard Biener wrote:

 On Mon, 26 Jan 2015, Jakub Jelinek wrote:

  Then it probably should be ok.  I'm really afraid of emitting more warnings
  with such high false positive rate now.

 As the patch also mitigates some of the code bloat we get with
 the complete peeling (regression against 4.7) I have installed it.
 It's also the easiest vehicle to verify range-info is not broken
 by passes between vrp1 and vrp2.

You could make warnings appear only for warn_array_bounds  1
if there are concerns about false positives.

For what it's worth, I tested the old version of both patches on 
one of my projects (mostly numerical algorithms) and it did not 
produce additional warnings.

I really appreciate all improvements in this area.

Martin




[committed] MAINTAINERS: add myself to write-after-approval list

2015-01-15 Thread Martin Uecker

2015-01-15  Martin Uecker  uec...@eecs.berkeley.edu

* MAINTAINERS: (Write After Approval): Add myself.


Index: MAINTAINERS
===
--- MAINTAINERS (Revision 219713)
+++ MAINTAINERS (Revision 219714)
@@ -576,6 +576,7 @@
 Philipp Tomsich
philipp.toms...@theobroma-systems.com
 Konrad Trifunovic  konrad.trifuno...@inria.fr
 Markus Trippelsdorfmar...@trippelsdorf.de
+Martin Uecker  uec...@eecs.berkeley.edu
 David Ung  dav...@mips.com
 Neil Vachharajani  nvach...@gmail.com
 Kris Van Hees  kris.van.h...@oracle.com


Re: [PATCH] add option to emit more array bounds warnigs

2015-01-13 Thread Martin Uecker

Mon, 12 Jan 2015 11:00:44 -0700
Jeff Law l...@redhat.com:
 On 11/11/14 23:13, Martin Uecker wrote:

...

 
 
  * gcc/tree-vrp.c (check_array_ref): Emit more warnings
  for warn_array_bounds = 2.
  * gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
  * gcc/c-family/c.opt: New option -Warray-bounds=.
  * gcc/common.opt: New option -Warray-bounds=.
  * gcc/doc/invoke.texi: Document new option.
 Has this patch been bootstrapped and regression tested, if so on what 
 platform.

x86_64-unknown-linux-gnu

 Given the new warnings (as implemented by the patch) are not enabled by 
 default, I'm inclined to approve once Martin verifies things via 
 bootstrap and regression test.

Thank you,

Martin

 



Re: [PATCH] add option to emit more array bounds warnigs

2015-01-13 Thread Martin Uecker

Jeff Law l...@redhat.com:
 On 01/13/15 17:40, Martin Uecker wrote:
  Jeff Law l...@redhat.com:
  On 01/13/15 10:34, Martin Uecker wrote:
  Mon, 12 Jan 2015 11:00:44 -0700
  Jeff Law l...@redhat.com:
  On 11/11/14 23:13, Martin Uecker wrote:
 
  ...
 
  Has this patch been bootstrapped and regression tested, if so on what
  platform.
 
  x86_64-unknown-linux-gnu
  Approved.  Please install on the trunk.  Sorry about the delays.
 
  I don't have write access ;-(
 I fixed up the ChangeLog entries and installed the patch for you.

Thank you, Jeff!

 If you plan to contribute regularly, you should go ahead and apply for 
 write access to the repository so that you'll be able to commit your own 
 patches once they're approved.

I put a request in with you as sponsor (hope this is ok).

 You'll also need to make sure you have an assignment on file with the 
 FSF.That patch was pretty small (the testcase was larger than the 
 patch itself, which I always like :-) so I didn't request an assignment. 
   Further submissions likely will require an assignment.

I already have an assignment on file.

Martin



Re: [PATCH] add option to emit more array bounds warnigs

2015-01-13 Thread Martin Uecker
Jeff Law l...@redhat.com:
 On 01/13/15 10:34, Martin Uecker wrote:
  Mon, 12 Jan 2015 11:00:44 -0700
  Jeff Law l...@redhat.com:
  On 11/11/14 23:13, Martin Uecker wrote:

...

  Has this patch been bootstrapped and regression tested, if so on what
  platform.
 
  x86_64-unknown-linux-gnu
 Approved.  Please install on the trunk.  Sorry about the delays.

I don't have write access ;-(

Martin





[PING] Re: [PATCH] add option to emit more array bounds warnigs

2015-01-11 Thread Martin Uecker



Please consider this patch. The additional warnings would be useful 
IMHO, are also emitted by clang, and the change seems trivial.

Previous discussion about potential false positives:
https://gcc.gnu.org/ml/gcc/2014-11/msg00114.html


Tue, 11 Nov 2014 22:13:20 -0800
Martin Uecker uec...@eecs.berkeley.edu:

 
 Hi,
 
 this proposed patch adds an option -Warray-bounds= in addition to
 -Warray-bound. -Warray-bounds=1 corresponds to -Warray-bound.
 For higher warning levels more warnings about optional accesses
 outside of arrays are emitted. For example, warnings for
 arrays accessed through pointers are now emitted:
 
 void foo(int (*a)[3])
 {
   (*a)[4] = 1;
 }
 
 Also warnings for arrays which are the last element of a struct
 are emitted, if it is not a flexible array member or does not use
 the zero size extensions.
 
 Because there is the risk of false positives, the higher warning
 level is not used by default.
 
 
 Martin

 

* gcc/tree-vrp.c (check_array_ref): Emit more warnings
   for warn_array_bounds = 2.
* gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
* gcc/c-family/c.opt: New option -Warray-bounds=.
* gcc/common.opt: New option -Warray-bounds=.
* gcc/doc/invoke.texi: Document new option.



diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 064c69e..e61fc56 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -279,6 +279,10 @@ Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
 
+Warray-bounds=
+LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
+; in common.opt
+
 Wassign-intercept
 ObjC ObjC++ Var(warn_assign_intercept) Warning
 Warn whenever an Objective-C assignment is being intercepted by the garbage 
collector
diff --git a/gcc/common.opt b/gcc/common.opt
index e104269..3d19875 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -529,6 +529,10 @@ Warray-bounds
 Common Var(warn_array_bounds) Warning
 Warn if an array is accessed out of bounds
 
+Warray-bounds=
+Common Joined RejectNegative UInteger Var(warn_array_bounds) Warning
+Warn if an array is accessed out of bounds
+
 Wattributes
 Common Var(warn_attributes) Init(1) Warning
 Warn about inappropriate attribute usage
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ed23f6f..f20cbf0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -240,7 +240,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
--Waggressive-loop-optimizations -Warray-bounds @gol
+-Waggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wbool-compare @gol
 -Wno-attributes -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -3382,7 +3382,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect 
Options}.
 @option{-Wall} turns on the following warning flags:
 
 @gccoptlist{-Waddress   @gol
--Warray-bounds @r{(only with} @option{-O2}@r{)}  @gol
+-Warray-bounds=1 @r{(only with} @option{-O2}@r{)}  @gol
 -Wc++11-compat  -Wc++14-compat@gol
 -Wchar-subscripts  @gol
 -Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
@@ -4296,12 +4296,26 @@ Warn about overriding virtual functions that are not 
marked with the override
 keyword.
 
 @item -Warray-bounds
+@itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
 @opindex Warray-bounds
 This option is only active when @option{-ftree-vrp} is active
 (default for @option{-O2} and above). It warns about subscripts to arrays
 that are always out of bounds. This warning is enabled by @option{-Wall}.
 
+@table @gcctabopt
+@item -Warray-bounds=1
+This is the warning level of @option{-Warray-bounds} and is enabled
+by @option{-Wall}; higher levels are not, and must be explicitly requested.
+
+@item -Warray-bounds=2
+This warning level also warns about out of bounds access for
+arrays at the end of a struct and for arrays accessed through
+pointers. This warning level may give a larger number of
+false positives and is deactivated by default.
+@end table
+
+
 @item -Wbool-compare
 @opindex Wno-bool-compare
 @opindex Wbool-compare
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c 
b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
new file mode 100644
index 000..2e68498
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options -O3 -Warray-bounds=2 } */
+
+extern void* malloc(unsigned long x);
+
+int e[3];
+
+struct f { int f[3]; };
+
+extern void bar(int v[]);
+
+struct h {
+
+   int i;
+   int j[];
+};
+
+struct h0 {
+
+   int i;
+   int j[0];
+};
+
+struct h0b {
+
+   int i;
+   int j[0];
+   int k;
+};
+
+struct h1 {
+
+   int i;
+   int j[1];
+};
+
+struct h1b {
+
+   int i;
+   int j[1];
+   int k;
+};
+
+struct h3 {
+
+   int i;
+   int j[3];
+};
+
+struct h3b {
+
+   int i;
+   int j[3];
+   int k;
+};
+
+void foo(int (*a)[3

[PATCH v5] warning about const multidimensional array as function parameter

2014-12-08 Thread Martin Uecker



Another version of this patch. I fixed the formatting problems and 
the spurios use of OPT_Wdiscarded_array_qualifiers. I also added 
'-pedantic -Wdiscarded-array-qualifiers' to the dg-options in
'testsuite/gcc.dg/qual-component-1.c' and changed the expected 
warnings to the new ones. For some reason, the changes to this
file were missing in my previous versions. (scroll down to the
end for this file)

Thank you,
Martin


2014-12-08 Martin Uecker uec...@eecs.berkeley.edu

* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with 
qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from 
element type.
(build_conditional_expr): Add warnings for lost qualifiers.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Adapt warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS 
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)
* gcc.dg/qual-component-1.c: Change dg-options, dg-warnings


Index: gcc/c/c-typeck.c
===
--- gcc/c/c-typeck.c(Revision 218476)
+++ gcc/c/c-typeck.c(Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
 mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
   target = composite_type (mv1, mv2);
 
+  /* Strip array types to get correct qualifier for pointers to arrays */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
   /* For function types do not merge const qualifiers, but drop them
  if used inconsistently.  The middle-end uses these to mark const
  and noreturn functions.  */
-  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
-  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
 target_quals = (quals1  quals2);
   else
@@ -1224,6 +1225,7 @@ static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
+  int val_ped;
   tree mvl = TREE_TYPE (ttl);
   tree mvr = TREE_TYPE (ttr);
   addr_space_t asl = TYPE_ADDR_SPACE (mvl);
@@ -1235,19 +1237,32 @@ comp_target_types (location_t location, tree ttl,
   if (!addr_space_superset (asl, asr, as_common))
 return 0;
 
-  /* Do not lose qualifiers on element types of array types that are
- pointer targets by taking their TYPE_MAIN_VARIANT.  */
-  if (TREE_CODE (mvl) != ARRAY_TYPE)
-mvl = (TYPE_ATOMIC (mvl)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvl));
-  if (TREE_CODE (mvr) != ARRAY_TYPE)
-mvr = (TYPE_ATOMIC (mvr)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvr));
+  /* For pedantic record result of comptypes on arrays before losing
+ qualifiers on the element type below. */
+  val_ped = 1;
+
+  if (TREE_CODE (mvl) == ARRAY_TYPE
+   TREE_CODE (mvr) == ARRAY_TYPE)
+val_ped = comptypes (mvl, mvr);
+
+  /* Qualifiers on element types of array types that are
+ pointer targets are lost by taking their TYPE_MAIN_VARIANT.  */
+
+  mvl = (TYPE_ATOMIC (strip_array_types (mvl))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvl));
+
+  mvr = (TYPE_ATOMIC (strip_array_types (mvr))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvr));
+
   enum_and_int_p = false;
   val = comptypes_check_enum_int (mvl, mvr, enum_and_int_p);
 
+  if (val == 1  val_ped != 1)
+pedwarn (location, OPT_Wpedantic, pointers to arrays with different 
qualifiers 
+  are incompatible in ISO C);
+
   if (val == 2)
 pedwarn (location, OPT_Wpedantic, types are not quite compatible);
 
@@ -4609,6 +4624,13 @@ build_conditional_expr (location_t colon_loc, tree
   else if (VOID_TYPE_P (TREE_TYPE (type1))
!TYPE_ATOMIC (TREE_TYPE (type1)))
{
+ if ((TREE_CODE (TREE_TYPE (type2)) == ARRAY_TYPE)
+  (TYPE_QUALS (strip_array_types (TREE_TYPE (type2)))
+  ~TYPE_QUALS (TREE_TYPE (type1
+   warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers,
+   pointer to array loses

[PATCH] add option to emit more array bounds warnigs

2014-11-11 Thread Martin Uecker

Hi,

this proposed patch adds an option -Warray-bounds= in addition to
-Warray-bound. -Warray-bounds=1 corresponds to -Warray-bound.
For higher warning levels more warnings about optional accesses
outside of arrays are emitted. For example, warnings for
arrays accessed through pointers are now emitted:

void foo(int (*a)[3])
{
(*a)[4] = 1;
}

Also warnings for arrays which are the last element of a struct
are emitted, if it is not a flexible array member or does not use
the zero size extensions.

Because there is the risk of false positives, the higher warning
level is not used by default.


Martin


* gcc/tree-vrp.c (check_array_ref): Emit more warnings
   for warn_array_bounds = 2.
* gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
* gcc/c-family/c.opt: New option -Warray-bounds=.
* gcc/common.opt: New option -Warray-bounds=.
* gcc/doc/invoke.texi: Document new option.


diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 66c62fb..0d5ecfd 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -279,6 +279,10 @@ Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
 
+Warray-bounds=
+LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
+; in common.opt
+
 Wassign-intercept
 ObjC ObjC++ Var(warn_assign_intercept) Warning
 Warn whenever an Objective-C assignment is being intercepted by the garbage 
collector
diff --git a/gcc/common.opt b/gcc/common.opt
index b400636..d65085a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -525,6 +525,10 @@ Warray-bounds
 Common Var(warn_array_bounds) Warning
 Warn if an array is accessed out of bounds
 
+Warray-bounds=
+Common Joined RejectNegative UInteger Var(warn_array_bounds) Warning
+Warn if an array is accessed out of bounds
+
 Wattributes
 Common Var(warn_attributes) Init(1) Warning
 Warn about inappropriate attribute usage
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 57666db..afc4be8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -239,7 +239,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
--Waggressive-loop-optimizations -Warray-bounds @gol
+-Waggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wbool-compare @gol
 -Wno-attributes -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -3344,7 +3344,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect 
Options}.
 @option{-Wall} turns on the following warning flags:
 
 @gccoptlist{-Waddress   @gol
--Warray-bounds @r{(only with} @option{-O2}@r{)}  @gol
+-Warray-bounds=1 @r{(only with} @option{-O2}@r{)}  @gol
 -Wc++11-compat  @gol
 -Wchar-subscripts  @gol
 -Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
@@ -4239,12 +4239,26 @@ hiearchy graph is more complete. It is recommended to 
first consider suggestins
 of @option{-Wsuggest-final-types} and then rebuild with new annotations.
 
 @item -Warray-bounds
+@itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
 @opindex Warray-bounds
 This option is only active when @option{-ftree-vrp} is active
 (default for @option{-O2} and above). It warns about subscripts to arrays
 that are always out of bounds. This warning is enabled by @option{-Wall}.
 
+@table @gcctabopt
+@item -Warray-bounds=1
+This is the warning level of @option{-Warray-bounds} and is enabled
+by @option{-Wall}; higher levels are not, and must be explicitly requested.
+
+@item -Warray-bounds=2
+This warning level also warns about out of bounds access for
+arrays at the end of a struct and for arrays accessed through
+pointers. This warning level may give a larger number of
+false positives and is deactivated by default.
+@end table
+
+
 @item -Wbool-compare
 @opindex Wno-bool-compare
 @opindex Wbool-compare
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c 
b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
new file mode 100644
index 000..2e68498
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options -O3 -Warray-bounds=2 } */
+
+extern void* malloc(unsigned long x);
+
+int e[3];
+
+struct f { int f[3]; };
+
+extern void bar(int v[]);
+
+struct h {
+
+   int i;
+   int j[];
+};
+
+struct h0 {
+
+   int i;
+   int j[0];
+};
+
+struct h0b {
+
+   int i;
+   int j[0];
+   int k;
+};
+
+struct h1 {
+
+   int i;
+   int j[1];
+};
+
+struct h1b {
+
+   int i;
+   int j[1];
+   int k;
+};
+
+struct h3 {
+
+   int i;
+   int j[3];
+};
+
+struct h3b {
+
+   int i;
+   int j[3];
+   int k;
+};
+
+void foo(int (*a)[3])
+{
+   (*a)[4] = 1;/* { dg-warning subscript is above array bound } */
+   a[0][0] = 1;// ok
+   a[1][0] = 1;// ok
+   a[1][4] = 1;/* { dg-warning subscript is above array bound } */
+
+   int c[3] = { 0 };
+
+   c[4] = 1;   /* { dg-warning subscript is 

[PATCH v4] warning about const multidimensional array as function parameter

2014-11-10 Thread Martin Uecker

For completeness, this version adds the missing warning if the 
'const' is lost in a conditional expression with a void* on the
other branch. The only code change relative to the previous
version is in c/c-typeck.c in build_conditional_expr (otherwise 
I added the warnings to the testsuite and fixed some typos and 
trailing whitespace errors).

I would rather have the 'const' propagate to the result
of the conditional expression as with regular pointers to
const, but I do not see an easy way to make the warnings
(or errors) which could result from this be dependent on 
-Wdiscarded-array-qualifiers.

Joseph Myers jos...@codesourcery.com:

 On Thu, 6 Nov 2014, Martin Uecker wrote:
  This patch implements a new proposed behaviour for 
  pointers to arrays with qualifiers in C.
  
  I found some time to work on this again, so here is another 
  revision. Main changes to the previous version of the patch:
  
  - add more test cases for cast from/to (const) void*
  - correctly uses pedwarn/warning_at
 
 Thanks.  I'll review this in more detail later, but I suspect it's quite 
 close to being ready to go in once the paperwork has been processed.

Thank you. I got the form and have sent it back, but did not get
a reply yet.
 
Martin


2014-11-10 Martin Uecker uec...@eecs.berkeley.edu

* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with 
qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from 
element type.
(build_conditional_expr): Add warnings for lost qualifiers.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Adapt warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS 
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)




Index: gcc/c/c-typeck.c
===
--- gcc/c/c-typeck.c(Revision 217273)
+++ gcc/c/c-typeck.c(Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
 mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
   target = composite_type (mv1, mv2);
 
+  /* Strip array types to get correct qualifier for pointers to arrays */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
   /* For function types do not merge const qualifiers, but drop them
  if used inconsistently.  The middle-end uses these to mark const
  and noreturn functions.  */
-  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
-  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
 target_quals = (quals1  quals2);
   else
@@ -1224,6 +1225,7 @@ static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
+  int val_ped;
   tree mvl = TREE_TYPE (ttl);
   tree mvr = TREE_TYPE (ttr);
   addr_space_t asl = TYPE_ADDR_SPACE (mvl);
@@ -1235,19 +1237,32 @@ comp_target_types (location_t location, tree ttl,
   if (!addr_space_superset (asl, asr, as_common))
 return 0;
 
-  /* Do not lose qualifiers on element types of array types that are
- pointer targets by taking their TYPE_MAIN_VARIANT.  */
-  if (TREE_CODE (mvl) != ARRAY_TYPE)
-mvl = (TYPE_ATOMIC (mvl)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvl));
-  if (TREE_CODE (mvr) != ARRAY_TYPE)
-mvr = (TYPE_ATOMIC (mvr)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvr));
+  /* For pedantic record result of comptypes on arrays before losing
+ qualifiers on the element type below. */
+  val_ped = 1;
+
+  if (TREE_CODE (mvl) == ARRAY_TYPE
+   TREE_CODE (mvr) == ARRAY_TYPE)
+val_ped = comptypes (mvl, mvr);
+
+  /* Qualifiers on element types of array types that are
+ pointer targets are lost by taking their TYPE_MAIN_VARIANT.  */
+
+  mvl = (TYPE_ATOMIC (strip_array_types (mvl))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvl));
+
+  mvr = (TYPE_ATOMIC (strip_array_types (mvr))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvr));
+
   enum_and_int_p = false;
   val = comptypes_check_enum_int (mvl, mvr, enum_and_int_p

[PATCH v3] warning about const multidimensional array as function parameter

2014-11-06 Thread Martin Uecker


This patch implements a new proposed behaviour for 
pointers to arrays with qualifiers in C.

I found some time to work on this again, so here is another 
revision. Main changes to the previous version of the patch:

- add more test cases for cast from/to (const) void*
- correctly uses pedwarn/warning_at


previous versions (see v1 for a description of the main idea):
v2: https://gcc.gnu.org/ml/gcc/2014-10/msg00243.html
v1: https://gcc.gnu.org/ml/gcc/2014-10/msg00224.html



On Wed, 29 Oct 2014 16:43:16 +
Joseph S. Myers jos...@codesourcery.com:
 On Tue, 28 Oct 2014, Martin Uecker wrote:

  Note that there is now a semantic (and not only diagnostic) change.
  Without this patch
  
  const int a[1];
  int b[1];
  (x ? a : b)
  
  would return a 'void*' and a warning about pointer type mismatch.
  With this patch the conditional has type 'const int (*)[1]'.
 
 I believe that is safe (in that that conditional expression isn't valid in 
 ISO C).  What wouldn't be safe is making a conditional expression between 
 void * and const int (*)[] have type const void * instead of void *.

Yes, the cases which are changed in the patch should all
be illegal in ISO C. 

On the other hand, not changing the case you mention means that
there is still inconsistent behaviour even with the patch:
 
void* v;
const int (*i)[1];
int (*ip)[1] = (1 ? v : i); // const is lost in conditional

const int (*i2);
int (*ip2) = (1 ? v : i2);  // const is not lost - warning

Maybe I should at least add a warning for the first case where the 
'const' is lost already in the conditional?


 WARN_FOR_QUALIFIERS uses pedwarn.  That means this is not safe, because 
 pedwarns become errors with -pedantic-errors, but this includes cases that 
 are valid in ISO C and so must not become errors with -pedantic-errors 
 (such as converting const int (*)[] to void *).

Ok. I added a new macro WARNING_FOR_QUALIFIERS and renamed the others
to PEDWARN_FOR_* . The full logic to make this work correctly turned
out to be quite simple. 

The behaviour can be summarized like this:

p2ca = pointer to const array
p2cv = pointer to const void
...

lq = loss of qualifier
ip = incompatible pointer 
'!' error with -pedantic-errors
'*' can be deactivated with a new option

conversionold  new   new+pedantic
p2ca - p2a : ip! | lq* | ip! + lq*
p2a  - p2ca: ip! | | ip!
p2v  - p2a : | | 
p2v - p2ca : | |
p2cv - p2a : lq! | lq! | lq!
p2cv - p2ca: lq! | | lq!
p2a - p2v  : | | 
p2a - p2cv : | |
p2ca - p2v : | lq* | lq*
p2ca - p2cv: | |




2014-10-28 Martin Uecker uec...@eecs.berkeley.edu

* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with 
qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from 
element type.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Change warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS 
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)


Index: gcc/c/c-typeck.c
===
--- gcc/c/c-typeck.c(Revision 217175)
+++ gcc/c/c-typeck.c(Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
 mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
   target = composite_type (mv1, mv2);
 
+  /* Strip array types to get correct qualifier for pointers to arrays */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
   /* For function types do not merge const qualifiers, but drop them
  if used inconsistently.  The middle-end uses these to mark const
  and noreturn functions.  */
-  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
-  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
 target_quals = (quals1  quals2);
   else
@@ -1224,6 +1225,7 @@ static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
+  int val_ped;
   tree mvl = TREE_TYPE (ttl);
   tree mvr = TREE_TYPE (ttr);
   addr_space_t asl = TYPE_ADDR_SPACE (mvl);
@@ -1235,19 +1237,32 @@ comp_target_types (location_t location, tree ttl,
   if (!addr_space_superset (asl, asr, as_common))
 return 0;
 
-  /* Do not lose qualifiers on element

<    1   2   3