public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [GCC 13][PATCH] PR101836: Add a new option -fstrict-flex-array[=n] and use it in __builtin_object_size
@ 2022-06-27 14:19 Qing Zhao
  2022-06-28  7:16 ` Richard Biener
  0 siblings, 1 reply; 30+ messages in thread
From: Qing Zhao @ 2022-06-27 14:19 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches Paul A Clarke via
  Cc: kees Cook, siddhesh Poyarekar, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 2528 bytes --]

Hi, 

Per our discussion in the bug report, I came up with the following patch:

=======

PR101836: Add a new option -fstrict-flex-array[=n]

Add the new option and use it in __builtin_object_size.

Treat the trailing array of a structure as a flexible array member in a
stricter way.  The value of 'n' controls the level of strictness.
'n'=0 is the least strict, all trailing arrays of structures are treated
as flexible array members; This is the default behavior of GCC without specify
this option.
'n'=3 is the strictest, only when the trailing array is declared as a
flexible array member per C99 standard onwards ([]), it is treated as a
flexible array member;
There are two more levels in between 0 and 3, which are provided to support
older codes that use GCC zero-length array extension ([0]), or one-size array as
flexible array member ([1]):
When 'n' is 1, the trailing array is treated as a flexible array member
when it is declared as either [], [0], or [1];
When 'n' is 2, the trailing array is treated as a flexible array member
when it is declared as either [], or [0].

There are other places in GCC that conservatively treat flexible array members.
A follow-up patch will make -ftrict-flex-array option to control all these
places consistently.

Bootstrapped and regression tested on both X86 and aarch64, no issues.

Any comment and suggestion?

Okay for commit to Gcc13?

thanks.

Qing

=======================

gcc/

       PR tree-optimization/101836
       * common.opt (fstrict-flex-array, fstrict-flex-array=): New options.
       * doc/invoke.texi (-fstrict-flex-array, -fstrict-flex-array=): Document.
       * tree-object-size.cc (addr_object_size): Call is_flexible_array_p to
       check whether an array is a flexible array.
       * tree.cc (special_array_member_type): New routine.
       (is_flexible_array_p): New routine.
       (component_ref_size): Call special_array_member_type to decide the
       type of special array member.
       * tree.h (enum struct special_array_member): Add is_vla, trail_flex.
       (special_array_member_type): New prototype.
       (is_flexible_array_p): New prototype.

gcc/testsuite/

       PR tree-optimization/101836
       * gcc.dg/pr101836.c: New test.
       * gcc.dg/pr101836_1.c: New test.
       * gcc.dg/pr101836_2.c: New test.
       * gcc.dg/pr101836_3.c: New test.
       * gcc.dg/pr101836_4.c: New test.
       * gcc.dg/pr101836_5.c: New test.


The complete patch is:


[-- Attachment #2: 0001-PR101836-Add-a-new-option-fstrict-flex-array-n.patch --]
[-- Type: application/octet-stream, Size: 26062 bytes --]

From 880f1024c5d1b8d118ff3c84d3da43aebc0ad27a Mon Sep 17 00:00:00 2001
From: Qing Zhao <qing.zhao@oracle.com>
Date: Thu, 16 Jun 2022 21:05:39 +0000
Subject: [PATCH] PR101836: Add a new option -fstrict-flex-array[=n]

Add the new option and use it in __builtin_object_size.

Treat the trailing array of a structure as a flexible array member in a
stricter way.  The value of 'n' controls the level of strictness.
'n'=0 is the least strict, all trailing arrays of structures are treated
as flexible array members; This is the default behavior of GCC without specify
this option.
'n'=3 is the strictest, only when the trailing array is declared as a
flexible array member per C99 standard onwards ([]), it is treated as a
flexible array member;
There are two more levels in between 0 and 3, which are provided to support
older codes that use GCC zero-length array extension ([0]), or one-size array as
flexible array member ([1]):
When 'n' is 1, the trailing array is treated as a flexible array member
when it is declared as either [], [0], or [1];
When 'n' is 2, the trailing array is treated as a flexible array member
when it is declared as either [], or [0].

There are other places in GCC that conservatively treat flexible array members.
A follow-up patch will make -ftrict-flex-array option to control all these
places consistently.

gcc/

	PR tree-optimization/101836
	* common.opt (fstrict-flex-array, fstrict-flex-array=): New options.
	* doc/invoke.texi (-fstrict-flex-array, -fstrict-flex-array=): Document.
	* tree-object-size.cc (addr_object_size): Call is_flexible_array_p to
	check whether an array is a flexible array.
	* tree.cc (special_array_member_type): New routine.
	(is_flexible_array_p): New routine.
	(component_ref_size): Call special_array_member_type to decide the
	type of special array member.
	* tree.h (enum struct special_array_member): Add is_vla, trail_flex.
	(special_array_member_type): New prototype.
	(is_flexible_array_p): New prototype.

gcc/testsuite/

	PR tree-optimization/101836
	* gcc.dg/pr101836.c: New test.
	* gcc.dg/pr101836_1.c: New test.
	* gcc.dg/pr101836_2.c: New test.
	* gcc.dg/pr101836_3.c: New test.
	* gcc.dg/pr101836_4.c: New test.
	* gcc.dg/pr101836_5.c: New test.
---
 gcc/common.opt                    |   8 ++
 gcc/doc/invoke.texi               |  33 ++++++-
 gcc/testsuite/gcc.dg/pr101836.c   |  60 +++++++++++
 gcc/testsuite/gcc.dg/pr101836_1.c |  60 +++++++++++
 gcc/testsuite/gcc.dg/pr101836_2.c |  60 +++++++++++
 gcc/testsuite/gcc.dg/pr101836_3.c |  60 +++++++++++
 gcc/testsuite/gcc.dg/pr101836_4.c |  60 +++++++++++
 gcc/testsuite/gcc.dg/pr101836_5.c |  60 +++++++++++
 gcc/tree-object-size.cc           |  16 ++-
 gcc/tree.cc                       | 159 ++++++++++++++++++++++--------
 gcc/tree.h                        |  16 ++-
 11 files changed, 536 insertions(+), 56 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr101836.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr101836_5.c

diff --git a/gcc/common.opt b/gcc/common.opt
index 32917aafcae..e28697ab8b1 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2772,6 +2772,14 @@ fstrict-aliasing
 Common Var(flag_strict_aliasing) Optimization
 Assume strict aliasing rules apply.
 
+fstrict-flex-array
+Common Alias(fstrict-flex-array=,3,0)
+
+fstrict-flex-array=
+Common Joined RejectNegative UInteger Var(flag_strict_flex_array) Init(0) IntegerRange(0,3) Optimization
+-fstrict-flex-array=<level>    Treat the trailing array of a structure as a flexible array in a stricter way.  The default is treating all trailing arrays of structures as flexible arrays.
+
+
 fstrict-overflow
 Common
 Treat signed overflow as undefined.  Negated as -fwrapv -fwrapv-pointer.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 81d13f4e78e..7a72e29cedf 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -579,7 +579,7 @@ Objective-C and Objective-C++ Dialects}.
 -fsplit-paths @gol
 -fsplit-wide-types  -fsplit-wide-types-early  -fssa-backprop  -fssa-phiopt @gol
 -fstdarg-opt  -fstore-merging  -fstrict-aliasing -fipa-strict-aliasing @gol
--fthread-jumps  -ftracer  -ftree-bit-ccp @gol
+-fstrict-flex-array[=@var{n}] -fthread-jumps  -ftracer  -ftree-bit-ccp @gol
 -ftree-builtin-call-dce  -ftree-ccp  -ftree-ch @gol
 -ftree-coalesce-vars  -ftree-copy-prop  -ftree-dce  -ftree-dominator-opts @gol
 -ftree-dse  -ftree-forwprop  -ftree-fre  -fcode-hoisting @gol
@@ -12787,6 +12787,37 @@ function boundary.
 The @option{-fipa-strict-aliasing} option is enabled by default and is
 effective only in combination with @option{-fstrict-aliasing}.
 
+@item -fstrict-flex-array
+@opindex fstrict-flex-array
+@opindex fno-strict-flex-array
+Treat the trailing array of a structure as a flexible array member in a
+stricter way.
+The positive form is equivalent to @option{-fstrict-flex-array=3}, which is the
+strictest.  A trailing array is treated as a flexible array member only when it
+is declared as a flexible array member per C99 standard onwards.
+The negative form is equivalent to @option{-fstrict-flex-array=0}, which is the
+least strict.  All trailing arrays of structures are treated as flexible array
+members.
+
+@item -fstrict-flex-array=@var{n}
+@opindex fstrict-flex-array=@var{n}
+Treat the trailing array of a structure as a flexible array member in a
+stricter way.  The value of @var{n} controls the level of strictness.
+@var{n} is 0 is the least strict, all trailing arrays of structures are treated
+as flexible array members; This is the default behavior of GCC without specify
+this option.
+@var{n} is 3 is the strictest, only when the trailing array is declared as a
+flexible array member per C99 standard onwards ([]), it is treated as a
+flexible array member;
+There are two more levels in between 0 and 3, which are provided to support
+older codes that use GCC zero-length array extension ([0]), or one-size array as
+flexible array member ([1]):
+When @var{n} is 1, the trailing array is treated as a flexible array member
+when it is declared as either [], [0], or [1];
+When @var{n} is 2, the trailing array is treated as a flexible array member
+when it is declared as either [], or [0].
+
+
 @item -falign-functions
 @itemx -falign-functions=@var{n}
 @itemx -falign-functions=@var{n}:@var{m}
diff --git a/gcc/testsuite/gcc.dg/pr101836.c b/gcc/testsuite/gcc.dg/pr101836.c
new file mode 100644
index 00000000000..e5b4e5160a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836.c
@@ -0,0 +1,60 @@
+/* -fstrict-flex-array is aliased with -ftrict-flex-array=3, which is the
+   strictest, only [] is treated as flexible array.  */ 
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-array" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4];
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1];
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), 0);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr101836_1.c b/gcc/testsuite/gcc.dg/pr101836_1.c
new file mode 100644
index 00000000000..30ea20427a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_1.c
@@ -0,0 +1,60 @@
+/* -fstrict-flex-array=3 is the strictest, only [] is treated as
+   flexible array.  */ 
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-array=3" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4];
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1];
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), 0);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr101836_2.c b/gcc/testsuite/gcc.dg/pr101836_2.c
new file mode 100644
index 00000000000..ebbe88f433c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_2.c
@@ -0,0 +1,60 @@
+/* When -fstrict-flex-array=2, only [] and [0] are treated as flexiable
+   arrays.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-array=2" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4];
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1];
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), 4);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr101836_3.c b/gcc/testsuite/gcc.dg/pr101836_3.c
new file mode 100644
index 00000000000..d4ba0afe5bc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_3.c
@@ -0,0 +1,60 @@
+/* When -fstrict-flex-array=1, [], [0], and [1] are treated as flexible
+   arrays.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-array=1" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4];
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1];
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    expect(__builtin_object_size(normal->c, 1), 16);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr101836_4.c b/gcc/testsuite/gcc.dg/pr101836_4.c
new file mode 100644
index 00000000000..b10d3ce312d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_4.c
@@ -0,0 +1,60 @@
+/* when -fstrict-flex-array=0, all trailing arrays are treated as
+   flexible arrays.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-array=0" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4];
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1];
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    expect(__builtin_object_size(normal->c, 1), -1);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr101836_5.c b/gcc/testsuite/gcc.dg/pr101836_5.c
new file mode 100644
index 00000000000..2f6b5f7ae1f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101836_5.c
@@ -0,0 +1,60 @@
+/* -fno-strict-flex-array is aliased to -fstrict-flex-array=0,
+   all trailing arrays are treated as flexible array.  */
+/* PR tree-optimization/101836 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-strict-flex-array" } */
+
+#include <stdio.h>
+
+#define expect(p, _v) do { \
+    size_t v = _v; \
+    if (p == v) \
+        printf("ok:  %s == %zd\n", #p, p); \
+    else \
+	{  \
+          printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+	  __builtin_abort (); \
+	} \
+} while (0);
+
+struct trailing_array_1 {
+    int a;
+    int b;
+    int c[4];
+};
+
+struct trailing_array_2 {
+    int a;
+    int b;
+    int c[1];
+};
+
+struct trailing_array_3 {
+    int a;
+    int b;
+    int c[0];
+};
+struct trailing_array_4 {
+    int a;
+    int b;
+    int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+    struct trailing_array_1 *normal,
+    struct trailing_array_2 *trailing_1,
+    struct trailing_array_3 *trailing_0,
+    struct trailing_array_4 *trailing_flex)
+{
+    expect(__builtin_object_size(normal->c, 1), -1);
+    expect(__builtin_object_size(trailing_1->c, 1), -1);
+    expect(__builtin_object_size(trailing_0->c, 1), -1);
+    expect(__builtin_object_size(trailing_flex->c, 1), -1);
+}
+
+int main(int argc, char *argv[])
+{
+    stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
+
+    return 0;
+}
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 12bc0868b77..9f6e78640ed 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -604,9 +604,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 	  else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
 	    {
 	      tree v = var;
-	      /* For &X->fld, compute object size only if fld isn't the last
-		 field, as struct { int i; char c[1]; } is often used instead
-		 of flexible array member.  */
+	      bool is_flexible_array = false;
+	      /* For &X->fld, compute object size if fld isn't a flexible array
+		 member.  */
 	      while (v && v != pt_var)
 		switch (TREE_CODE (v))
 		  {
@@ -628,6 +628,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 		    v = NULL_TREE;
 		    break;
 		  case COMPONENT_REF:
+		    is_flexible_array = is_flexible_array_p (v);
 		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
 		      {
 			v = NULL_TREE;
@@ -645,12 +646,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
 			   == RECORD_TYPE)
 		      {
-			tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
-			for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
-			  if (TREE_CODE (fld_chain) == FIELD_DECL)
-			    break;
-
-			if (fld_chain)
+			/* compute object size only if v is not a
+			   flexible array member.  */
+			if (!is_flexible_array)
 			  {
 			    v = NULL_TREE;
 			    break;
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2bfb67489c6..329684b57df 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12762,6 +12762,112 @@ array_at_struct_end_p (tree ref)
   return true;
 }
 
+/* Return the type of special_array_member for the COMPONENT_REF REF.  */
+special_array_member
+special_array_member_type (tree ref)
+{
+  gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+  bool trailing = array_at_struct_end_p (ref);
+  special_array_member sam = special_array_member::none;
+
+  /* if this reference is a trailing array, and has a C99 flexible array
+     member type, it's a real flexible array member.  */
+  if (trailing && flexible_array_type_p (TREE_TYPE (TREE_OPERAND (ref, 0))))
+    return special_array_member::trail_flex;
+
+  /* The referenced member.  */
+  tree member = TREE_OPERAND (ref, 1);
+  tree memtype = TREE_TYPE (member);
+
+  /* If the type of the referenced member is not ARRAY, not a special
+     array member.  */
+  if (TREE_CODE (memtype) != ARRAY_TYPE)
+    return sam;
+
+  tree memsize = DECL_SIZE_UNIT (member);
+  if (memsize)
+    {
+      bool zero_length = integer_zerop (memsize);
+      if (!trailing && !zero_length)
+	/* MEMBER is either an interior array or is an array with
+	   more than one element, not a special array member.  */
+	return sam;
+
+      if (zero_length)
+	{
+	  if (trailing)
+	    sam = special_array_member::trail_0;
+	  else
+	    sam = special_array_member::int_0;
+	}
+      else
+	if (tree dom = TYPE_DOMAIN (memtype))
+	  if (tree min = TYPE_MIN_VALUE (dom))
+	    if (tree max = TYPE_MAX_VALUE (dom))
+	      if (TREE_CODE (min) == INTEGER_CST
+		  && TREE_CODE (max) == INTEGER_CST)
+		{
+		  offset_int minidx = wi::to_offset (min);
+		  offset_int maxidx = wi::to_offset (max);
+		  offset_int neltsm1 = maxidx - minidx;
+		  if (neltsm1 > 0)
+		    /* MEMBER is an array with a constant size which is more
+		       than one element, not a special array member.  */
+		    return sam;
+
+		  if (neltsm1 == 0 && trailing)
+		    sam = special_array_member::trail_1;
+		}
+      /* When getting here and the type has not been decided yet, the array is
+	 a variable length array.  */
+      if (sam == special_array_member::none)
+	  sam = special_array_member::is_vla;
+
+    }
+  return sam;
+}
+
+/* Check whether the component reference REF is a flexible array:
+   it's decided based on the value of flag_strict_flex_array.  */
+bool
+is_flexible_array_p (tree ref)
+{
+  gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+
+  bool is_trailing_array = array_at_struct_end_p (ref);
+  bool is_flexible_array = false;
+
+  /* Set for accesses to special trailing arrays.  */
+  special_array_member sam = special_array_member_type (ref);
+
+  switch (flag_strict_flex_array)
+    {
+      case 0:
+	/* default, all trailing arrays are flexiable arrays.  */
+	is_flexible_array = is_trailing_array;
+	break;
+      case 1:
+	/* Level 1: all [1], [0], and [] are flexiable arrays.  */
+	if (sam == special_array_member::trail_1)
+	  is_flexible_array = is_trailing_array;
+	/* FALLTHROUGH */
+      case 2:
+	/* Level 2: all [0], and [] are flexiable arrays.  */
+	if (sam == special_array_member::trail_0)
+	  is_flexible_array = is_trailing_array;
+	/* FALLTHROUGH */
+      case 3:
+	/* Level 3: Only [] are flexiable arrays.  */
+	if (sam == special_array_member::trail_flex)
+	  is_flexible_array = is_trailing_array;
+	break;
+      default:
+	gcc_unreachable ();
+    }
+
+  return is_flexible_array;
+}
+
 /* Return a tree representing the offset, in bytes, of the field referenced
    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
 
@@ -12831,12 +12937,9 @@ get_initializer_for (tree init, tree decl)
 tree
 component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 {
-  gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
-
-  special_array_member sambuf;
-  if (!sam)
-    sam = &sambuf;
-  *sam = special_array_member::none;
+  special_array_member temp_sam = special_array_member_type (ref);
+  if (sam)
+    *sam = temp_sam;
 
   /* The object/argument referenced by the COMPONENT_REF and its type.  */
   tree arg = TREE_OPERAND (ref, 0);
@@ -12857,41 +12960,13 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 	return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
 		? memsize : NULL_TREE);
 
-      bool trailing = array_at_struct_end_p (ref);
-      bool zero_length = integer_zerop (memsize);
-      if (!trailing && !zero_length)
+      if (temp_sam == special_array_member::none)
 	/* MEMBER is either an interior array or is an array with
-	   more than one element.  */
+	   more than one element, i.e, a normal array.  */
 	return memsize;
 
-      if (zero_length)
-	{
-	  if (trailing)
-	    *sam = special_array_member::trail_0;
-	  else
-	    {
-	      *sam = special_array_member::int_0;
-	      memsize = NULL_TREE;
-	    }
-	}
-
-      if (!zero_length)
-	if (tree dom = TYPE_DOMAIN (memtype))
-	  if (tree min = TYPE_MIN_VALUE (dom))
-	    if (tree max = TYPE_MAX_VALUE (dom))
-	      if (TREE_CODE (min) == INTEGER_CST
-		  && TREE_CODE (max) == INTEGER_CST)
-		{
-		  offset_int minidx = wi::to_offset (min);
-		  offset_int maxidx = wi::to_offset (max);
-		  offset_int neltsm1 = maxidx - minidx;
-		  if (neltsm1 > 0)
-		    /* MEMBER is an array with more than one element.  */
-		    return memsize;
-
-		  if (neltsm1 == 0)
-		    *sam = special_array_member::trail_1;
-		}
+      if (temp_sam == special_array_member::int_0)
+	memsize = NULL_TREE;
 
       /* For a reference to a zero- or one-element array member of a union
 	 use the size of the union instead of the size of the member.  */
@@ -12908,7 +12983,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
   tree base = get_addr_base_and_unit_offset (ref, &baseoff);
   if (!base || !VAR_P (base))
     {
-      if (*sam != special_array_member::int_0)
+      if (temp_sam != special_array_member::int_0)
 	return NULL_TREE;
 
       if (TREE_CODE (arg) != COMPONENT_REF)
@@ -12928,7 +13003,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
   /* Determine the base type of the referenced object.  If it's
      the same as ARGTYPE and MEMBER has a known size, return it.  */
   tree bt = basetype;
-  if (*sam != special_array_member::int_0)
+  if (temp_sam != special_array_member::int_0)
     while (TREE_CODE (bt) == ARRAY_TYPE)
       bt = TREE_TYPE (bt);
   bool typematch = useless_type_conversion_p (argtype, bt);
@@ -12968,7 +13043,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 	  if (DECL_P (base)
 	      && DECL_EXTERNAL (base)
 	      && bt == basetype
-	      && *sam != special_array_member::int_0)
+	      && temp_sam != special_array_member::int_0)
 	    /* The size of a flexible array member of an extern struct
 	       with no initializer cannot be determined (it's defined
 	       in another translation unit and can have an initializer
@@ -13017,7 +13092,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 	  ? NULL_TREE : size_zero_node);
 }
 
-/* Return the machine mode of T.  For vectors, returns the mode of the
+/* Return the macmhine mode of T.  For vectors, returns the mode of the
    inner type.  The main use case is to feed the result to HONOR_NANS,
    avoiding the BLKmode that a direct TYPE_MODE (T) might return.  */
 
diff --git a/gcc/tree.h b/gcc/tree.h
index 507ea252b95..cd1c30ee179 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5539,12 +5539,20 @@ extern tree component_ref_field_offset (tree);
    returns null.  */
 enum struct special_array_member
   {
-   none,      /* Not a special array member.  */
-   int_0,     /* Interior array member with size zero.  */
-   trail_0,   /* Trailing array member with size zero.  */
-   trail_1    /* Trailing array member with one element.  */
+   none,       /* Not a special array member.  */
+   is_vla,     /* variable length array.  */
+   int_0,      /* Interior array member with size zero.  */
+   trail_0,    /* Trailing array member with size zero.  */
+   trail_1,    /* Trailing array member with one element.  */
+   trail_flex  /* Flexible array member per C99 standard, [].  */
   };
 
+/* Return the type of special_array_member for the COMPONENT_REF REF.  */
+extern special_array_member special_array_member_type (tree);
+
+/* Check whether the component reference REF is a flexible array.  */
+extern bool is_flexible_array_p (tree);
+
 /* Return the size of the member referenced by the COMPONENT_REF, using
    its initializer expression if necessary in order to determine the size
    of an initialized flexible array member.  The size might be zero for
-- 
2.27.0


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

end of thread, other threads:[~2022-07-07 13:33 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-27 14:19 [GCC 13][PATCH] PR101836: Add a new option -fstrict-flex-array[=n] and use it in __builtin_object_size Qing Zhao
2022-06-28  7:16 ` Richard Biener
2022-06-28 15:03   ` Qing Zhao
2022-06-28 15:08     ` Jakub Jelinek
2022-06-28 15:59       ` Qing Zhao
2022-06-28 16:43         ` Jakub Jelinek
2022-06-28 18:15           ` Qing Zhao
2022-06-28 18:22             ` Jakub Jelinek
2022-06-28 18:29               ` Qing Zhao
2022-06-28 18:49                 ` Jakub Jelinek
2022-06-28 19:01                   ` Qing Zhao
2022-06-29 21:14                     ` Martin Sebor
2022-06-30 14:07                       ` Qing Zhao
2022-06-30 14:24                         ` Richard Biener
2022-06-30 15:31                           ` Qing Zhao
2022-06-30 17:03                             ` Jakub Jelinek
2022-06-30 19:30                               ` Qing Zhao
2022-07-01  6:49                                 ` Richard Biener
2022-07-01 12:55                                   ` Qing Zhao
2022-07-01 12:58                                     ` Richard Biener
2022-07-01 13:40                                       ` Qing Zhao
2022-07-01 12:59                                     ` Jakub Jelinek
2022-07-01 14:01                                       ` Qing Zhao
2022-07-01 15:32                                         ` Martin Sebor
2022-07-04  6:49                                           ` Richard Biener
2022-07-06 14:20                                             ` Qing Zhao
2022-07-07  8:02                                               ` Richard Biener
2022-07-07 13:33                                                 ` Qing Zhao
2022-06-29 20:45           ` Qing Zhao
2022-06-28 16:21   ` Martin Sebor

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