The GCC 11 -Warray-bounds enhancement to diagnose accesses whose
leading offset is in bounds but whose trailing offset is not has
been causing some confusion.  When the warning is issued for
an access to an in-bounds member via a pointer to a struct that's
larger than the pointed-to object, phrasing this strictly invalid
access in terms of array subscripts can be misleading, especially
when the source code doesn't involve any arrays or indexing.

Since the problem boils down to an aliasing violation much more
so than an actual out-of-bounds access, the attached patch adjusts
the code to issue a -Wstrict-aliasing warning in these cases instead
of -Warray-bounds.  In addition, since the aliasing assumptions in
GCC can be disabled by -fno-strict-aliasing, the patch also makes
these instances of the warning conditional on -fstrict-aliasing
being in effect.

Martin
PR middle-end/98503 -Warray-bounds when -Wstrict-aliasing would be more appropriate

gcc/ChangeLog:

	PR middle-end/98503
	* gimple-array-bounds.cc (array_bounds_checker::check_mem_ref):
	Issue -Wstrict-aliasing for a subset of violations.
	(array_bounds_checker::check_array_bounds):  Set new member.
	* gimple-array-bounds.h (array_bounds_checker::cref_of_mref): New
	data member.

gcc/testsuite/ChangeLog:

	PR middle-end/98503
	* g++.dg/warn/Warray-bounds-10.C: Adjust text of expected warnings.
	* g++.dg/warn/Warray-bounds-11.C: Same.
	* g++.dg/warn/Warray-bounds-12.C: Same.
	* g++.dg/warn/Warray-bounds-13.C: Same.
	* gcc.dg/Warray-bounds-63.c: Avoid -Wstrict-aliasing.  Adjust text
	of expected warnings.
	* gcc.dg/Warray-bounds-66.c: Adjust text of expected warnings.
	* gcc.dg/Wstrict-aliasing-2.c: New test.
	* gcc.dg/Wstrict-aliasing-3.c: New test.

diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index 2576556f76b..f6b2af0d681 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -670,6 +670,8 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
 	axssize = wi::to_offset (access_size);
 
   const bool uboob = !lboob && offrange[0] + axssize > ubound;
+  /* Set to OFFRANGE converted to index range.  */
+  offset_int idxrange[2] = { offrange[0], offrange[1] };
   if (lboob || uboob)
     {
       /* Treat a reference to a non-array object as one to an array
@@ -681,43 +683,84 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
 	 to compute the index to print in the diagnostic; arrays
 	 in MEM_REF don't mean anything.  A type with no size like
 	 void is as good as having a size of 1.  */
-      tree type = TREE_TYPE (ref);
-      while (TREE_CODE (type) == ARRAY_TYPE)
-	type = TREE_TYPE (type);
+      tree type = strip_array_types (TREE_TYPE (ref));
       if (tree size = TYPE_SIZE_UNIT (type))
 	{
-	  offrange[0] = offrange[0] / wi::to_offset (size);
-	  offrange[1] = offrange[1] / wi::to_offset (size);
+	  idxrange[0] = offrange[0] / wi::to_offset (size);
+	  idxrange[1] = offrange[1] / wi::to_offset (size);
 	}
     }
 
   if (lboob)
     {
-      if (offrange[0] == offrange[1])
+      if (idxrange[0] == idxrange[1])
 	warned = warning_at (location, OPT_Warray_bounds,
 			     "array subscript %wi is outside array bounds "
 			     "of %qT",
-			     offrange[0].to_shwi (), reftype);
+			     idxrange[0].to_shwi (), reftype);
       else
 	warned = warning_at (location, OPT_Warray_bounds,
 			     "array subscript [%wi, %wi] is outside "
 			     "array bounds of %qT",
-			     offrange[0].to_shwi (),
-			     offrange[1].to_shwi (), reftype);
+			     idxrange[0].to_shwi (),
+			     idxrange[1].to_shwi (), reftype);
     }
   else if (uboob && !ignore_off_by_one)
     {
+      bool done = false;
+
       tree backtype = reftype;
       if (alloc_stmt)
 	/* If the memory was dynamically allocated refer to it as if
 	   it were an untyped array of bytes.  */
 	backtype = build_array_type_nelts (unsigned_char_type_node,
 					   arrbounds[1].to_uhwi ());
+      else if (cref_of_mref)
+	{
+	  /* For a COMPONENT_REF (struct S, MEM_REF (T, ...), fld) see
+	     if the offset of fld's last byte is in bounds of struct S,
+	     and if so, issue -Wstrict-aliasing instead.  */
+	  tree fld = TREE_OPERAND (cref_of_mref, 1);
+	  offset_int fldoff = offrange[0] + wi::to_offset (byte_position (fld));
+	  if (tree fldsiz = DECL_SIZE_UNIT (fld))
+	    if (tree_fits_uhwi_p (fldsiz))
+	      fldoff += wi::to_offset (fldsiz);
+
+	  if (fldoff <= arrbounds[1])
+	    {
+	      if (flag_strict_aliasing)
+		{
+		  /* Only warn when -fstrict-aliasing is enabled (as per
+		     the manual).  */
+		  if (offrange[0] == 0)
+		    warned = warning_at (location, OPT_Wstrict_aliasing,
+					 "access to %qT by an lvalue of %qT "
+					 "violates strict-aliasing rules",
+					 TREE_TYPE (reftype), axstype);
+		  else
+		    warned = warning_at (location, OPT_Wstrict_aliasing,
+					 "access to %qT by %<%T[%wi]%> "
+					 "violates strict-aliasing rules",
+					 TREE_TYPE (reftype), axstype,
+					 offrange[0].to_shwi ());
+		}
+	      done = true;
+	    }
+	}
 
-      warned = warning_at (location, OPT_Warray_bounds,
-			   "array subscript %<%T[%wi]%> is partly "
-			   "outside array bounds of %qT",
-			   axstype, offrange[0].to_shwi (), backtype);
+      if (!done)
+	{
+	  if (offrange[0] == 0)
+	    warned = warning_at (location, OPT_Warray_bounds,
+				 "access by %qT is partly outside array "
+				 "bounds of %qT",
+				 axstype, backtype);
+	  else
+	    warned = warning_at (location, OPT_Warray_bounds,
+				 "array subscript %<%T[%wi]%> is partly "
+				 "outside array bounds of %qT",
+				 axstype, idxrange[0].to_shwi (), backtype);
+	}
     }
 
   if (warned)
@@ -906,13 +949,21 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
     warned = checker->check_array_ref (location, t,
 				       false/*ignore_off_by_one*/);
   else if (TREE_CODE (t) == MEM_REF)
-    warned = checker->check_mem_ref (location, t,
-				     false /*ignore_off_by_one*/);
+    {
+      warned = checker->check_mem_ref (location, t,
+				       false /*ignore_off_by_one*/);
+      checker->cref_of_mref = NULL_TREE;
+    }
   else if (TREE_CODE (t) == ADDR_EXPR)
     {
       checker->check_addr_expr (location, t);
       *walk_subtree = FALSE;
     }
+  else if (TREE_CODE (t) == COMPONENT_REF
+	   && TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF)
+    /* Remember T for the subsequent MEM_REF handler.  */
+    checker->cref_of_mref = t;
+
   /* Propagate the no-warning bit to the outer expression.  */
   if (warned)
     TREE_NO_WARNING (t) = true;
diff --git a/gcc/gimple-array-bounds.h b/gcc/gimple-array-bounds.h
index 1bfa2d45870..02d5bacec8f 100644
--- a/gcc/gimple-array-bounds.h
+++ b/gcc/gimple-array-bounds.h
@@ -26,7 +26,7 @@ class array_bounds_checker
 
 public:
   array_bounds_checker (struct function *fun, class vr_values *v)
-    : fun (fun), ranges (v) { }
+    : fun (fun), ranges (v), cref_of_mref () { }
   void check ();
 
 private:
@@ -36,8 +36,12 @@ private:
   void check_addr_expr (location_t, tree);
   const value_range *get_value_range (const_tree op);
 
+  /* The current function being processed.  */
   struct function *fun;
+  /* Pointer to an instance of the range analyzer.  */
   class vr_values *ranges;
+  /* A COMPONENT_REF with a MEM_REF operand.  */
+  tree cref_of_mref;
 };
 
 #endif // GCC_GIMPLE_ARRAY_BOUNDS_H
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-10.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-10.C
index 22466977b68..ea8691531c2 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-10.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-10.C
@@ -19,9 +19,9 @@ void warn_op_new ()
 {
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new\\\(\(long \)?unsigned int\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
@@ -45,9 +45,9 @@ void warn_op_array_new ()
 
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new \\\[]\\\(\(long \)?unsigned int\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-11.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-11.C
index 9875e29085d..d934b800c73 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-11.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-11.C
@@ -21,9 +21,9 @@ void warn_op_new ()
 {
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new\\\(std::size_t, const std::nothrow_t.\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
@@ -47,9 +47,9 @@ void warn_op_array_new ()
 
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new \\\[]\\\(std::size_t, const std::nothrow_t&\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-12.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-12.C
index 9e8b6048944..a8d1099e041 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-12.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-12.C
@@ -21,9 +21,9 @@ void warn_new ()
 {
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new\\\(\(long \)?unsigned int\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
@@ -47,9 +47,9 @@ void warn_array_new ()
 
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new \\\[]\\\(\(long \)?unsigned int\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-13.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-13.C
index 42fb809de3c..705029f2718 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-13.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-13.C
@@ -25,9 +25,9 @@ void warn_nothrow_new ()
 {
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new\\\(std::size_t, const std::nothrow_t.\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
@@ -51,9 +51,9 @@ void warn_nothrow_array_new ()
 
   T (int32_t, 0, 0);          // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
                               // { dg-message "referencing an object of size \\d allocated by 'void\\\* operator new \\\[]\\\(std::size_t, const std::nothrow_t&\\\)'" "note" { target *-*-* } .-1 }
-  T (int32_t, 1, 0);          // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
-  T (int32_t, 2, 0);         //  { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
-  T (int32_t, 3, 0);         // { dg-warning "array subscript 'int32_t {aka int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[3]'" }
+  T (int32_t, 1, 0);          // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[1]'" }
+  T (int32_t, 2, 0);         //  { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[2]'" }
+  T (int32_t, 3, 0);         // { dg-warning "access by 'int32_t' {aka 'int'} is partly outside array bounds of 'unsigned char \\\[3]'" }
 
   T (int32_t, 4, 0);
 
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-63.c b/gcc/testsuite/gcc.dg/Warray-bounds-63.c
index a3fc9188211..0ef4a469f01 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-63.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-63.c
@@ -31,10 +31,11 @@ void word_store_to_decl (void)
 
   char *p = (char*)&s;
 
-  int16_t *q = (int16_t*)(p + 1);
+  typedef __attribute__ ((may_alias)) int16_t alias16_t;
+  alias16_t *q = (alias16_t*)(p + 1);
 
   q[0] = 0; q[1] = 1;
-  q[2] = 2;                     // { dg-warning "array subscript 'int16_t {aka short int}\\\[2]' is partly outside array bounds of 'struct S6\\\[1]'" }
+  q[2] = 2;                     // { dg-warning "array subscript 'alias16_t {aka short int}\\\[2]' is partly outside array bounds of 'struct S6\\\[1]'" }
 
   sink (&s);
 }
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-66.c b/gcc/testsuite/gcc.dg/Warray-bounds-66.c
index c61891f5c07..85906fcf7b7 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-66.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-66.c
@@ -119,7 +119,7 @@ void test_alloca_int16_range (unsigned n)
   {
     p = alloca (UR (0, 1));   // { dg-message "object of size between 0 and 1 allocated by '__builtin_alloca'" }
     sink (p);
-    T (p[0]);                 // { dg-warning "subscript 'int16_t {aka short int}\\\[0\\\]' is partly outside array bounds of 'unsigned char\\\[1]'" }
+    T (p[0]);                 // { dg-warning "access by 'int16_t' {aka 'short int'} is partly outside array bounds of 'unsigned char\\\[1]'" }
     T (p[1]);                 // { dg-warning "subscript 1 is outside array bounds of 'int16_t\\\[0]'" }
   }
 
diff --git a/gcc/testsuite/gcc.dg/Wstrict-aliasing-2.c b/gcc/testsuite/gcc.dg/Wstrict-aliasing-2.c
new file mode 100644
index 00000000000..cc1d548239f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-aliasing-2.c
@@ -0,0 +1,85 @@
+/* PR middle-end/98503 -Warray-bounds when -Wstrict-aliasing would be more
+   appropriate
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+void* malloc (__SIZE_TYPE__);
+
+
+struct A { int i1, i2; };
+struct B { int i1, i2, i3; };
+
+extern struct A a;
+extern struct A a2[2];
+
+
+void warn_strict_alias_B_i1_A (void)
+{
+  struct B *p = (struct B*)&a;
+  p->i1 = 0;                    // { dg-warning "\\\[-Wstrict-aliasing" }
+}
+
+void warn_strict_alias_B_i2_A (void)
+{
+  struct B *p = (struct B*)&a;
+  p->i2 = 0;                    // { dg-warning "access to 'struct A' by an lvalue of 'struct B' violates strict-aliasing rules" }
+}
+
+void nowarn_strict_alias_B_i3_A (void)
+{
+  struct B *p = (struct B*)&a;
+  p->i3 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+void warn_strict_alias_B_A2 (void)
+{
+  struct B *p = (struct B*)&a2;
+  /* Of the aliasing violations below only last one is diagnosed because
+     it's the only one where the member access exceeds the boundary of
+     the destination object.  */
+  p[0].i1 = 0;                    // { dg-warning "\\\[-Wstrict-aliasing" "pr?????" { xfail *-*-* } }
+  p[0].i2 = 0;                    // { dg-warning "\\\[-Wstrict-aliasing" "pr?????" { xfail *-*-* } }
+  p[0].i3 = 0;                    // { dg-warning "\\\[-Wstrict-aliasing" "pr?????" { xfail *-*-* } }
+  p[1].i1 = 0;                    // { dg-warning "\\\[-Wstrict-aliasing" }
+  p[1].i2 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  p[1].i3 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void* nowarn_access_A_i1_malloc_A (void)
+{
+  struct B *p = (struct B*)malloc (sizeof (struct A));
+  struct A *q = (struct A*)p;
+  q->i1 = 0;
+  return p;
+}
+
+void* nowarn_access_A_i2_malloc_A (void)
+{
+  struct B *p = (struct B*)malloc (sizeof (struct A));
+  struct A *q = (struct A*)p;
+  q->i2 = 0;
+  return p;
+}
+
+
+struct B* warn_array_bounds_access_B_i1_malloc_A (void)
+{
+  struct B *p = malloc (sizeof (struct A));
+  p->i1 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  return p;
+}
+
+struct B* warn_array_bounds_access_B_i2_malloc_A (void)
+{
+  struct B *p = malloc (sizeof (struct A));
+  p->i2 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  return p;
+}
+
+struct B* warn_array_bounds_access_B_i3_malloc_A (void)
+{
+  struct B *p = malloc (sizeof (struct A));
+  p->i3 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  return p;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-aliasing-3.c b/gcc/testsuite/gcc.dg/Wstrict-aliasing-3.c
new file mode 100644
index 00000000000..5fe17ef22dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-aliasing-3.c
@@ -0,0 +1,71 @@
+/* PR middle-end/98503 -Warray-bounds when -Wstrict-aliasing would be more
+   appropriate
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fno-strict-aliasing" } */
+
+void* malloc (__SIZE_TYPE__);
+
+
+struct A { int i1, i2; };
+struct B { int i1, i2, i3; };
+
+extern struct A a;
+extern struct A a2[2];
+
+
+void nowarn_strict_alias_B_i1_A (void)
+{
+  struct B *p = (struct B*)&a;
+  p->i1 = 0;   // only warn with -fstrict-aliasing
+}
+
+void nowarn_strict_alias_B_i2_A (void)
+{
+  struct B *p = (struct B*)&a;
+  p->i2 = 0;   // only warn with -fstrict-aliasing
+}
+
+void nowarn_strict_alias_B_i3_A (void)
+{
+  struct B *p = (struct B*)&a;
+  p->i3 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+void* nowarn_access_A_i1_malloc_A (void)
+{
+  struct B *p = (struct B*)malloc (sizeof (struct A));
+  struct A *q = (struct A*)p;
+  q->i1 = 0;
+  return p;
+}
+
+void* nowarn_access_A_i2_malloc_A (void)
+{
+  struct B *p = (struct B*)malloc (sizeof (struct A));
+  struct A *q = (struct A*)p;
+  q->i2 = 0;
+  return p;
+}
+
+
+struct B* warn_array_bounds_access_B_i1_malloc_A (void)
+{
+  struct B *p = malloc (sizeof (struct A));
+  p->i1 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  return p;
+}
+
+struct B* warn_array_bounds_access_B_i2_malloc_A (void)
+{
+  struct B *p = malloc (sizeof (struct A));
+  p->i2 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  return p;
+}
+
+struct B* warn_array_bounds_access_B_i3_malloc_A (void)
+{
+  struct B *p = malloc (sizeof (struct A));
+  p->i3 = 0;                    // { dg-warning "\\\[-Warray-bounds" }
+  return p;
+}

Reply via email to