public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* V4 [PATCH] C/C++: Add -Waddress-of-packed-member
@ 2018-09-25 15:47 H.J. Lu
  2018-11-04 15:16 ` PING: " H.J. Lu
  2018-12-13 20:50 ` Jason Merrill
  0 siblings, 2 replies; 23+ messages in thread
From: H.J. Lu @ 2018-09-25 15:47 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph Myers, Martin Sebor, GCC Patches

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

On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> On 07/23/2018 05:24 PM, H.J. Lu wrote:
>>
>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
>> wrote:
>>>
>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>
>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
>>>> wrote:
>>>>>
>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>>
>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
>>>>>>> +    {
>>>>>>> +      /* Check the THEN path first.  */
>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
>>>>>>> +      context = check_address_of_packed_member (type, op1);
>>>>>>
>>>>>>
>>>>>> This should handle the GNU extension of re-using operand 0 if operand
>>>>>> 1 is omitted.
>>>>>
>>>>>
>>>>> Doesn't that just use a SAVE_EXPR?
>>>>
>>>>
>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
>>>
>>>
>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
>>> is produced directly.
>>
>>
>> Here is the updated patch.  Changes from the last one:
>>
>> 1. Handle COMPOUND_EXPR.
>> 2. Fixed typos in comments.
>> 3. Combined warn_for_pointer_of_packed_member and
>> warn_for_address_of_packed_member into
>> warn_for_address_or_pointer_of_packed_member.
>
>
>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
>
>
> I think this would read better as
>
> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> ‘long int *’ (alignment 8) may result in an unaligned pointer value
> [-Waddress-of-packed-member]

Fixed.

>> +      while (TREE_CODE (base) == ARRAY_REF)
>> +       base = TREE_OPERAND (base, 0);
>> +      if (TREE_CODE (base) != COMPONENT_REF)
>> +       return NULL_TREE;
>
>
> Are you deliberately not handling the other handled_component_p cases? If
> so, there should be a comment.

I changed it to

     while (handled_component_p (base))
        {
          enum tree_code code = TREE_CODE (base);
          if (code == COMPONENT_REF)
            break;
          switch (code)
            {
            case ARRAY_REF:
              base = TREE_OPERAND (base, 0);
              break;
            default:
              /* FIXME: Can it ever happen?  */
              gcc_unreachable ();
              break;
            }
        }

Is there a testcase to trigger this ICE? I couldn't find one.

>> +  /* Check alignment of the object.  */
>> +  if (TREE_CODE (object) == COMPONENT_REF)
>> +    {
>> +      field = TREE_OPERAND (object, 1);
>> +      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
>> +       {
>> +         type_align = TYPE_ALIGN (type);
>> +         context = DECL_CONTEXT (field);
>> +         record_align = TYPE_ALIGN (context);
>> +         if ((record_align % type_align) != 0)
>> +           return context;
>> +       }
>> +    }
>
>
> Why doesn't this recurse?  What if you have a packed field three
> COMPONENT_REFs down?

My patch works on
[hjl@gnu-cfl-1 pr51628-4]$ cat x.i
struct A { int i; } __attribute__ ((packed));
struct B { struct A a; };
struct C { struct B b; };

extern struct C *p;

int* g8 (void) { return &p->b.a.i; }
[hjl@gnu-cfl-1 pr51628-4]$ make x.s
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S x.i
x.i: In function ‘g8’:
x.i:7:25: warning: taking address of packed member of ‘struct A’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
7 | int* g8 (void) { return &p->b.a.i; }
  |                         ^~~~~~~~~
[hjl@gnu-cfl-1 pr51628-4]$

If it isn't what you had in mind, can you give me a testcase?

>> +  if (TREE_CODE (rhs) == COND_EXPR)
>> +    {
>> +      /* Check the THEN path first.  */
>> +      tree op1 = TREE_OPERAND (rhs, 1);
>> +      context = check_address_of_packed_member (type, op1);
>> +      if (context)
>> +       rhs = op1;
>> +      else
>> +       {
>> +         /* Check the ELSE path.  */
>> +         rhs = TREE_OPERAND (rhs, 2);
>> +         context = check_address_of_packed_member (type, rhs);
>> +       }
>> +    }
>
>
> Likewise, what if you have more levels of COND_EXPR?  Or COMPOUND_EXPR
> within COND_EXPR?

Fixed, now I got

[hjl@gnu-cfl-1 pr51628-5]$ cat z.i
struct A {
  int i;
} __attribute__ ((packed));

int*
foo3 (struct A *p1, int *q1, int *q2, struct A *p2)
{
  return (q1
          ? &p1->i
          : (q2 ? &p2->i : q2));
}
[hjl@gnu-cfl-1 pr51628-5]$ make z.s
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S z.i
z.i: In function ‘foo3’:
z.i:9:13: warning: taking address of packed member of ‘struct A’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
9 |           ? &p1->i
  |             ^~~~~~
z.i:10:19: warning: taking address of packed member of ‘struct A’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
10 |           : (q2 ? &p2->i : q2));
   |                   ^~~~~~
[hjl@gnu-cfl-1 pr51628-5]$

>> @@ -7470,6 +7470,9 @@ convert_for_arg_passing (tree type, tree val,
>> tsubst_flags_t complain)
>> +  warn_for_address_or_pointer_of_packed_member (true, type, val);
>
>
>> @@ -8914,6 +8914,8 @@ convert_for_assignment (tree type, tree rhs,
>> +  warn_for_address_or_pointer_of_packed_member (true, type, rhs);
>
>
> Why would address_p be true in these calls?  It seems that you are warning
> at the point of assignment but looking for the warning about taking the
> address rather than the one about assignment.

It happens only with C for incompatible pointer conversion:

[hjl@gnu-cfl-1 pr51628-2]$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
[hjl@gnu-cfl-1 pr51628-2]$ make c.s
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S c.i
c.i: In function ‘g8’:
c.i:4:33: warning: returning ‘struct C *’ from a function with
incompatible return type ‘long int *’ [-Wincompatible-pointer-types]
4 | long* g8 (struct C *p) { return p; }
  |                                 ^
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment
1) to ‘long int *’ (alignment 8) may may result in an unaligned
pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
[hjl@gnu-cfl-1 pr51628-2]$

address_p is false in this case and rhs is PARM_DECL, VAR_DECL or
NOP_EXPR.  This comes from convert_for_assignment in c/c-typeck.c.

For other compatible pointer assignment, address_p is true and rhs is
ADDR_EXPR, PARM_DECL, VAR_DECL or NOP_EXPR.   Check
for  ADDR_EXPR won't work.

address_p isn't an appropriate parameter name.  I changed it to convert_p
to indicate that it is an incompatible pointer type conversion.

> If you want to warn about taking the address, shouldn't that happen under
> cp_build_addr_expr?  Alternately, drop the address_p parameter and choose
> your path inside warn_for_*_packed_member based on whether rhs is an
> ADDR_EXPR there rather than in the caller.
>

Here is the updated patch.  OK for trunk?

Thanks.


-- 
H.J.

[-- Attachment #2: 0001-C-C-Add-Waddress-of-packed-member.patch --]
[-- Type: text/x-patch, Size: 49029 bytes --]

From b5cecbaabfe0fde7aeb3d3c24d8959853985951c Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 12 Jan 2018 21:12:05 -0800
Subject: [PATCH] C/C++: Add -Waddress-of-packed-member
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When address of packed member of struct or union is taken, it may result
in an unaligned pointer value.  This patch adds -Waddress-of-packed-member
to check alignment at pointer assignment and warn unaligned address as
well as unaligned pointer:

$ cat x.i
struct pair_t
{
  char c;
  int i;
} __attribute__ ((packed));

extern struct pair_t p;
int *addr = &p.i;
$ gcc -O2 -S x.i
x.i:8:13: warning: taking address of packed member of ‘struct pair_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
8 | int *addr = &p.i;
  |             ^

$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
$ gcc -O2 -S c.i -Wno-incompatible-pointer-types
c.i: In function ‘g8’:
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment 1) to ‘long int *’ (alignment 8) may may result in an unaligned pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
$

This warning is enabled by default.  Since read_encoded_value_with_base
in unwind-pe.h has

  union unaligned
    {
      void *ptr;
      unsigned u2 __attribute__ ((mode (HI)));
      unsigned u4 __attribute__ ((mode (SI)));
      unsigned u8 __attribute__ ((mode (DI)));
      signed s2 __attribute__ ((mode (HI)));
      signed s4 __attribute__ ((mode (SI)));
      signed s8 __attribute__ ((mode (DI)));
    } __attribute__((__packed__));
  _Unwind_Internal_Ptr result;

and GCC warns:

gcc/libgcc/unwind-pe.h:210:37: warning: taking address of packed member of 'union unaligned' may result in an unaligned pointer value [-Waddress-of-packed-member]
    result = (_Unwind_Internal_Ptr) u->ptr;
                                    ^
we need to add GCC pragma to ignore -Waddress-of-packed-member.

gcc/c/

	PR c/51628
	* doc/invoke.texi: Document -Wno-address-of-packed-member.

gcc/c-family/

	PR c/51628
	* c-common.h (warn_for_address_or_pointer_of_packed_member): New.
	* c-warn.c (check_address_of_packed_member): New function.
	(check_and_warn_address_of_packed_member): Likewise.
	(warn_for_address_or_pointer_of_packed_member): Likewise.
	* c.opt: Add -Wno-address-of-packed-member.

gcc/c/

	PR c/51628
	* c-typeck.c (convert_for_assignment): Call
	warn_for_address_or_pointer_of_packed_member.

gcc/cp/

	PR c/51628
	* call.c (convert_for_arg_passing): Call
	warn_for_address_or_pointer_of_packed_member.
	* typeck.c (convert_for_assignment): Likewise.

gcc/testsuite/

	PR c/51628
	* c-c++-common/pr51628-1.c: New test.
	* c-c++-common/pr51628-2.c: Likewise.
	* c-c++-common/pr51628-3.c: Likewise.
	* c-c++-common/pr51628-4.c: Likewise.
	* c-c++-common/pr51628-5.c: Likewise.
	* c-c++-common/pr51628-6.c: Likewise.
	* c-c++-common/pr51628-7.c: Likewise.
	* c-c++-common/pr51628-8.c: Likewise.
	* c-c++-common/pr51628-9.c: Likewise.
	* c-c++-common/pr51628-10.c: Likewise.
	* c-c++-common/pr51628-11.c: Likewise.
	* c-c++-common/pr51628-12.c: Likewise.
	* c-c++-common/pr51628-13.c: Likewise.
	* c-c++-common/pr51628-14.c: Likewise.
	* c-c++-common/pr51628-15.c: Likewise.
	* c-c++-common/pr51628-26.c: Likewise.
	* c-c++-common/pr51628-27.c: Likewise.
	* c-c++-common/pr51628-28.c: Likewise.
	* gcc.dg/pr51628-17.c: Likewise.
	* gcc.dg/pr51628-18.c: Likewise.
	* gcc.dg/pr51628-19.c: Likewise.
	* gcc.dg/pr51628-20.c: Likewise.
	* gcc.dg/pr51628-21.c: Likewise.
	* gcc.dg/pr51628-22.c: Likewise.
	* gcc.dg/pr51628-23.c: Likewise.
	* gcc.dg/pr51628-24.c: Likewise.
	* gcc.dg/pr51628-25.c: Likewise.
	* c-c++-common/asan/misalign-1.c: Add
	-Wno-address-of-packed-member.
	* c-c++-common/asan/misalign-2.c: Likewise.
	* c-c++-common/ubsan/align-2.c: Likewise.
	* c-c++-common/ubsan/align-4.c: Likewise.
	* c-c++-common/ubsan/align-6.c: Likewise.
	* c-c++-common/ubsan/align-7.c: Likewise.
	* c-c++-common/ubsan/align-8.c: Likewise.
	* c-c++-common/ubsan/align-10.c: Likewise.
	* g++.dg/ubsan/align-2.C: Likewise.
	* gcc.target/i386/avx512bw-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu64-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu64-2.c: Likewise.

libgcc/

	* unwind-pe.h (read_encoded_value_with_base): Add GCC pragma
	to ignore -Waddress-of-packed-member.
---
 gcc/c-family/c-common.h                       |   1 +
 gcc/c-family/c-warn.c                         | 188 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  11 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |  11 +-
 gcc/testsuite/c-c++-common/asan/misalign-1.c  |   2 +-
 gcc/testsuite/c-c++-common/asan/misalign-2.c  |   2 +-
 gcc/testsuite/c-c++-common/pr51628-1.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-10.c       |  24 +++
 gcc/testsuite/c-c++-common/pr51628-11.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-12.c       |  18 ++
 gcc/testsuite/c-c++-common/pr51628-13.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-14.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-15.c       |  14 ++
 gcc/testsuite/c-c++-common/pr51628-16.c       |  13 ++
 gcc/testsuite/c-c++-common/pr51628-2.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-26.c       |  33 +++
 gcc/testsuite/c-c++-common/pr51628-27.c       |  12 ++
 gcc/testsuite/c-c++-common/pr51628-28.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-3.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-4.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-5.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-6.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-7.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-8.c        |  36 ++++
 gcc/testsuite/c-c++-common/pr51628-9.c        |  36 ++++
 gcc/testsuite/c-c++-common/ubsan/align-10.c   |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-2.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-4.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-6.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-7.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-8.c    |   2 +-
 gcc/testsuite/g++.dg/ubsan/align-2.C          |   2 +-
 gcc/testsuite/gcc.dg/pr51628-17.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-18.c             |  23 +++
 gcc/testsuite/gcc.dg/pr51628-19.c             |  26 +++
 gcc/testsuite/gcc.dg/pr51628-20.c             |  11 +
 gcc/testsuite/gcc.dg/pr51628-21.c             |  11 +
 gcc/testsuite/gcc.dg/pr51628-22.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-23.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-24.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-25.c             |   9 +
 .../gcc.target/i386/avx512bw-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu32-2.c     |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu64-2.c     |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu32-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu64-2.c    |   2 +-
 libgcc/unwind-pe.h                            |   5 +
 51 files changed, 820 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-10.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-11.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-12.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-13.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-14.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-15.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-16.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-26.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-27.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-28.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-4.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-5.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-6.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-7.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-8.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-9.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-17.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-18.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-19.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-20.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-21.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-22.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-23.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-24.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-25.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 9e868768d01..0d39004ae3d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1272,6 +1272,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern bool warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_for_address_or_pointer_of_packed_member (bool, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index a1a7f935964..c14030cd1a7 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2609,3 +2609,191 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
 }
+
+/* Return struct or union type if the right hand value, RHS, takes the
+   unaligned address of packed member of struct or union when assigning
+   to TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_address_of_packed_member (tree type, tree rhs)
+{
+  tree base;
+  tree object;
+  tree field;
+
+  if (INDIRECT_REF_P (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+
+  switch (TREE_CODE (rhs))
+    {
+    case ADDR_EXPR:
+      base = TREE_OPERAND (rhs, 0);
+      while (handled_component_p (base))
+	{
+	  enum tree_code code = TREE_CODE (base);
+	  if (code == COMPONENT_REF)
+	    break;
+	  switch (code)
+	    {
+	    case ARRAY_REF:
+	      base = TREE_OPERAND (base, 0);
+	      break;
+	    default:
+	      /* FIXME: Can it ever happen?  */
+	      gcc_unreachable ();
+	      break;
+	    }
+	}
+      if (TREE_CODE (base) != COMPONENT_REF)
+	return NULL_TREE;
+      object = TREE_OPERAND (base, 0);
+      field = TREE_OPERAND (base, 1);
+      break;
+    case COMPONENT_REF:
+      object = TREE_OPERAND (rhs, 0);
+      field = TREE_OPERAND (rhs, 1);
+      break;
+    default:
+      return NULL_TREE;
+    }
+
+  tree context;
+  unsigned int type_align, record_align;
+
+  /* Check alignment of the data member.  */
+  if (TREE_CODE (field) == FIELD_DECL
+      && (DECL_PACKED (field)
+	  || TYPE_PACKED (TREE_TYPE (field))))
+    {
+      /* Check the expected alignment against the field alignment.  */
+      type_align = TYPE_ALIGN (type);
+      context = DECL_CONTEXT (field);
+      record_align = TYPE_ALIGN (context);
+      if ((record_align % type_align) != 0)
+	return context;
+      tree field_off = byte_position (field);
+      if (!multiple_of_p (TREE_TYPE (field_off), field_off,
+			  size_int (type_align / BITS_PER_UNIT)))
+	return context;
+    }
+
+  /* Check alignment of the object.  */
+  if (TREE_CODE (object) == COMPONENT_REF)
+    {
+      field = TREE_OPERAND (object, 1);
+      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
+	{
+	  type_align = TYPE_ALIGN (type);
+	  context = DECL_CONTEXT (field);
+	  record_align = TYPE_ALIGN (context);
+	  if ((record_align % type_align) != 0)
+	    return context;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Check and warn if the right hand value, RHS, takes the unaligned
+   address of packed member of struct or union when assigning to TYPE.  */
+
+static void
+check_and_warn_address_of_packed_member (tree type, tree rhs)
+{
+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      tree context = check_address_of_packed_member (type, rhs);
+      if (context)
+	{
+	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
+	  warning_at (loc, OPT_Waddress_of_packed_member,
+		      "taking address of packed member of %qT may result "
+		      "in an unaligned pointer value",
+		      context);
+	}
+      return;
+    }
+
+  /* Check the THEN path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
+
+  /* Check the ELSE path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
+}
+
+/* Warn if the right hand value, RHS:
+   1. For CONVERT_P == true, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+   2. For CONVERT_P == false, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool convert_p, tree type,
+					      tree rhs)
+{
+  if (!warn_address_of_packed_member)
+    return;
+
+  /* Don't warn if we don't assign RHS to a pointer.  */
+  if (!POINTER_TYPE_P (type))
+    return;
+
+  while (TREE_CODE (rhs) == COMPOUND_EXPR)
+    rhs = TREE_OPERAND (rhs, 1);
+
+  if (convert_p)
+    {
+      bool rhspointer_p;
+      tree rhstype;
+
+      /* Check the original type of RHS.  */
+      switch (TREE_CODE (rhs))
+	{
+	case PARM_DECL:
+	case VAR_DECL:
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = POINTER_TYPE_P (rhstype);
+	  break;
+	case NOP_EXPR:
+	  rhs = TREE_OPERAND (rhs, 0);
+	  if (TREE_CODE (rhs) == ADDR_EXPR)
+	    rhs = TREE_OPERAND (rhs, 0);
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
+	  break;
+	default:
+	  return;
+	}
+
+      if (rhspointer_p && TYPE_PACKED (TREE_TYPE (rhstype)))
+	{
+	  unsigned int type_align = TYPE_ALIGN_UNIT (TREE_TYPE (type));
+	  unsigned int rhs_align = TYPE_ALIGN_UNIT (TREE_TYPE (rhstype));
+	  if ((rhs_align % type_align) != 0)
+	    {
+	      location_t location = EXPR_LOC_OR_LOC (rhs, input_location);
+	      warning_at (location, OPT_Waddress_of_packed_member,
+			  "converting a packed %qT pointer (alignment %d) "
+			  "to %qT (alignment %d) may may result in an "
+			  "unaligned pointer value",
+			  rhstype, rhs_align, type, type_align);
+	      tree decl = TYPE_STUB_DECL (TREE_TYPE (rhstype));
+	      inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	      decl = TYPE_STUB_DECL (TREE_TYPE (type));
+	      if (decl)
+		inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	    }
+	}
+    }
+  else
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+
+      check_and_warn_address_of_packed_member (type, rhs);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 43d1d27ac00..3ceee456291 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -616,6 +616,10 @@ Wincompatible-pointer-types
 C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning
 Warn when there is a conversion between pointers that have incompatible types.
 
+Waddress-of-packed-member
+C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning
+Warn when the address of packed member of struct or union is taken.
+
 Winit-self
 C ObjC C++ ObjC++ Var(warn_init_self) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about variables which are initialized to themselves.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index a5a7da0084c..7ecd38b27d5 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6541,7 +6541,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    return rhs;
+    {
+      warn_for_address_or_pointer_of_packed_member (false, type,
+						    orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7036,6 +7040,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	    }
 	}
 
+      /* If RHS is't an address, check pointer or array of packed
+	 struct or union.  */
+      warn_for_address_or_pointer_of_packed_member
+	(TREE_CODE (orig_rhs) != ADDR_EXPR, type, orig_rhs);
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index b2ca667c8b4..8d4099d3dea 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7539,6 +7539,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	}
       maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
     }
+
+  warn_for_address_or_pointer_of_packed_member (false, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index e9932202b46..1400f16a20e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8926,6 +8926,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (false, type, rhs);
+
   return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
 					    complain, flags);
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7ef4e7a449b..2815f495ebf 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -278,8 +278,8 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
--w  -Wextra  -Wall  -Waddress  -Waggregate-return  -Waligned-new @gol
--Walloc-zero  -Walloc-size-larger-than=@var{byte-size}
+-w  -Wextra  -Wall  -Waddress -Waddress-of-packed-member -Waggregate-return @gol
+-Waligned-new -Walloc-zero  -Walloc-size-larger-than=@var{byte-size}
 -Walloca  -Walloca-larger-than=@var{byte-size} @gol
 -Wno-aggressive-loop-optimizations  -Warray-bounds  -Warray-bounds=@var{n} @gol
 -Wno-attributes  -Wbool-compare  -Wbool-operation @gol
@@ -6701,6 +6701,13 @@ behavior and are not portable in C, so they usually indicate that the
 programmer intended to use @code{strcmp}.  This warning is enabled by
 @option{-Wall}.
 
+@item -Waddress-of-packed-member
+@opindex Waddress-of-packed-member
+@opindex Wno-address-of-packed-member
+Warn when the address of packed member of struct or union is taken,
+which usually results in an unaligned pointer value.  This is
+enabled by default.
+
 @item -Wlogical-op
 @opindex Wlogical-op
 @opindex Wno-logical-op
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-1.c b/gcc/testsuite/c-c++-common/asan/misalign-1.c
index 5cd605ac045..ebeb0306706 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-1.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-2.c b/gcc/testsuite/c-c++-common/asan/misalign-2.c
index a6ed49bac05..b27e22d35a8 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-2.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/pr51628-1.c b/gcc/testsuite/c-c++-common/pr51628-1.c
new file mode 100644
index 00000000000..5324f9cc964
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-1.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-10.c b/gcc/testsuite/c-c++-common/pr51628-10.c
new file mode 100644
index 00000000000..085fe1608c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-10.c
@@ -0,0 +1,24 @@
+/* PR c/51628.  */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+struct pair_t
+{
+  char c;
+  __int128_t i;
+} __attribute__ ((packed));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__((packed)) unaligned_int128_t;
+
+struct pair_t p = {0, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *) &p.i;
+
+int 
+main() 
+{
+  addr->value = ~(__int128_t)0;
+  return (p.i != 1) ? 0 : 1;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-11.c b/gcc/testsuite/c-c++-common/pr51628-11.c
new file mode 100644
index 00000000000..7661232ac88
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-11.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[12];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
diff --git a/gcc/testsuite/c-c++-common/pr51628-12.c b/gcc/testsuite/c-c++-common/pr51628-12.c
new file mode 100644
index 00000000000..bc221fa87ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-12.c
@@ -0,0 +1,18 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[10];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-13.c b/gcc/testsuite/c-c++-common/pr51628-13.c
new file mode 100644
index 00000000000..0edd5e7f84d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-13.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* h4 (struct C *p) { return &p->b.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-14.c b/gcc/testsuite/c-c++-common/pr51628-14.c
new file mode 100644
index 00000000000..f50378b8651
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-14.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+void* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/c-c++-common/pr51628-15.c b/gcc/testsuite/c-c++-common/pr51628-15.c
new file mode 100644
index 00000000000..bcac6d70ad5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-15.c
@@ -0,0 +1,14 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+int*
+f (struct A *p, int *q)
+{
+  return q ? q : &p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-16.c b/gcc/testsuite/c-c++-common/pr51628-16.c
new file mode 100644
index 00000000000..cd502fe76b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-16.c
@@ -0,0 +1,13 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct __attribute__ ((packed)) A { int i; };
+struct B {
+  struct A a;
+} b;
+
+int *p = (int*)&b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+int *q = (int*)&b.a;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-2.c b/gcc/testsuite/c-c++-common/pr51628-2.c
new file mode 100644
index 00000000000..abfb84ddd05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-2.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (8)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-26.c b/gcc/testsuite/c-c++-common/pr51628-26.c
new file mode 100644
index 00000000000..2042379860a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-26.c
@@ -0,0 +1,33 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+struct A p = {1};
+int *addr;
+
+int i, j;
+
+void
+foo1 (void)
+{
+  addr = (i = -1, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo2 (void)
+{
+  addr = (i = -1, j = -2, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo3 (void)
+{
+  addr = (i = -1, (j = -2, &p.i));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-27.c b/gcc/testsuite/c-c++-common/pr51628-27.c
new file mode 100644
index 00000000000..9ae1efd7afb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-27.c
@@ -0,0 +1,12 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; } __attribute__ ((packed));
+struct B { struct A a; };
+struct C { struct B b; };
+
+extern struct C *p;
+
+int* g8 (void) { return &p->b.a.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-28.c b/gcc/testsuite/c-c++-common/pr51628-28.c
new file mode 100644
index 00000000000..e8c752d0b12
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-28.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { 
+  int i;
+} __attribute__ ((packed));
+
+int *
+foo3 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 
+	  ? &p1->i
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? &p2->i : q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-3.c b/gcc/testsuite/c-c++-common/pr51628-3.c
new file mode 100644
index 00000000000..0ea94c845a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-3.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (2)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-4.c b/gcc/testsuite/c-c++-common/pr51628-4.c
new file mode 100644
index 00000000000..c4c1fb72d6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-4.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-5.c b/gcc/testsuite/c-c++-common/pr51628-5.c
new file mode 100644
index 00000000000..9d7c309a0ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-5.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-6.c b/gcc/testsuite/c-c++-common/pr51628-6.c
new file mode 100644
index 00000000000..52aa07a4cf3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-6.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-7.c b/gcc/testsuite/c-c++-common/pr51628-7.c
new file mode 100644
index 00000000000..ae4a681f966
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-7.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+  bar (p0);
+  p1 = &p->i[1];
+  bar (p1);
+  bar (p->i);
+  bar (&p->i[2]);
+  x = p->i;
+  return &p->i[3];
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-8.c b/gcc/testsuite/c-c++-common/pr51628-8.c
new file mode 100644
index 00000000000..cc2dae096ae
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-8.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i[4];
+} __attribute__ ((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-9.c b/gcc/testsuite/c-c++-common/pr51628-9.c
new file mode 100644
index 00000000000..0470aa3b93d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-9.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__ ((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-10.c b/gcc/testsuite/c-c++-common/ubsan/align-10.c
index 56ae9ebfe30..6210533173c 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-10.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct R { int a; } r;
 struct S { struct R a; char b; long long c; short d[10]; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-2.c b/gcc/testsuite/c-c++-common/ubsan/align-2.c
index 071de8c202a..336b1c3c907 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-2.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=alignment" } */
+/* { dg-options "-fsanitize=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-4.c b/gcc/testsuite/c-c++-common/ubsan/align-4.c
index 3252595d330..d5feeee29c6 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-4.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=null,alignment" } */
+/* { dg-options "-fsanitize=null,alignment -Wno-address-of-packed-member" } */
 
 #include "align-2.c"
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-6.c b/gcc/testsuite/c-c++-common/ubsan/align-6.c
index 3364746fb27..0302b7b8894 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-6.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-7.c b/gcc/testsuite/c-c++-common/ubsan/align-7.c
index ec4e87f56d5..dd1e8c91cef 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-7.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-7.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-8.c b/gcc/testsuite/c-c++-common/ubsan/align-8.c
index 61c1ceb6682..5fe0e0fe931 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-8.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/g++.dg/ubsan/align-2.C b/gcc/testsuite/g++.dg/ubsan/align-2.C
index 3e4f5485d02..c97ede88392 100644
--- a/gcc/testsuite/g++.dg/ubsan/align-2.C
+++ b/gcc/testsuite/g++.dg/ubsan/align-2.C
@@ -1,6 +1,6 @@
 // Limit this to known non-strict alignment targets.
 // { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
-// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -Wno-address-of-packed-member -std=c++11" }
 
 typedef const long int L;
 struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
diff --git a/gcc/testsuite/gcc.dg/pr51628-17.c b/gcc/testsuite/gcc.dg/pr51628-17.c
new file mode 100644
index 00000000000..0be95b2294e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-17.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+long* f8 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-18.c b/gcc/testsuite/gcc.dg/pr51628-18.c
new file mode 100644
index 00000000000..03a04eff75c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-18.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    int c[k];
+    int x[n];
+  } __attribute__ ((packed, aligned (4)));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+  foo (p0);
+  p1 = &p->x[1];
+  foo (p1);
+  return &p->x[1];
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-19.c b/gcc/testsuite/gcc.dg/pr51628-19.c
new file mode 100644
index 00000000000..7ff03e85cea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-19.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    char c[k];
+    int x[n];
+  } __attribute__ ((packed));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p0);
+  p1 = &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p1);
+  return &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-20.c b/gcc/testsuite/gcc.dg/pr51628-20.c
new file mode 100644
index 00000000000..80888283b73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-20.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C *p;
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-21.c b/gcc/testsuite/gcc.dg/pr51628-21.c
new file mode 100644
index 00000000000..3077e72c8d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-21.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C p[];
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-22.c b/gcc/testsuite/gcc.dg/pr51628-22.c
new file mode 100644
index 00000000000..1bd5d791639
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-22.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* g4 (struct C *p) { return &p->b; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-23.c b/gcc/testsuite/gcc.dg/pr51628-23.c
new file mode 100644
index 00000000000..5709be60ac8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-23.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+char* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/gcc.dg/pr51628-24.c b/gcc/testsuite/gcc.dg/pr51628-24.c
new file mode 100644
index 00000000000..3ad99cd2f16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-24.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+short* f2 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-25.c b/gcc/testsuite/gcc.dg/pr51628-25.c
new file mode 100644
index 00000000000..2fc5c028711
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-25.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+long* g8 (struct C *p) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
index a61609c40d2..c6e3ebdc507 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw" } */
+/* { dg-options "-O2 -mavx512bw -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512bw } */
 
 #define AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
index f2edc3dff7b..95a657fc5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
index 14176965ace..954b091d976 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
index 45ae83d4552..81465f8d9a0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 /* { dg-require-effective-target avx512bw } */
 
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
index 4b928d0cd42..19390664bd0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
index 1863ed3616f..aea0c12a5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index dd5ae95fc2c..05c2fb4dd50 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -177,6 +177,9 @@ read_sleb128 (const unsigned char *p, _sleb128_t *val)
    The function returns P incremented past the value.  BASE is as given
    by base_of_encoded_value for this encoding in the appropriate context.  */
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 static const unsigned char *
 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
 			      const unsigned char *p, _Unwind_Ptr *val)
@@ -270,6 +273,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
   return p;
 }
 
+#pragma GCC diagnostic pop
+
 #ifndef NO_BASE_OF_ENCODED_VALUE
 
 /* Like read_encoded_value_with_base, but get the base from the context
-- 
2.17.1


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

* PING: V4 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-09-25 15:47 V4 [PATCH] C/C++: Add -Waddress-of-packed-member H.J. Lu
@ 2018-11-04 15:16 ` H.J. Lu
  2018-11-25 14:38   ` PING^2: " H.J. Lu
  2018-12-13 20:50 ` Jason Merrill
  1 sibling, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-11-04 15:16 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph S. Myers, Martin Sebor, GCC Patches

On Tue, Sep 25, 2018 at 8:46 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> > On 07/23/2018 05:24 PM, H.J. Lu wrote:
> >>
> >> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> >> wrote:
> >>>
> >>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> >>>
> >>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> >>>> wrote:
> >>>>>
> >>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> >>>>>
> >>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> >>>>>>> +    {
> >>>>>>> +      /* Check the THEN path first.  */
> >>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> >>>>>>> +      context = check_address_of_packed_member (type, op1);
> >>>>>>
> >>>>>>
> >>>>>> This should handle the GNU extension of re-using operand 0 if operand
> >>>>>> 1 is omitted.
> >>>>>
> >>>>>
> >>>>> Doesn't that just use a SAVE_EXPR?
> >>>>
> >>>>
> >>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> >>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> >>>
> >>>
> >>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> >>> is produced directly.
> >>
> >>
> >> Here is the updated patch.  Changes from the last one:
> >>
> >> 1. Handle COMPOUND_EXPR.
> >> 2. Fixed typos in comments.
> >> 3. Combined warn_for_pointer_of_packed_member and
> >> warn_for_address_of_packed_member into
> >> warn_for_address_or_pointer_of_packed_member.
> >
> >
> >> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> >> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> >
> >
> > I think this would read better as
> >
> > c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> > ‘long int *’ (alignment 8) may result in an unaligned pointer value
> > [-Waddress-of-packed-member]
>
> Fixed.
>
> >> +      while (TREE_CODE (base) == ARRAY_REF)
> >> +       base = TREE_OPERAND (base, 0);
> >> +      if (TREE_CODE (base) != COMPONENT_REF)
> >> +       return NULL_TREE;
> >
> >
> > Are you deliberately not handling the other handled_component_p cases? If
> > so, there should be a comment.
>
> I changed it to
>
>      while (handled_component_p (base))
>         {
>           enum tree_code code = TREE_CODE (base);
>           if (code == COMPONENT_REF)
>             break;
>           switch (code)
>             {
>             case ARRAY_REF:
>               base = TREE_OPERAND (base, 0);
>               break;
>             default:
>               /* FIXME: Can it ever happen?  */
>               gcc_unreachable ();
>               break;
>             }
>         }
>
> Is there a testcase to trigger this ICE? I couldn't find one.
>
> >> +  /* Check alignment of the object.  */
> >> +  if (TREE_CODE (object) == COMPONENT_REF)
> >> +    {
> >> +      field = TREE_OPERAND (object, 1);
> >> +      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
> >> +       {
> >> +         type_align = TYPE_ALIGN (type);
> >> +         context = DECL_CONTEXT (field);
> >> +         record_align = TYPE_ALIGN (context);
> >> +         if ((record_align % type_align) != 0)
> >> +           return context;
> >> +       }
> >> +    }
> >
> >
> > Why doesn't this recurse?  What if you have a packed field three
> > COMPONENT_REFs down?
>
> My patch works on
> [hjl@gnu-cfl-1 pr51628-4]$ cat x.i
> struct A { int i; } __attribute__ ((packed));
> struct B { struct A a; };
> struct C { struct B b; };
>
> extern struct C *p;
>
> int* g8 (void) { return &p->b.a.i; }
> [hjl@gnu-cfl-1 pr51628-4]$ make x.s
> /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> -S x.i
> x.i: In function ‘g8’:
> x.i:7:25: warning: taking address of packed member of ‘struct A’ may
> result in an unaligned pointer value [-Waddress-of-packed-member]
> 7 | int* g8 (void) { return &p->b.a.i; }
>   |                         ^~~~~~~~~
> [hjl@gnu-cfl-1 pr51628-4]$
>
> If it isn't what you had in mind, can you give me a testcase?
>
> >> +  if (TREE_CODE (rhs) == COND_EXPR)
> >> +    {
> >> +      /* Check the THEN path first.  */
> >> +      tree op1 = TREE_OPERAND (rhs, 1);
> >> +      context = check_address_of_packed_member (type, op1);
> >> +      if (context)
> >> +       rhs = op1;
> >> +      else
> >> +       {
> >> +         /* Check the ELSE path.  */
> >> +         rhs = TREE_OPERAND (rhs, 2);
> >> +         context = check_address_of_packed_member (type, rhs);
> >> +       }
> >> +    }
> >
> >
> > Likewise, what if you have more levels of COND_EXPR?  Or COMPOUND_EXPR
> > within COND_EXPR?
>
> Fixed, now I got
>
> [hjl@gnu-cfl-1 pr51628-5]$ cat z.i
> struct A {
>   int i;
> } __attribute__ ((packed));
>
> int*
> foo3 (struct A *p1, int *q1, int *q2, struct A *p2)
> {
>   return (q1
>           ? &p1->i
>           : (q2 ? &p2->i : q2));
> }
> [hjl@gnu-cfl-1 pr51628-5]$ make z.s
> /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> -S z.i
> z.i: In function ‘foo3’:
> z.i:9:13: warning: taking address of packed member of ‘struct A’ may
> result in an unaligned pointer value [-Waddress-of-packed-member]
> 9 |           ? &p1->i
>   |             ^~~~~~
> z.i:10:19: warning: taking address of packed member of ‘struct A’ may
> result in an unaligned pointer value [-Waddress-of-packed-member]
> 10 |           : (q2 ? &p2->i : q2));
>    |                   ^~~~~~
> [hjl@gnu-cfl-1 pr51628-5]$
>
> >> @@ -7470,6 +7470,9 @@ convert_for_arg_passing (tree type, tree val,
> >> tsubst_flags_t complain)
> >> +  warn_for_address_or_pointer_of_packed_member (true, type, val);
> >
> >
> >> @@ -8914,6 +8914,8 @@ convert_for_assignment (tree type, tree rhs,
> >> +  warn_for_address_or_pointer_of_packed_member (true, type, rhs);
> >
> >
> > Why would address_p be true in these calls?  It seems that you are warning
> > at the point of assignment but looking for the warning about taking the
> > address rather than the one about assignment.
>
> It happens only with C for incompatible pointer conversion:
>
> [hjl@gnu-cfl-1 pr51628-2]$ cat c.i
> struct B { int i; };
> struct C { struct B b; } __attribute__ ((packed));
>
> long* g8 (struct C *p) { return p; }
> [hjl@gnu-cfl-1 pr51628-2]$ make c.s
> /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> -S c.i
> c.i: In function ‘g8’:
> c.i:4:33: warning: returning ‘struct C *’ from a function with
> incompatible return type ‘long int *’ [-Wincompatible-pointer-types]
> 4 | long* g8 (struct C *p) { return p; }
>   |                                 ^
> c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment
> 1) to ‘long int *’ (alignment 8) may may result in an unaligned
> pointer value [-Waddress-of-packed-member]
> 4 | long* g8 (struct C *p) { return p; }
>   |                  ^
> c.i:2:8: note: defined here
> 2 | struct C { struct B b; } __attribute__ ((packed));
>   |        ^
> [hjl@gnu-cfl-1 pr51628-2]$
>
> address_p is false in this case and rhs is PARM_DECL, VAR_DECL or
> NOP_EXPR.  This comes from convert_for_assignment in c/c-typeck.c.
>
> For other compatible pointer assignment, address_p is true and rhs is
> ADDR_EXPR, PARM_DECL, VAR_DECL or NOP_EXPR.   Check
> for  ADDR_EXPR won't work.
>
> address_p isn't an appropriate parameter name.  I changed it to convert_p
> to indicate that it is an incompatible pointer type conversion.
>
> > If you want to warn about taking the address, shouldn't that happen under
> > cp_build_addr_expr?  Alternately, drop the address_p parameter and choose
> > your path inside warn_for_*_packed_member based on whether rhs is an
> > ADDR_EXPR there rather than in the caller.
> >
>
> Here is the updated patch.  OK for trunk?
>
> Thanks.

PING:

https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01452.html


-- 
H.J.

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

* PING^2: V4 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-11-04 15:16 ` PING: " H.J. Lu
@ 2018-11-25 14:38   ` H.J. Lu
  0 siblings, 0 replies; 23+ messages in thread
From: H.J. Lu @ 2018-11-25 14:38 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph S. Myers, Martin Sebor, GCC Patches

On Sun, Nov 4, 2018 at 7:16 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Tue, Sep 25, 2018 at 8:46 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> > > On 07/23/2018 05:24 PM, H.J. Lu wrote:
> > >>
> > >> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> > >> wrote:
> > >>>
> > >>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > >>>
> > >>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> > >>>> wrote:
> > >>>>>
> > >>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > >>>>>
> > >>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> > >>>>>>> +    {
> > >>>>>>> +      /* Check the THEN path first.  */
> > >>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> > >>>>>>> +      context = check_address_of_packed_member (type, op1);
> > >>>>>>
> > >>>>>>
> > >>>>>> This should handle the GNU extension of re-using operand 0 if operand
> > >>>>>> 1 is omitted.
> > >>>>>
> > >>>>>
> > >>>>> Doesn't that just use a SAVE_EXPR?
> > >>>>
> > >>>>
> > >>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> > >>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> > >>>
> > >>>
> > >>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> > >>> is produced directly.
> > >>
> > >>
> > >> Here is the updated patch.  Changes from the last one:
> > >>
> > >> 1. Handle COMPOUND_EXPR.
> > >> 2. Fixed typos in comments.
> > >> 3. Combined warn_for_pointer_of_packed_member and
> > >> warn_for_address_of_packed_member into
> > >> warn_for_address_or_pointer_of_packed_member.
> > >
> > >
> > >> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> > >> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> > >
> > >
> > > I think this would read better as
> > >
> > > c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> > > ‘long int *’ (alignment 8) may result in an unaligned pointer value
> > > [-Waddress-of-packed-member]
> >
> > Fixed.
> >
> > >> +      while (TREE_CODE (base) == ARRAY_REF)
> > >> +       base = TREE_OPERAND (base, 0);
> > >> +      if (TREE_CODE (base) != COMPONENT_REF)
> > >> +       return NULL_TREE;
> > >
> > >
> > > Are you deliberately not handling the other handled_component_p cases? If
> > > so, there should be a comment.
> >
> > I changed it to
> >
> >      while (handled_component_p (base))
> >         {
> >           enum tree_code code = TREE_CODE (base);
> >           if (code == COMPONENT_REF)
> >             break;
> >           switch (code)
> >             {
> >             case ARRAY_REF:
> >               base = TREE_OPERAND (base, 0);
> >               break;
> >             default:
> >               /* FIXME: Can it ever happen?  */
> >               gcc_unreachable ();
> >               break;
> >             }
> >         }
> >
> > Is there a testcase to trigger this ICE? I couldn't find one.
> >
> > >> +  /* Check alignment of the object.  */
> > >> +  if (TREE_CODE (object) == COMPONENT_REF)
> > >> +    {
> > >> +      field = TREE_OPERAND (object, 1);
> > >> +      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
> > >> +       {
> > >> +         type_align = TYPE_ALIGN (type);
> > >> +         context = DECL_CONTEXT (field);
> > >> +         record_align = TYPE_ALIGN (context);
> > >> +         if ((record_align % type_align) != 0)
> > >> +           return context;
> > >> +       }
> > >> +    }
> > >
> > >
> > > Why doesn't this recurse?  What if you have a packed field three
> > > COMPONENT_REFs down?
> >
> > My patch works on
> > [hjl@gnu-cfl-1 pr51628-4]$ cat x.i
> > struct A { int i; } __attribute__ ((packed));
> > struct B { struct A a; };
> > struct C { struct B b; };
> >
> > extern struct C *p;
> >
> > int* g8 (void) { return &p->b.a.i; }
> > [hjl@gnu-cfl-1 pr51628-4]$ make x.s
> > /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> > -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> > -S x.i
> > x.i: In function ‘g8’:
> > x.i:7:25: warning: taking address of packed member of ‘struct A’ may
> > result in an unaligned pointer value [-Waddress-of-packed-member]
> > 7 | int* g8 (void) { return &p->b.a.i; }
> >   |                         ^~~~~~~~~
> > [hjl@gnu-cfl-1 pr51628-4]$
> >
> > If it isn't what you had in mind, can you give me a testcase?
> >
> > >> +  if (TREE_CODE (rhs) == COND_EXPR)
> > >> +    {
> > >> +      /* Check the THEN path first.  */
> > >> +      tree op1 = TREE_OPERAND (rhs, 1);
> > >> +      context = check_address_of_packed_member (type, op1);
> > >> +      if (context)
> > >> +       rhs = op1;
> > >> +      else
> > >> +       {
> > >> +         /* Check the ELSE path.  */
> > >> +         rhs = TREE_OPERAND (rhs, 2);
> > >> +         context = check_address_of_packed_member (type, rhs);
> > >> +       }
> > >> +    }
> > >
> > >
> > > Likewise, what if you have more levels of COND_EXPR?  Or COMPOUND_EXPR
> > > within COND_EXPR?
> >
> > Fixed, now I got
> >
> > [hjl@gnu-cfl-1 pr51628-5]$ cat z.i
> > struct A {
> >   int i;
> > } __attribute__ ((packed));
> >
> > int*
> > foo3 (struct A *p1, int *q1, int *q2, struct A *p2)
> > {
> >   return (q1
> >           ? &p1->i
> >           : (q2 ? &p2->i : q2));
> > }
> > [hjl@gnu-cfl-1 pr51628-5]$ make z.s
> > /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> > -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> > -S z.i
> > z.i: In function ‘foo3’:
> > z.i:9:13: warning: taking address of packed member of ‘struct A’ may
> > result in an unaligned pointer value [-Waddress-of-packed-member]
> > 9 |           ? &p1->i
> >   |             ^~~~~~
> > z.i:10:19: warning: taking address of packed member of ‘struct A’ may
> > result in an unaligned pointer value [-Waddress-of-packed-member]
> > 10 |           : (q2 ? &p2->i : q2));
> >    |                   ^~~~~~
> > [hjl@gnu-cfl-1 pr51628-5]$
> >
> > >> @@ -7470,6 +7470,9 @@ convert_for_arg_passing (tree type, tree val,
> > >> tsubst_flags_t complain)
> > >> +  warn_for_address_or_pointer_of_packed_member (true, type, val);
> > >
> > >
> > >> @@ -8914,6 +8914,8 @@ convert_for_assignment (tree type, tree rhs,
> > >> +  warn_for_address_or_pointer_of_packed_member (true, type, rhs);
> > >
> > >
> > > Why would address_p be true in these calls?  It seems that you are warning
> > > at the point of assignment but looking for the warning about taking the
> > > address rather than the one about assignment.
> >
> > It happens only with C for incompatible pointer conversion:
> >
> > [hjl@gnu-cfl-1 pr51628-2]$ cat c.i
> > struct B { int i; };
> > struct C { struct B b; } __attribute__ ((packed));
> >
> > long* g8 (struct C *p) { return p; }
> > [hjl@gnu-cfl-1 pr51628-2]$ make c.s
> > /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> > -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> > -S c.i
> > c.i: In function ‘g8’:
> > c.i:4:33: warning: returning ‘struct C *’ from a function with
> > incompatible return type ‘long int *’ [-Wincompatible-pointer-types]
> > 4 | long* g8 (struct C *p) { return p; }
> >   |                                 ^
> > c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment
> > 1) to ‘long int *’ (alignment 8) may may result in an unaligned
> > pointer value [-Waddress-of-packed-member]
> > 4 | long* g8 (struct C *p) { return p; }
> >   |                  ^
> > c.i:2:8: note: defined here
> > 2 | struct C { struct B b; } __attribute__ ((packed));
> >   |        ^
> > [hjl@gnu-cfl-1 pr51628-2]$
> >
> > address_p is false in this case and rhs is PARM_DECL, VAR_DECL or
> > NOP_EXPR.  This comes from convert_for_assignment in c/c-typeck.c.
> >
> > For other compatible pointer assignment, address_p is true and rhs is
> > ADDR_EXPR, PARM_DECL, VAR_DECL or NOP_EXPR.   Check
> > for  ADDR_EXPR won't work.
> >
> > address_p isn't an appropriate parameter name.  I changed it to convert_p
> > to indicate that it is an incompatible pointer type conversion.
> >
> > > If you want to warn about taking the address, shouldn't that happen under
> > > cp_build_addr_expr?  Alternately, drop the address_p parameter and choose
> > > your path inside warn_for_*_packed_member based on whether rhs is an
> > > ADDR_EXPR there rather than in the caller.
> > >
> >
> > Here is the updated patch.  OK for trunk?
> >
> > Thanks.
>
> PING:
>
> https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01452.html
>
>

PING.

-- 
H.J.

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

* Re: V4 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-09-25 15:47 V4 [PATCH] C/C++: Add -Waddress-of-packed-member H.J. Lu
  2018-11-04 15:16 ` PING: " H.J. Lu
@ 2018-12-13 20:50 ` Jason Merrill
  2018-12-14  0:09   ` V5 " H.J. Lu
  1 sibling, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-13 20:50 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph Myers, Martin Sebor, GCC Patches

On 9/25/18 11:46 AM, H.J. Lu wrote:
> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
>>>
>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
>>> wrote:
>>>>
>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>
>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
>>>>> wrote:
>>>>>>
>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>>>
>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
>>>>>>>> +    {
>>>>>>>> +      /* Check the THEN path first.  */
>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
>>>>>>>> +      context = check_address_of_packed_member (type, op1);
>>>>>>>
>>>>>>>
>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
>>>>>>> 1 is omitted.
>>>>>>
>>>>>>
>>>>>> Doesn't that just use a SAVE_EXPR?
>>>>>
>>>>>
>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
>>>>
>>>>
>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
>>>> is produced directly.
>>>
>>>
>>> Here is the updated patch.  Changes from the last one:
>>>
>>> 1. Handle COMPOUND_EXPR.
>>> 2. Fixed typos in comments.
>>> 3. Combined warn_for_pointer_of_packed_member and
>>> warn_for_address_of_packed_member into
>>> warn_for_address_or_pointer_of_packed_member.
>>
>>
>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
>>
>>
>> I think this would read better as
>>
>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
>> [-Waddress-of-packed-member]
> 
> Fixed.
> 
>>> +      while (TREE_CODE (base) == ARRAY_REF)
>>> +       base = TREE_OPERAND (base, 0);
>>> +      if (TREE_CODE (base) != COMPONENT_REF)
>>> +       return NULL_TREE;
>>
>>
>> Are you deliberately not handling the other handled_component_p cases? If
>> so, there should be a comment.
> 
> I changed it to
> 
>       while (handled_component_p (base))
>          {
>            enum tree_code code = TREE_CODE (base);
>            if (code == COMPONENT_REF)
>              break;
>            switch (code)
>              {
>              case ARRAY_REF:
>                base = TREE_OPERAND (base, 0);
>                break;
>              default:
>                /* FIXME: Can it ever happen?  */
>                gcc_unreachable ();
>                break;
>              }
>          }
> 
> Is there a testcase to trigger this ICE? I couldn't find one.

You can take the address of an element of complex:

   __complex int i;
   int *p = &__real(i);

You may get VIEW_CONVERT_EXPR with location wrappers.

>>> +  /* Check alignment of the object.  */
>>> +  if (TREE_CODE (object) == COMPONENT_REF)
>>> +    {
>>> +      field = TREE_OPERAND (object, 1);
>>> +      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
>>> +       {
>>> +         type_align = TYPE_ALIGN (type);
>>> +         context = DECL_CONTEXT (field);
>>> +         record_align = TYPE_ALIGN (context);
>>> +         if ((record_align % type_align) != 0)
>>> +           return context;
>>> +       }
>>> +    }
>>
>>
>> Why doesn't this recurse?  What if you have a packed field three
>> COMPONENT_REFs down?
> 
> My patch works on
> [hjl@gnu-cfl-1 pr51628-4]$ cat x.i
> struct A { int i; } __attribute__ ((packed));
> struct B { struct A a; };
> struct C { struct B b; };
> 
> extern struct C *p;
> 
> int* g8 (void) { return &p->b.a.i; }
> [hjl@gnu-cfl-1 pr51628-4]$ make x.s
> /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> -S x.i
> x.i: In function ‘g8’:
> x.i:7:25: warning: taking address of packed member of ‘struct A’ may
> result in an unaligned pointer value [-Waddress-of-packed-member]
> 7 | int* g8 (void) { return &p->b.a.i; }
>    |                         ^~~~~~~~~
> [hjl@gnu-cfl-1 pr51628-4]$
> 
> If it isn't what you had in mind, can you give me a testcase?

In that testcase, 'i' is the top COMPONENT_EXPR.  What I was talking 
about would be more like

  struct A { int i; };
  struct B { struct A a; };
  struct C { struct B b __attribute__ ((packed)); };

  extern struct C *p;

  int* g8 (void) { return &p->b.a.i; }

Jason

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

* V5 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-13 20:50 ` Jason Merrill
@ 2018-12-14  0:09   ` H.J. Lu
  2018-12-14 22:10     ` Jason Merrill
  0 siblings, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-12-14  0:09 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph S. Myers, Martin Sebor, GCC Patches

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

On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 9/25/18 11:46 AM, H.J. Lu wrote:
> > On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> >> On 07/23/2018 05:24 PM, H.J. Lu wrote:
> >>>
> >>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> >>> wrote:
> >>>>
> >>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> >>>>
> >>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> >>>>> wrote:
> >>>>>>
> >>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> >>>>>>
> >>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> >>>>>>>> +    {
> >>>>>>>> +      /* Check the THEN path first.  */
> >>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> >>>>>>>> +      context = check_address_of_packed_member (type, op1);
> >>>>>>>
> >>>>>>>
> >>>>>>> This should handle the GNU extension of re-using operand 0 if operand
> >>>>>>> 1 is omitted.
> >>>>>>
> >>>>>>
> >>>>>> Doesn't that just use a SAVE_EXPR?
> >>>>>
> >>>>>
> >>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> >>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> >>>>
> >>>>
> >>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> >>>> is produced directly.
> >>>
> >>>
> >>> Here is the updated patch.  Changes from the last one:
> >>>
> >>> 1. Handle COMPOUND_EXPR.
> >>> 2. Fixed typos in comments.
> >>> 3. Combined warn_for_pointer_of_packed_member and
> >>> warn_for_address_of_packed_member into
> >>> warn_for_address_or_pointer_of_packed_member.
> >>
> >>
> >>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> >>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> >>
> >>
> >> I think this would read better as
> >>
> >> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> >> ‘long int *’ (alignment 8) may result in an unaligned pointer value
> >> [-Waddress-of-packed-member]
> >
> > Fixed.
> >
> >>> +      while (TREE_CODE (base) == ARRAY_REF)
> >>> +       base = TREE_OPERAND (base, 0);
> >>> +      if (TREE_CODE (base) != COMPONENT_REF)
> >>> +       return NULL_TREE;
> >>
> >>
> >> Are you deliberately not handling the other handled_component_p cases? If
> >> so, there should be a comment.
> >
> > I changed it to
> >
> >       while (handled_component_p (base))
> >          {
> >            enum tree_code code = TREE_CODE (base);
> >            if (code == COMPONENT_REF)
> >              break;
> >            switch (code)
> >              {
> >              case ARRAY_REF:
> >                base = TREE_OPERAND (base, 0);
> >                break;
> >              default:
> >                /* FIXME: Can it ever happen?  */
> >                gcc_unreachable ();
> >                break;
> >              }
> >          }
> >
> > Is there a testcase to trigger this ICE? I couldn't find one.
>
> You can take the address of an element of complex:
>
>    __complex int i;
>    int *p = &__real(i);
>
> You may get VIEW_CONVERT_EXPR with location wrappers.

Fixed.  I replaced gcc_unreachable with return NULL_TREE;

> >>> +  /* Check alignment of the object.  */
> >>> +  if (TREE_CODE (object) == COMPONENT_REF)
> >>> +    {
> >>> +      field = TREE_OPERAND (object, 1);
> >>> +      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
> >>> +       {
> >>> +         type_align = TYPE_ALIGN (type);
> >>> +         context = DECL_CONTEXT (field);
> >>> +         record_align = TYPE_ALIGN (context);
> >>> +         if ((record_align % type_align) != 0)
> >>> +           return context;
> >>> +       }
> >>> +    }
> >>
> >>
> >> Why doesn't this recurse?  What if you have a packed field three
> >> COMPONENT_REFs down?
> >
> > My patch works on
> > [hjl@gnu-cfl-1 pr51628-4]$ cat x.i
> > struct A { int i; } __attribute__ ((packed));
> > struct B { struct A a; };
> > struct C { struct B b; };
> >
> > extern struct C *p;
> >
> > int* g8 (void) { return &p->b.a.i; }
> > [hjl@gnu-cfl-1 pr51628-4]$ make x.s
> > /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> > -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> > -S x.i
> > x.i: In function ‘g8’:
> > x.i:7:25: warning: taking address of packed member of ‘struct A’ may
> > result in an unaligned pointer value [-Waddress-of-packed-member]
> > 7 | int* g8 (void) { return &p->b.a.i; }
> >    |                         ^~~~~~~~~
> > [hjl@gnu-cfl-1 pr51628-4]$
> >
> > If it isn't what you had in mind, can you give me a testcase?
>
> In that testcase, 'i' is the top COMPONENT_EXPR.  What I was talking
> about would be more like
>
>   struct A { int i; };
>   struct B { struct A a; };
>   struct C { struct B b __attribute__ ((packed)); };
>
>   extern struct C *p;
>
>   int* g8 (void) { return &p->b.a.i; }
>

Fixed with a recursive call:

  tree context = check_alignment_of_packed_member (type, field);
  if (context)
    return context;

  /* Check alignment of the object.  */
  while (TREE_CODE (object) == COMPONENT_REF)
    {
      field = TREE_OPERAND (object, 1);
      context = check_alignment_of_packed_member (type, field);
      if (context)
        return context;
      object = TREE_OPERAND (object, 0);
    }

  return NULL_TREE;

Here is the updated patch.

Tested on i686 and x86-64.  OK for trunk?

Thanks.


-- 
H.J.

[-- Attachment #2: 0001-C-C-Add-Waddress-of-packed-member.patch --]
[-- Type: text/x-patch, Size: 49613 bytes --]

From a2d11ab284fa9d04b38c05c9df6a615f951b304d Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 12 Jan 2018 21:12:05 -0800
Subject: [PATCH] C/C++: Add -Waddress-of-packed-member
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When address of packed member of struct or union is taken, it may result
in an unaligned pointer value.  This patch adds -Waddress-of-packed-member
to check alignment at pointer assignment and warn unaligned address as
well as unaligned pointer:

$ cat x.i
struct pair_t
{
  char c;
  int i;
} __attribute__ ((packed));

extern struct pair_t p;
int *addr = &p.i;
$ gcc -O2 -S x.i
x.i:8:13: warning: taking address of packed member of ‘struct pair_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
8 | int *addr = &p.i;
  |             ^

$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
$ gcc -O2 -S c.i -Wno-incompatible-pointer-types
c.i: In function ‘g8’:
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment 1) to ‘long int *’ (alignment 8) may may result in an unaligned pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
$

This warning is enabled by default.  Since read_encoded_value_with_base
in unwind-pe.h has

  union unaligned
    {
      void *ptr;
      unsigned u2 __attribute__ ((mode (HI)));
      unsigned u4 __attribute__ ((mode (SI)));
      unsigned u8 __attribute__ ((mode (DI)));
      signed s2 __attribute__ ((mode (HI)));
      signed s4 __attribute__ ((mode (SI)));
      signed s8 __attribute__ ((mode (DI)));
    } __attribute__((__packed__));
  _Unwind_Internal_Ptr result;

and GCC warns:

gcc/libgcc/unwind-pe.h:210:37: warning: taking address of packed member of 'union unaligned' may result in an unaligned pointer value [-Waddress-of-packed-member]
    result = (_Unwind_Internal_Ptr) u->ptr;
                                    ^
we need to add GCC pragma to ignore -Waddress-of-packed-member.

gcc/c/

	PR c/51628
	* doc/invoke.texi: Document -Wno-address-of-packed-member.

gcc/c-family/

	PR c/51628
	* c-common.h (warn_for_address_or_pointer_of_packed_member): New.
	* c-warn.c (check_alignment_of_packed_member): New function.
	(check_address_of_packed_member): Likewise.
	(check_and_warn_address_of_packed_member): Likewise.
	(warn_for_address_or_pointer_of_packed_member): Likewise.
	* c.opt: Add -Wno-address-of-packed-member.

gcc/c/

	PR c/51628
	* c-typeck.c (convert_for_assignment): Call
	warn_for_address_or_pointer_of_packed_member.

gcc/cp/

	PR c/51628
	* call.c (convert_for_arg_passing): Call
	warn_for_address_or_pointer_of_packed_member.
	* typeck.c (convert_for_assignment): Likewise.

gcc/testsuite/

	PR c/51628
	* c-c++-common/pr51628-1.c: New test.
	* c-c++-common/pr51628-2.c: Likewise.
	* c-c++-common/pr51628-3.c: Likewise.
	* c-c++-common/pr51628-4.c: Likewise.
	* c-c++-common/pr51628-5.c: Likewise.
	* c-c++-common/pr51628-6.c: Likewise.
	* c-c++-common/pr51628-7.c: Likewise.
	* c-c++-common/pr51628-8.c: Likewise.
	* c-c++-common/pr51628-9.c: Likewise.
	* c-c++-common/pr51628-10.c: Likewise.
	* c-c++-common/pr51628-11.c: Likewise.
	* c-c++-common/pr51628-12.c: Likewise.
	* c-c++-common/pr51628-13.c: Likewise.
	* c-c++-common/pr51628-14.c: Likewise.
	* c-c++-common/pr51628-15.c: Likewise.
	* c-c++-common/pr51628-26.c: Likewise.
	* c-c++-common/pr51628-27.c: Likewise.
	* c-c++-common/pr51628-28.c: Likewise.
	* c-c++-common/pr51628-29.c: Likewise.
	* gcc.dg/pr51628-17.c: Likewise.
	* gcc.dg/pr51628-18.c: Likewise.
	* gcc.dg/pr51628-19.c: Likewise.
	* gcc.dg/pr51628-20.c: Likewise.
	* gcc.dg/pr51628-21.c: Likewise.
	* gcc.dg/pr51628-22.c: Likewise.
	* gcc.dg/pr51628-23.c: Likewise.
	* gcc.dg/pr51628-24.c: Likewise.
	* gcc.dg/pr51628-25.c: Likewise.
	* c-c++-common/asan/misalign-1.c: Add
	-Wno-address-of-packed-member.
	* c-c++-common/asan/misalign-2.c: Likewise.
	* c-c++-common/ubsan/align-2.c: Likewise.
	* c-c++-common/ubsan/align-4.c: Likewise.
	* c-c++-common/ubsan/align-6.c: Likewise.
	* c-c++-common/ubsan/align-7.c: Likewise.
	* c-c++-common/ubsan/align-8.c: Likewise.
	* c-c++-common/ubsan/align-10.c: Likewise.
	* g++.dg/ubsan/align-2.C: Likewise.
	* gcc.target/i386/avx512bw-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu64-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu64-2.c: Likewise.

libgcc/

	* unwind-pe.h (read_encoded_value_with_base): Add GCC pragma
	to ignore -Waddress-of-packed-member.
---
 gcc/c-family/c-common.h                       |   1 +
 gcc/c-family/c-warn.c                         | 192 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  11 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |   8 +
 gcc/testsuite/c-c++-common/asan/misalign-1.c  |   2 +-
 gcc/testsuite/c-c++-common/asan/misalign-2.c  |   2 +-
 gcc/testsuite/c-c++-common/pr51628-1.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-10.c       |  24 +++
 gcc/testsuite/c-c++-common/pr51628-11.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-12.c       |  18 ++
 gcc/testsuite/c-c++-common/pr51628-13.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-14.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-15.c       |  14 ++
 gcc/testsuite/c-c++-common/pr51628-16.c       |  13 ++
 gcc/testsuite/c-c++-common/pr51628-2.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-26.c       |  33 +++
 gcc/testsuite/c-c++-common/pr51628-27.c       |  12 ++
 gcc/testsuite/c-c++-common/pr51628-28.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-29.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-3.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-4.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-5.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-6.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-7.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-8.c        |  36 ++++
 gcc/testsuite/c-c++-common/pr51628-9.c        |  36 ++++
 gcc/testsuite/c-c++-common/ubsan/align-10.c   |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-2.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-4.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-6.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-7.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-8.c    |   2 +-
 gcc/testsuite/g++.dg/ubsan/align-2.C          |   2 +-
 gcc/testsuite/gcc.dg/pr51628-17.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-18.c             |  23 +++
 gcc/testsuite/gcc.dg/pr51628-19.c             |  26 +++
 gcc/testsuite/gcc.dg/pr51628-20.c             |  11 +
 gcc/testsuite/gcc.dg/pr51628-21.c             |  11 +
 gcc/testsuite/gcc.dg/pr51628-22.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-23.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-24.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-25.c             |   9 +
 .../gcc.target/i386/avx512bw-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu32-2.c     |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu64-2.c     |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu32-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu64-2.c    |   2 +-
 libgcc/unwind-pe.h                            |   5 +
 52 files changed, 839 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-10.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-11.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-12.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-13.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-14.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-15.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-16.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-26.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-27.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-28.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-29.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-4.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-5.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-6.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-7.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-8.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-9.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-17.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-18.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-19.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-20.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-21.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-22.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-23.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-24.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-25.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343c0b3..eb0ad60940d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1282,6 +1282,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern bool warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_for_address_or_pointer_of_packed_member (bool, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 798ad1bcb39..615134cfdac 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2616,3 +2616,195 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
 }
+
+/* Return struct or union type if the alignment of data memeber, FIELD,
+   is less than the alignment of TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_alignment_of_packed_member (tree type, tree field)
+{
+  /* Check alignment of the data member.  */
+  if (TREE_CODE (field) == FIELD_DECL
+      && (DECL_PACKED (field)
+	  || TYPE_PACKED (TREE_TYPE (field))))
+    {
+      /* Check the expected alignment against the field alignment.  */
+      unsigned int type_align = TYPE_ALIGN (type);
+      tree context = DECL_CONTEXT (field);
+      unsigned int record_align = TYPE_ALIGN (context);
+      if ((record_align % type_align) != 0)
+	return context;
+      tree field_off = byte_position (field);
+      if (!multiple_of_p (TREE_TYPE (field_off), field_off,
+			  size_int (type_align / BITS_PER_UNIT)))
+	return context;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return struct or union type if the right hand value, RHS, takes the
+   unaligned address of packed member of struct or union when assigning
+   to TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_address_of_packed_member (tree type, tree rhs)
+{
+  tree base;
+  tree object;
+  tree field;
+
+  if (INDIRECT_REF_P (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+
+  switch (TREE_CODE (rhs))
+    {
+    case ADDR_EXPR:
+      base = TREE_OPERAND (rhs, 0);
+      while (handled_component_p (base))
+	{
+	  enum tree_code code = TREE_CODE (base);
+	  if (code == COMPONENT_REF)
+	    break;
+	  switch (code)
+	    {
+	    case ARRAY_REF:
+	      base = TREE_OPERAND (base, 0);
+	      break;
+	    default:
+	      return NULL_TREE;
+	    }
+	}
+      if (TREE_CODE (base) != COMPONENT_REF)
+	return NULL_TREE;
+      object = TREE_OPERAND (base, 0);
+      field = TREE_OPERAND (base, 1);
+      break;
+    case COMPONENT_REF:
+      object = TREE_OPERAND (rhs, 0);
+      field = TREE_OPERAND (rhs, 1);
+      break;
+    default:
+      return NULL_TREE;
+    }
+
+  tree context = check_alignment_of_packed_member (type, field);
+  if (context)
+    return context;
+
+  /* Check alignment of the object.  */
+  while (TREE_CODE (object) == COMPONENT_REF)
+    {
+      field = TREE_OPERAND (object, 1);
+      context = check_alignment_of_packed_member (type, field);
+      if (context)
+	return context;
+      object = TREE_OPERAND (object, 0);
+    }
+
+  return NULL_TREE;
+}
+
+/* Check and warn if the right hand value, RHS, takes the unaligned
+   address of packed member of struct or union when assigning to TYPE.  */
+
+static void
+check_and_warn_address_of_packed_member (tree type, tree rhs)
+{
+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      tree context = check_address_of_packed_member (type, rhs);
+      if (context)
+	{
+	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
+	  warning_at (loc, OPT_Waddress_of_packed_member,
+		      "taking address of packed member of %qT may result "
+		      "in an unaligned pointer value",
+		      context);
+	}
+      return;
+    }
+
+  /* Check the THEN path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
+
+  /* Check the ELSE path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
+}
+
+/* Warn if the right hand value, RHS:
+   1. For CONVERT_P == true, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+   2. For CONVERT_P == false, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool convert_p, tree type,
+					      tree rhs)
+{
+  if (!warn_address_of_packed_member)
+    return;
+
+  /* Don't warn if we don't assign RHS to a pointer.  */
+  if (!POINTER_TYPE_P (type))
+    return;
+
+  while (TREE_CODE (rhs) == COMPOUND_EXPR)
+    rhs = TREE_OPERAND (rhs, 1);
+
+  if (convert_p)
+    {
+      bool rhspointer_p;
+      tree rhstype;
+
+      /* Check the original type of RHS.  */
+      switch (TREE_CODE (rhs))
+	{
+	case PARM_DECL:
+	case VAR_DECL:
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = POINTER_TYPE_P (rhstype);
+	  break;
+	case NOP_EXPR:
+	  rhs = TREE_OPERAND (rhs, 0);
+	  if (TREE_CODE (rhs) == ADDR_EXPR)
+	    rhs = TREE_OPERAND (rhs, 0);
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
+	  break;
+	default:
+	  return;
+	}
+
+      if (rhspointer_p && TYPE_PACKED (TREE_TYPE (rhstype)))
+	{
+	  unsigned int type_align = TYPE_ALIGN_UNIT (TREE_TYPE (type));
+	  unsigned int rhs_align = TYPE_ALIGN_UNIT (TREE_TYPE (rhstype));
+	  if ((rhs_align % type_align) != 0)
+	    {
+	      location_t location = EXPR_LOC_OR_LOC (rhs, input_location);
+	      warning_at (location, OPT_Waddress_of_packed_member,
+			  "converting a packed %qT pointer (alignment %d) "
+			  "to %qT (alignment %d) may may result in an "
+			  "unaligned pointer value",
+			  rhstype, rhs_align, type, type_align);
+	      tree decl = TYPE_STUB_DECL (TREE_TYPE (rhstype));
+	      inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	      decl = TYPE_STUB_DECL (TREE_TYPE (type));
+	      if (decl)
+		inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	    }
+	}
+    }
+  else
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+
+      check_and_warn_address_of_packed_member (type, rhs);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 07ff1c84f96..22ccf910a85 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -625,6 +625,10 @@ Wincompatible-pointer-types
 C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning
 Warn when there is a conversion between pointers that have incompatible types.
 
+Waddress-of-packed-member
+C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning
+Warn when the address of packed member of struct or union is taken.
+
 Winit-self
 C ObjC C++ ObjC++ Var(warn_init_self) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about variables which are initialized to themselves.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1a897273088..da4a8169d56 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6724,7 +6724,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    return rhs;
+    {
+      warn_for_address_or_pointer_of_packed_member (false, type,
+						    orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7279,6 +7283,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	    }
 	}
 
+      /* If RHS is't an address, check pointer or array of packed
+	 struct or union.  */
+      warn_for_address_or_pointer_of_packed_member
+	(TREE_CODE (orig_rhs) != ADDR_EXPR, type, orig_rhs);
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36b604..40ffc863091 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7618,6 +7618,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	}
       maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
     }
+
+  warn_for_address_or_pointer_of_packed_member (false, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ac0c81155b5..93b295ade90 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9023,6 +9023,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (false, type, rhs);
+
   return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
 					    complain, flags);
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 44e1069de3b..258760a544a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -358,6 +358,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
 -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
 -Wwrite-strings @gol
+-Waddress-of-packed-member @gol
 -Wzero-as-null-pointer-constant  -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -6981,6 +6982,13 @@ behavior and are not portable in C, so they usually indicate that the
 programmer intended to use @code{strcmp}.  This warning is enabled by
 @option{-Wall}.
 
+@item -Waddress-of-packed-member
+@opindex Waddress-of-packed-member
+@opindex Wno-address-of-packed-member
+Warn when the address of packed member of struct or union is taken,
+which usually results in an unaligned pointer value.  This is
+enabled by default.
+
 @item -Wlogical-op
 @opindex Wlogical-op
 @opindex Wno-logical-op
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-1.c b/gcc/testsuite/c-c++-common/asan/misalign-1.c
index 5cd605ac045..ebeb0306706 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-1.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-2.c b/gcc/testsuite/c-c++-common/asan/misalign-2.c
index a6ed49bac05..b27e22d35a8 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-2.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/pr51628-1.c b/gcc/testsuite/c-c++-common/pr51628-1.c
new file mode 100644
index 00000000000..5324f9cc964
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-1.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-10.c b/gcc/testsuite/c-c++-common/pr51628-10.c
new file mode 100644
index 00000000000..085fe1608c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-10.c
@@ -0,0 +1,24 @@
+/* PR c/51628.  */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+struct pair_t
+{
+  char c;
+  __int128_t i;
+} __attribute__ ((packed));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__((packed)) unaligned_int128_t;
+
+struct pair_t p = {0, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *) &p.i;
+
+int 
+main() 
+{
+  addr->value = ~(__int128_t)0;
+  return (p.i != 1) ? 0 : 1;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-11.c b/gcc/testsuite/c-c++-common/pr51628-11.c
new file mode 100644
index 00000000000..7661232ac88
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-11.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[12];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
diff --git a/gcc/testsuite/c-c++-common/pr51628-12.c b/gcc/testsuite/c-c++-common/pr51628-12.c
new file mode 100644
index 00000000000..bc221fa87ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-12.c
@@ -0,0 +1,18 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[10];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-13.c b/gcc/testsuite/c-c++-common/pr51628-13.c
new file mode 100644
index 00000000000..0edd5e7f84d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-13.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* h4 (struct C *p) { return &p->b.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-14.c b/gcc/testsuite/c-c++-common/pr51628-14.c
new file mode 100644
index 00000000000..f50378b8651
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-14.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+void* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/c-c++-common/pr51628-15.c b/gcc/testsuite/c-c++-common/pr51628-15.c
new file mode 100644
index 00000000000..bcac6d70ad5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-15.c
@@ -0,0 +1,14 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+int*
+f (struct A *p, int *q)
+{
+  return q ? q : &p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-16.c b/gcc/testsuite/c-c++-common/pr51628-16.c
new file mode 100644
index 00000000000..cd502fe76b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-16.c
@@ -0,0 +1,13 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct __attribute__ ((packed)) A { int i; };
+struct B {
+  struct A a;
+} b;
+
+int *p = (int*)&b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+int *q = (int*)&b.a;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-2.c b/gcc/testsuite/c-c++-common/pr51628-2.c
new file mode 100644
index 00000000000..abfb84ddd05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-2.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (8)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-26.c b/gcc/testsuite/c-c++-common/pr51628-26.c
new file mode 100644
index 00000000000..2042379860a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-26.c
@@ -0,0 +1,33 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+struct A p = {1};
+int *addr;
+
+int i, j;
+
+void
+foo1 (void)
+{
+  addr = (i = -1, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo2 (void)
+{
+  addr = (i = -1, j = -2, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo3 (void)
+{
+  addr = (i = -1, (j = -2, &p.i));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-27.c b/gcc/testsuite/c-c++-common/pr51628-27.c
new file mode 100644
index 00000000000..9ae1efd7afb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-27.c
@@ -0,0 +1,12 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; } __attribute__ ((packed));
+struct B { struct A a; };
+struct C { struct B b; };
+
+extern struct C *p;
+
+int* g8 (void) { return &p->b.a.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-28.c b/gcc/testsuite/c-c++-common/pr51628-28.c
new file mode 100644
index 00000000000..e8c752d0b12
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-28.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { 
+  int i;
+} __attribute__ ((packed));
+
+int *
+foo3 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 
+	  ? &p1->i
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? &p2->i : q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-29.c b/gcc/testsuite/c-c++-common/pr51628-29.c
new file mode 100644
index 00000000000..94b3722d2c8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-29.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+g8 (void)
+{
+  return &p->b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-3.c b/gcc/testsuite/c-c++-common/pr51628-3.c
new file mode 100644
index 00000000000..0ea94c845a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-3.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (2)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-4.c b/gcc/testsuite/c-c++-common/pr51628-4.c
new file mode 100644
index 00000000000..c4c1fb72d6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-4.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-5.c b/gcc/testsuite/c-c++-common/pr51628-5.c
new file mode 100644
index 00000000000..9d7c309a0ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-5.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-6.c b/gcc/testsuite/c-c++-common/pr51628-6.c
new file mode 100644
index 00000000000..52aa07a4cf3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-6.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-7.c b/gcc/testsuite/c-c++-common/pr51628-7.c
new file mode 100644
index 00000000000..ae4a681f966
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-7.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+  bar (p0);
+  p1 = &p->i[1];
+  bar (p1);
+  bar (p->i);
+  bar (&p->i[2]);
+  x = p->i;
+  return &p->i[3];
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-8.c b/gcc/testsuite/c-c++-common/pr51628-8.c
new file mode 100644
index 00000000000..cc2dae096ae
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-8.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i[4];
+} __attribute__ ((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-9.c b/gcc/testsuite/c-c++-common/pr51628-9.c
new file mode 100644
index 00000000000..0470aa3b93d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-9.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__ ((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-10.c b/gcc/testsuite/c-c++-common/ubsan/align-10.c
index 56ae9ebfe30..6210533173c 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-10.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct R { int a; } r;
 struct S { struct R a; char b; long long c; short d[10]; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-2.c b/gcc/testsuite/c-c++-common/ubsan/align-2.c
index 071de8c202a..336b1c3c907 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-2.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=alignment" } */
+/* { dg-options "-fsanitize=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-4.c b/gcc/testsuite/c-c++-common/ubsan/align-4.c
index 3252595d330..d5feeee29c6 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-4.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=null,alignment" } */
+/* { dg-options "-fsanitize=null,alignment -Wno-address-of-packed-member" } */
 
 #include "align-2.c"
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-6.c b/gcc/testsuite/c-c++-common/ubsan/align-6.c
index 3364746fb27..0302b7b8894 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-6.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-7.c b/gcc/testsuite/c-c++-common/ubsan/align-7.c
index ec4e87f56d5..dd1e8c91cef 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-7.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-7.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-8.c b/gcc/testsuite/c-c++-common/ubsan/align-8.c
index 61c1ceb6682..5fe0e0fe931 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-8.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/g++.dg/ubsan/align-2.C b/gcc/testsuite/g++.dg/ubsan/align-2.C
index 3e4f5485d02..c97ede88392 100644
--- a/gcc/testsuite/g++.dg/ubsan/align-2.C
+++ b/gcc/testsuite/g++.dg/ubsan/align-2.C
@@ -1,6 +1,6 @@
 // Limit this to known non-strict alignment targets.
 // { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
-// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -Wno-address-of-packed-member -std=c++11" }
 
 typedef const long int L;
 struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
diff --git a/gcc/testsuite/gcc.dg/pr51628-17.c b/gcc/testsuite/gcc.dg/pr51628-17.c
new file mode 100644
index 00000000000..0be95b2294e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-17.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+long* f8 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-18.c b/gcc/testsuite/gcc.dg/pr51628-18.c
new file mode 100644
index 00000000000..03a04eff75c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-18.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    int c[k];
+    int x[n];
+  } __attribute__ ((packed, aligned (4)));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+  foo (p0);
+  p1 = &p->x[1];
+  foo (p1);
+  return &p->x[1];
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-19.c b/gcc/testsuite/gcc.dg/pr51628-19.c
new file mode 100644
index 00000000000..7ff03e85cea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-19.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    char c[k];
+    int x[n];
+  } __attribute__ ((packed));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p0);
+  p1 = &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p1);
+  return &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-20.c b/gcc/testsuite/gcc.dg/pr51628-20.c
new file mode 100644
index 00000000000..80888283b73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-20.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C *p;
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-21.c b/gcc/testsuite/gcc.dg/pr51628-21.c
new file mode 100644
index 00000000000..3077e72c8d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-21.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C p[];
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-22.c b/gcc/testsuite/gcc.dg/pr51628-22.c
new file mode 100644
index 00000000000..1bd5d791639
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-22.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* g4 (struct C *p) { return &p->b; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-23.c b/gcc/testsuite/gcc.dg/pr51628-23.c
new file mode 100644
index 00000000000..5709be60ac8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-23.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+char* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/gcc.dg/pr51628-24.c b/gcc/testsuite/gcc.dg/pr51628-24.c
new file mode 100644
index 00000000000..3ad99cd2f16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-24.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+short* f2 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-25.c b/gcc/testsuite/gcc.dg/pr51628-25.c
new file mode 100644
index 00000000000..2fc5c028711
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-25.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+long* g8 (struct C *p) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
index a61609c40d2..c6e3ebdc507 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw" } */
+/* { dg-options "-O2 -mavx512bw -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512bw } */
 
 #define AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
index f2edc3dff7b..95a657fc5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
index 14176965ace..954b091d976 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
index 45ae83d4552..81465f8d9a0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 /* { dg-require-effective-target avx512bw } */
 
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
index 4b928d0cd42..19390664bd0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
index 1863ed3616f..aea0c12a5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index dd5ae95fc2c..05c2fb4dd50 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -177,6 +177,9 @@ read_sleb128 (const unsigned char *p, _sleb128_t *val)
    The function returns P incremented past the value.  BASE is as given
    by base_of_encoded_value for this encoding in the appropriate context.  */
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 static const unsigned char *
 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
 			      const unsigned char *p, _Unwind_Ptr *val)
@@ -270,6 +273,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
   return p;
 }
 
+#pragma GCC diagnostic pop
+
 #ifndef NO_BASE_OF_ENCODED_VALUE
 
 /* Like read_encoded_value_with_base, but get the base from the context
-- 
2.19.2


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

* Re: V5 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-14  0:09   ` V5 " H.J. Lu
@ 2018-12-14 22:10     ` Jason Merrill
  2018-12-14 22:48       ` V6 " H.J. Lu
  0 siblings, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-14 22:10 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph S. Myers, Martin Sebor, GCC Patches

On 12/13/18 6:56 PM, H.J. Lu wrote:
> On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
>>
>> On 9/25/18 11:46 AM, H.J. Lu wrote:
>>> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
>>>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
>>>>>
>>>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
>>>>> wrote:
>>>>>>
>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>>>
>>>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>>>>>
>>>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
>>>>>>>>>> +    {
>>>>>>>>>> +      /* Check the THEN path first.  */
>>>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
>>>>>>>>>> +      context = check_address_of_packed_member (type, op1);
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
>>>>>>>>> 1 is omitted.
>>>>>>>>
>>>>>>>>
>>>>>>>> Doesn't that just use a SAVE_EXPR?
>>>>>>>
>>>>>>>
>>>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
>>>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
>>>>>>
>>>>>>
>>>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
>>>>>> is produced directly.
>>>>>
>>>>>
>>>>> Here is the updated patch.  Changes from the last one:
>>>>>
>>>>> 1. Handle COMPOUND_EXPR.
>>>>> 2. Fixed typos in comments.
>>>>> 3. Combined warn_for_pointer_of_packed_member and
>>>>> warn_for_address_of_packed_member into
>>>>> warn_for_address_or_pointer_of_packed_member.
>>>>
>>>>
>>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
>>>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
>>>>
>>>>
>>>> I think this would read better as
>>>>
>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
>>>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
>>>> [-Waddress-of-packed-member]
>>>
>>> Fixed.
>>>
>>>>> +      while (TREE_CODE (base) == ARRAY_REF)
>>>>> +       base = TREE_OPERAND (base, 0);
>>>>> +      if (TREE_CODE (base) != COMPONENT_REF)
>>>>> +       return NULL_TREE;
>>>>
>>>>
>>>> Are you deliberately not handling the other handled_component_p cases? If
>>>> so, there should be a comment.
>>>
>>> I changed it to
>>>
>>>        while (handled_component_p (base))
>>>           {
>>>             enum tree_code code = TREE_CODE (base);
>>>             if (code == COMPONENT_REF)
>>>               break;
>>>             switch (code)
>>>               {
>>>               case ARRAY_REF:
>>>                 base = TREE_OPERAND (base, 0);
>>>                 break;
>>>               default:
>>>                 /* FIXME: Can it ever happen?  */
>>>                 gcc_unreachable ();
>>>                 break;
>>>               }
>>>           }
>>>
>>> Is there a testcase to trigger this ICE? I couldn't find one.
>>
>> You can take the address of an element of complex:
>>
>>     __complex int i;
>>     int *p = &__real(i);
>>
>> You may get VIEW_CONVERT_EXPR with location wrappers.
> 
> Fixed.  I replaced gcc_unreachable with return NULL_TREE;

Then we're back to my earlier question: are you deliberately not 
handling the other cases?  Why not look through them as well?  What if 
e.g. the operand of __real is a packed field?

Jason

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

* V6 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-14 22:10     ` Jason Merrill
@ 2018-12-14 22:48       ` H.J. Lu
  2018-12-17  9:39         ` Richard Biener
  0 siblings, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-12-14 22:48 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph S. Myers, Martin Sebor, GCC Patches

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

On Fri, Dec 14, 2018 at 2:10 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 12/13/18 6:56 PM, H.J. Lu wrote:
> > On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
> >>
> >> On 9/25/18 11:46 AM, H.J. Lu wrote:
> >>> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> >>>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
> >>>>>
> >>>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> >>>>> wrote:
> >>>>>>
> >>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> >>>>>>
> >>>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> >>>>>>> wrote:
> >>>>>>>>
> >>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> >>>>>>>>
> >>>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> >>>>>>>>>> +    {
> >>>>>>>>>> +      /* Check the THEN path first.  */
> >>>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> >>>>>>>>>> +      context = check_address_of_packed_member (type, op1);
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
> >>>>>>>>> 1 is omitted.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> Doesn't that just use a SAVE_EXPR?
> >>>>>>>
> >>>>>>>
> >>>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> >>>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> >>>>>>
> >>>>>>
> >>>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> >>>>>> is produced directly.
> >>>>>
> >>>>>
> >>>>> Here is the updated patch.  Changes from the last one:
> >>>>>
> >>>>> 1. Handle COMPOUND_EXPR.
> >>>>> 2. Fixed typos in comments.
> >>>>> 3. Combined warn_for_pointer_of_packed_member and
> >>>>> warn_for_address_of_packed_member into
> >>>>> warn_for_address_or_pointer_of_packed_member.
> >>>>
> >>>>
> >>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> >>>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> >>>>
> >>>>
> >>>> I think this would read better as
> >>>>
> >>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> >>>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
> >>>> [-Waddress-of-packed-member]
> >>>
> >>> Fixed.
> >>>
> >>>>> +      while (TREE_CODE (base) == ARRAY_REF)
> >>>>> +       base = TREE_OPERAND (base, 0);
> >>>>> +      if (TREE_CODE (base) != COMPONENT_REF)
> >>>>> +       return NULL_TREE;
> >>>>
> >>>>
> >>>> Are you deliberately not handling the other handled_component_p cases? If
> >>>> so, there should be a comment.
> >>>
> >>> I changed it to
> >>>
> >>>        while (handled_component_p (base))
> >>>           {
> >>>             enum tree_code code = TREE_CODE (base);
> >>>             if (code == COMPONENT_REF)
> >>>               break;
> >>>             switch (code)
> >>>               {
> >>>               case ARRAY_REF:
> >>>                 base = TREE_OPERAND (base, 0);
> >>>                 break;
> >>>               default:
> >>>                 /* FIXME: Can it ever happen?  */
> >>>                 gcc_unreachable ();
> >>>                 break;
> >>>               }
> >>>           }
> >>>
> >>> Is there a testcase to trigger this ICE? I couldn't find one.
> >>
> >> You can take the address of an element of complex:
> >>
> >>     __complex int i;
> >>     int *p = &__real(i);
> >>
> >> You may get VIEW_CONVERT_EXPR with location wrappers.
> >
> > Fixed.  I replaced gcc_unreachable with return NULL_TREE;
>
> Then we're back to my earlier question: are you deliberately not
> handling the other cases?  Why not look through them as well?  What if
> e.g. the operand of __real is a packed field?
>

Here is the updated patch with

diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 615134cfdac..f105742598e 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2669,6 +2669,9 @@ check_address_of_packed_member (tree type, tree rhs)
    switch (code)
      {
      case ARRAY_REF:
+     case REALPART_EXPR:
+     case IMAGPART_EXPR:
+     case VIEW_CONVERT_EXPR:
        base = TREE_OPERAND (base, 0);
        break;
      default:

Now I got

[hjl@gnu-cfl-1 pr51628-6]$ cat foo.i
struct A { __complex int i; };
struct B { struct A a; };
struct C { struct B b __attribute__ ((packed)); };

extern struct C *p;

int*
foo1 (void)
{
  return &__real(p->b.a.i);
}
int*
foo2 (void)
{
  return &__imag(p->b.a.i);
}
[hjl@gnu-cfl-1 pr51628-6]$ make foo.s
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S foo.i
foo.i: In function ‘foo1’:
foo.i:10:10: warning: taking address of packed member of ‘struct C’
may result in an unaligned pointer value [-Waddress-of-packed-member]
   10 |   return &__real(p->b.a.i);
      |          ^~~~~~~~~~~~~~~~~
foo.i: In function ‘foo2’:
foo.i:15:10: warning: taking address of packed member of ‘struct C’
may result in an unaligned pointer value [-Waddress-of-packed-member]
   15 |   return &__imag(p->b.a.i);
      |          ^~~~~~~~~~~~~~~~~
[hjl@gnu-cfl-1 pr51628-6]$

OK for trunk?

-- 
H.J.

[-- Attachment #2: 0001-C-C-Add-Waddress-of-packed-member.patch --]
[-- Type: application/x-patch, Size: 50574 bytes --]

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

* Re: V6 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-14 22:48       ` V6 " H.J. Lu
@ 2018-12-17  9:39         ` Richard Biener
  2018-12-17 12:43           ` H.J. Lu
  0 siblings, 1 reply; 23+ messages in thread
From: Richard Biener @ 2018-12-17  9:39 UTC (permalink / raw)
  To: H. J. Lu; +Cc: Jason Merrill, Joseph S. Myers, Martin Sebor, GCC Patches

On Fri, Dec 14, 2018 at 11:48 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Fri, Dec 14, 2018 at 2:10 PM Jason Merrill <jason@redhat.com> wrote:
> >
> > On 12/13/18 6:56 PM, H.J. Lu wrote:
> > > On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
> > >>
> > >> On 9/25/18 11:46 AM, H.J. Lu wrote:
> > >>> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> > >>>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
> > >>>>>
> > >>>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> > >>>>> wrote:
> > >>>>>>
> > >>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > >>>>>>
> > >>>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> > >>>>>>> wrote:
> > >>>>>>>>
> > >>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > >>>>>>>>
> > >>>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> > >>>>>>>>>> +    {
> > >>>>>>>>>> +      /* Check the THEN path first.  */
> > >>>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> > >>>>>>>>>> +      context = check_address_of_packed_member (type, op1);
> > >>>>>>>>>
> > >>>>>>>>>
> > >>>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
> > >>>>>>>>> 1 is omitted.
> > >>>>>>>>
> > >>>>>>>>
> > >>>>>>>> Doesn't that just use a SAVE_EXPR?
> > >>>>>>>
> > >>>>>>>
> > >>>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> > >>>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> > >>>>>>
> > >>>>>>
> > >>>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> > >>>>>> is produced directly.
> > >>>>>
> > >>>>>
> > >>>>> Here is the updated patch.  Changes from the last one:
> > >>>>>
> > >>>>> 1. Handle COMPOUND_EXPR.
> > >>>>> 2. Fixed typos in comments.
> > >>>>> 3. Combined warn_for_pointer_of_packed_member and
> > >>>>> warn_for_address_of_packed_member into
> > >>>>> warn_for_address_or_pointer_of_packed_member.
> > >>>>
> > >>>>
> > >>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> > >>>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> > >>>>
> > >>>>
> > >>>> I think this would read better as
> > >>>>
> > >>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> > >>>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
> > >>>> [-Waddress-of-packed-member]
> > >>>
> > >>> Fixed.
> > >>>
> > >>>>> +      while (TREE_CODE (base) == ARRAY_REF)
> > >>>>> +       base = TREE_OPERAND (base, 0);
> > >>>>> +      if (TREE_CODE (base) != COMPONENT_REF)
> > >>>>> +       return NULL_TREE;
> > >>>>
> > >>>>
> > >>>> Are you deliberately not handling the other handled_component_p cases? If
> > >>>> so, there should be a comment.
> > >>>
> > >>> I changed it to
> > >>>
> > >>>        while (handled_component_p (base))
> > >>>           {
> > >>>             enum tree_code code = TREE_CODE (base);
> > >>>             if (code == COMPONENT_REF)
> > >>>               break;
> > >>>             switch (code)
> > >>>               {
> > >>>               case ARRAY_REF:
> > >>>                 base = TREE_OPERAND (base, 0);
> > >>>                 break;
> > >>>               default:
> > >>>                 /* FIXME: Can it ever happen?  */
> > >>>                 gcc_unreachable ();
> > >>>                 break;
> > >>>               }
> > >>>           }
> > >>>
> > >>> Is there a testcase to trigger this ICE? I couldn't find one.
> > >>
> > >> You can take the address of an element of complex:
> > >>
> > >>     __complex int i;
> > >>     int *p = &__real(i);
> > >>
> > >> You may get VIEW_CONVERT_EXPR with location wrappers.
> > >
> > > Fixed.  I replaced gcc_unreachable with return NULL_TREE;
> >
> > Then we're back to my earlier question: are you deliberately not
> > handling the other cases?  Why not look through them as well?  What if
> > e.g. the operand of __real is a packed field?
> >
>
> Here is the updated patch with
>
> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> index 615134cfdac..f105742598e 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -2669,6 +2669,9 @@ check_address_of_packed_member (tree type, tree rhs)
>     switch (code)
>       {
>       case ARRAY_REF:
> +     case REALPART_EXPR:
> +     case IMAGPART_EXPR:
> +     case VIEW_CONVERT_EXPR:
>         base = TREE_OPERAND (base, 0);
>         break;
>       default:

don't we have handled_component_p () for this?  (you're still
missing BIT_FIELD_REF which might be used for vector
element accesses)

>
> Now I got
>
> [hjl@gnu-cfl-1 pr51628-6]$ cat foo.i
> struct A { __complex int i; };
> struct B { struct A a; };
> struct C { struct B b __attribute__ ((packed)); };
>
> extern struct C *p;
>
> int*
> foo1 (void)
> {
>   return &__real(p->b.a.i);
> }
> int*
> foo2 (void)
> {
>   return &__imag(p->b.a.i);
> }
> [hjl@gnu-cfl-1 pr51628-6]$ make foo.s
> /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> -S foo.i
> foo.i: In function ‘foo1’:
> foo.i:10:10: warning: taking address of packed member of ‘struct C’
> may result in an unaligned pointer value [-Waddress-of-packed-member]
>    10 |   return &__real(p->b.a.i);
>       |          ^~~~~~~~~~~~~~~~~
> foo.i: In function ‘foo2’:
> foo.i:15:10: warning: taking address of packed member of ‘struct C’
> may result in an unaligned pointer value [-Waddress-of-packed-member]
>    15 |   return &__imag(p->b.a.i);
>       |          ^~~~~~~~~~~~~~~~~
> [hjl@gnu-cfl-1 pr51628-6]$
>
> OK for trunk?
>
> --
> H.J.

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

* Re: V6 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-17  9:39         ` Richard Biener
@ 2018-12-17 12:43           ` H.J. Lu
  2018-12-17 13:34             ` Richard Biener
  2018-12-17 13:53             ` Jason Merrill
  0 siblings, 2 replies; 23+ messages in thread
From: H.J. Lu @ 2018-12-17 12:43 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Jason Merrill, Joseph S. Myers, Martin Sebor, GCC Patches

On Mon, Dec 17, 2018 at 1:39 AM Richard Biener
<richard.guenther@gmail.com> wrote:
>
> On Fri, Dec 14, 2018 at 11:48 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Fri, Dec 14, 2018 at 2:10 PM Jason Merrill <jason@redhat.com> wrote:
> > >
> > > On 12/13/18 6:56 PM, H.J. Lu wrote:
> > > > On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
> > > >>
> > > >> On 9/25/18 11:46 AM, H.J. Lu wrote:
> > > >>> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> > > >>>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
> > > >>>>>
> > > >>>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> > > >>>>> wrote:
> > > >>>>>>
> > > >>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > > >>>>>>
> > > >>>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> > > >>>>>>> wrote:
> > > >>>>>>>>
> > > >>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > > >>>>>>>>
> > > >>>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> > > >>>>>>>>>> +    {
> > > >>>>>>>>>> +      /* Check the THEN path first.  */
> > > >>>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> > > >>>>>>>>>> +      context = check_address_of_packed_member (type, op1);
> > > >>>>>>>>>
> > > >>>>>>>>>
> > > >>>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
> > > >>>>>>>>> 1 is omitted.
> > > >>>>>>>>
> > > >>>>>>>>
> > > >>>>>>>> Doesn't that just use a SAVE_EXPR?
> > > >>>>>>>
> > > >>>>>>>
> > > >>>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> > > >>>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> > > >>>>>>
> > > >>>>>>
> > > >>>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> > > >>>>>> is produced directly.
> > > >>>>>
> > > >>>>>
> > > >>>>> Here is the updated patch.  Changes from the last one:
> > > >>>>>
> > > >>>>> 1. Handle COMPOUND_EXPR.
> > > >>>>> 2. Fixed typos in comments.
> > > >>>>> 3. Combined warn_for_pointer_of_packed_member and
> > > >>>>> warn_for_address_of_packed_member into
> > > >>>>> warn_for_address_or_pointer_of_packed_member.
> > > >>>>
> > > >>>>
> > > >>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> > > >>>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> > > >>>>
> > > >>>>
> > > >>>> I think this would read better as
> > > >>>>
> > > >>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> > > >>>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
> > > >>>> [-Waddress-of-packed-member]
> > > >>>
> > > >>> Fixed.
> > > >>>
> > > >>>>> +      while (TREE_CODE (base) == ARRAY_REF)
> > > >>>>> +       base = TREE_OPERAND (base, 0);
> > > >>>>> +      if (TREE_CODE (base) != COMPONENT_REF)
> > > >>>>> +       return NULL_TREE;
> > > >>>>
> > > >>>>
> > > >>>> Are you deliberately not handling the other handled_component_p cases? If
> > > >>>> so, there should be a comment.
> > > >>>
> > > >>> I changed it to
> > > >>>
> > > >>>        while (handled_component_p (base))
> > > >>>           {
> > > >>>             enum tree_code code = TREE_CODE (base);
> > > >>>             if (code == COMPONENT_REF)
> > > >>>               break;
> > > >>>             switch (code)
> > > >>>               {
> > > >>>               case ARRAY_REF:
> > > >>>                 base = TREE_OPERAND (base, 0);
> > > >>>                 break;
> > > >>>               default:
> > > >>>                 /* FIXME: Can it ever happen?  */
> > > >>>                 gcc_unreachable ();
> > > >>>                 break;
> > > >>>               }
> > > >>>           }
> > > >>>
> > > >>> Is there a testcase to trigger this ICE? I couldn't find one.
> > > >>
> > > >> You can take the address of an element of complex:
> > > >>
> > > >>     __complex int i;
> > > >>     int *p = &__real(i);
> > > >>
> > > >> You may get VIEW_CONVERT_EXPR with location wrappers.
> > > >
> > > > Fixed.  I replaced gcc_unreachable with return NULL_TREE;
> > >
> > > Then we're back to my earlier question: are you deliberately not
> > > handling the other cases?  Why not look through them as well?  What if
> > > e.g. the operand of __real is a packed field?
> > >
> >
> > Here is the updated patch with
> >
> > diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> > index 615134cfdac..f105742598e 100644
> > --- a/gcc/c-family/c-warn.c
> > +++ b/gcc/c-family/c-warn.c
> > @@ -2669,6 +2669,9 @@ check_address_of_packed_member (tree type, tree rhs)
> >     switch (code)
> >       {
> >       case ARRAY_REF:
> > +     case REALPART_EXPR:
> > +     case IMAGPART_EXPR:
> > +     case VIEW_CONVERT_EXPR:
> >         base = TREE_OPERAND (base, 0);
> >         break;
> >       default:
>
> don't we have handled_component_p () for this?  (you're still
> missing BIT_FIELD_REF which might be used for vector
> element accesses)
>

Do you have a testcase?

-- 
H.J.

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

* Re: V6 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-17 12:43           ` H.J. Lu
@ 2018-12-17 13:34             ` Richard Biener
  2018-12-17 13:53             ` Jason Merrill
  1 sibling, 0 replies; 23+ messages in thread
From: Richard Biener @ 2018-12-17 13:34 UTC (permalink / raw)
  To: H. J. Lu; +Cc: Jason Merrill, Joseph S. Myers, Martin Sebor, GCC Patches

On Mon, Dec 17, 2018 at 1:43 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Dec 17, 2018 at 1:39 AM Richard Biener
> <richard.guenther@gmail.com> wrote:
> >
> > On Fri, Dec 14, 2018 at 11:48 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > On Fri, Dec 14, 2018 at 2:10 PM Jason Merrill <jason@redhat.com> wrote:
> > > >
> > > > On 12/13/18 6:56 PM, H.J. Lu wrote:
> > > > > On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
> > > > >>
> > > > >> On 9/25/18 11:46 AM, H.J. Lu wrote:
> > > > >>> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> > > > >>>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
> > > > >>>>>
> > > > >>>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> > > > >>>>> wrote:
> > > > >>>>>>
> > > > >>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > > > >>>>>>
> > > > >>>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> > > > >>>>>>> wrote:
> > > > >>>>>>>>
> > > > >>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
> > > > >>>>>>>>
> > > > >>>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
> > > > >>>>>>>>>> +    {
> > > > >>>>>>>>>> +      /* Check the THEN path first.  */
> > > > >>>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
> > > > >>>>>>>>>> +      context = check_address_of_packed_member (type, op1);
> > > > >>>>>>>>>
> > > > >>>>>>>>>
> > > > >>>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
> > > > >>>>>>>>> 1 is omitted.
> > > > >>>>>>>>
> > > > >>>>>>>>
> > > > >>>>>>>> Doesn't that just use a SAVE_EXPR?
> > > > >>>>>>>
> > > > >>>>>>>
> > > > >>>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
> > > > >>>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> > > > >>>>>>
> > > > >>>>>>
> > > > >>>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> > > > >>>>>> is produced directly.
> > > > >>>>>
> > > > >>>>>
> > > > >>>>> Here is the updated patch.  Changes from the last one:
> > > > >>>>>
> > > > >>>>> 1. Handle COMPOUND_EXPR.
> > > > >>>>> 2. Fixed typos in comments.
> > > > >>>>> 3. Combined warn_for_pointer_of_packed_member and
> > > > >>>>> warn_for_address_of_packed_member into
> > > > >>>>> warn_for_address_or_pointer_of_packed_member.
> > > > >>>>
> > > > >>>>
> > > > >>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> > > > >>>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> > > > >>>>
> > > > >>>>
> > > > >>>> I think this would read better as
> > > > >>>>
> > > > >>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> > > > >>>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
> > > > >>>> [-Waddress-of-packed-member]
> > > > >>>
> > > > >>> Fixed.
> > > > >>>
> > > > >>>>> +      while (TREE_CODE (base) == ARRAY_REF)
> > > > >>>>> +       base = TREE_OPERAND (base, 0);
> > > > >>>>> +      if (TREE_CODE (base) != COMPONENT_REF)
> > > > >>>>> +       return NULL_TREE;
> > > > >>>>
> > > > >>>>
> > > > >>>> Are you deliberately not handling the other handled_component_p cases? If
> > > > >>>> so, there should be a comment.
> > > > >>>
> > > > >>> I changed it to
> > > > >>>
> > > > >>>        while (handled_component_p (base))
> > > > >>>           {
> > > > >>>             enum tree_code code = TREE_CODE (base);
> > > > >>>             if (code == COMPONENT_REF)
> > > > >>>               break;
> > > > >>>             switch (code)
> > > > >>>               {
> > > > >>>               case ARRAY_REF:
> > > > >>>                 base = TREE_OPERAND (base, 0);
> > > > >>>                 break;
> > > > >>>               default:
> > > > >>>                 /* FIXME: Can it ever happen?  */
> > > > >>>                 gcc_unreachable ();
> > > > >>>                 break;
> > > > >>>               }
> > > > >>>           }
> > > > >>>
> > > > >>> Is there a testcase to trigger this ICE? I couldn't find one.
> > > > >>
> > > > >> You can take the address of an element of complex:
> > > > >>
> > > > >>     __complex int i;
> > > > >>     int *p = &__real(i);
> > > > >>
> > > > >> You may get VIEW_CONVERT_EXPR with location wrappers.
> > > > >
> > > > > Fixed.  I replaced gcc_unreachable with return NULL_TREE;
> > > >
> > > > Then we're back to my earlier question: are you deliberately not
> > > > handling the other cases?  Why not look through them as well?  What if
> > > > e.g. the operand of __real is a packed field?
> > > >
> > >
> > > Here is the updated patch with
> > >
> > > diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> > > index 615134cfdac..f105742598e 100644
> > > --- a/gcc/c-family/c-warn.c
> > > +++ b/gcc/c-family/c-warn.c
> > > @@ -2669,6 +2669,9 @@ check_address_of_packed_member (tree type, tree rhs)
> > >     switch (code)
> > >       {
> > >       case ARRAY_REF:
> > > +     case REALPART_EXPR:
> > > +     case IMAGPART_EXPR:
> > > +     case VIEW_CONVERT_EXPR:
> > >         base = TREE_OPERAND (base, 0);
> > >         break;
> > >       default:
> >
> > don't we have handled_component_p () for this?  (you're still
> > missing BIT_FIELD_REF which might be used for vector
> > element accesses)
> >
>
> Do you have a testcase?

No, I suspect it might need some folding to trigger (IIRC I made the FEs
use ARRAY_REFs but I'm not sure whether fully, esp. in the case of
address-taking).  My attempt:

typedef int v4si __attribute__((vector_size(16)));
struct X
{
  v4si x;
} __attribute__((packed)) x;

int *foo()
{
  return &x.x[1];
}

that shows

 return &VIEW_CONVERT_EXPR<int[4]>(x.x)[1];

for both C and C++ (albeit checked GCC 8 here).

Richard.

> --
> H.J.

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

* Re: V6 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-17 12:43           ` H.J. Lu
  2018-12-17 13:34             ` Richard Biener
@ 2018-12-17 13:53             ` Jason Merrill
  2018-12-18 14:11               ` V7 " H.J. Lu
  1 sibling, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-17 13:53 UTC (permalink / raw)
  To: H.J. Lu, Richard Guenther; +Cc: Joseph S. Myers, Martin Sebor, GCC Patches

On 12/17/18 7:42 AM, H.J. Lu wrote:
> On Mon, Dec 17, 2018 at 1:39 AM Richard Biener
> <richard.guenther@gmail.com> wrote:
>>
>> On Fri, Dec 14, 2018 at 11:48 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>>>
>>> On Fri, Dec 14, 2018 at 2:10 PM Jason Merrill <jason@redhat.com> wrote:
>>>>
>>>> On 12/13/18 6:56 PM, H.J. Lu wrote:
>>>>> On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
>>>>>>
>>>>>> On 9/25/18 11:46 AM, H.J. Lu wrote:
>>>>>>> On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
>>>>>>>> On 07/23/2018 05:24 PM, H.J. Lu wrote:
>>>>>>>>>
>>>>>>>>> On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>>>>>>>
>>>>>>>>>>> On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On Mon, 18 Jun 2018, Jason Merrill wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>>> +  if (TREE_CODE (rhs) == COND_EXPR)
>>>>>>>>>>>>>> +    {
>>>>>>>>>>>>>> +      /* Check the THEN path first.  */
>>>>>>>>>>>>>> +      tree op1 = TREE_OPERAND (rhs, 1);
>>>>>>>>>>>>>> +      context = check_address_of_packed_member (type, op1);
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> This should handle the GNU extension of re-using operand 0 if operand
>>>>>>>>>>>>> 1 is omitted.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Doesn't that just use a SAVE_EXPR?
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Hmm, I suppose it does, but many places in the compiler seem to expect
>>>>>>>>>>> that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
>>>>>>>>>> is produced directly.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Here is the updated patch.  Changes from the last one:
>>>>>>>>>
>>>>>>>>> 1. Handle COMPOUND_EXPR.
>>>>>>>>> 2. Fixed typos in comments.
>>>>>>>>> 3. Combined warn_for_pointer_of_packed_member and
>>>>>>>>> warn_for_address_of_packed_member into
>>>>>>>>> warn_for_address_or_pointer_of_packed_member.
>>>>>>>>
>>>>>>>>
>>>>>>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
>>>>>>>>> alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
>>>>>>>>
>>>>>>>>
>>>>>>>> I think this would read better as
>>>>>>>>
>>>>>>>> c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
>>>>>>>> ‘long int *’ (alignment 8) may result in an unaligned pointer value
>>>>>>>> [-Waddress-of-packed-member]
>>>>>>>
>>>>>>> Fixed.
>>>>>>>
>>>>>>>>> +      while (TREE_CODE (base) == ARRAY_REF)
>>>>>>>>> +       base = TREE_OPERAND (base, 0);
>>>>>>>>> +      if (TREE_CODE (base) != COMPONENT_REF)
>>>>>>>>> +       return NULL_TREE;
>>>>>>>>
>>>>>>>>
>>>>>>>> Are you deliberately not handling the other handled_component_p cases? If
>>>>>>>> so, there should be a comment.
>>>>>>>
>>>>>>> I changed it to
>>>>>>>
>>>>>>>         while (handled_component_p (base))
>>>>>>>            {
>>>>>>>              enum tree_code code = TREE_CODE (base);
>>>>>>>              if (code == COMPONENT_REF)
>>>>>>>                break;
>>>>>>>              switch (code)
>>>>>>>                {
>>>>>>>                case ARRAY_REF:
>>>>>>>                  base = TREE_OPERAND (base, 0);
>>>>>>>                  break;
>>>>>>>                default:
>>>>>>>                  /* FIXME: Can it ever happen?  */
>>>>>>>                  gcc_unreachable ();
>>>>>>>                  break;
>>>>>>>                }
>>>>>>>            }
>>>>>>>
>>>>>>> Is there a testcase to trigger this ICE? I couldn't find one.
>>>>>>
>>>>>> You can take the address of an element of complex:
>>>>>>
>>>>>>      __complex int i;
>>>>>>      int *p = &__real(i);
>>>>>>
>>>>>> You may get VIEW_CONVERT_EXPR with location wrappers.
>>>>>
>>>>> Fixed.  I replaced gcc_unreachable with return NULL_TREE;
>>>>
>>>> Then we're back to my earlier question: are you deliberately not
>>>> handling the other cases?  Why not look through them as well?  What if
>>>> e.g. the operand of __real is a packed field?
>>>>
>>>
>>> Here is the updated patch with
>>>
>>> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
>>> index 615134cfdac..f105742598e 100644
>>> --- a/gcc/c-family/c-warn.c
>>> +++ b/gcc/c-family/c-warn.c
>>> @@ -2669,6 +2669,9 @@ check_address_of_packed_member (tree type, tree rhs)
>>>      switch (code)
>>>        {
>>>        case ARRAY_REF:
>>> +     case REALPART_EXPR:
>>> +     case IMAGPART_EXPR:
>>> +     case VIEW_CONVERT_EXPR:
>>>          base = TREE_OPERAND (base, 0);
>>>          break;
>>>        default:
>>
>> don't we have handled_component_p () for this?  (you're still
>> missing BIT_FIELD_REF which might be used for vector
>> element accesses)
>>
> 
> Do you have a testcase?

Is there a reason you only want to handle some component references and 
not others?  If not, checking handled_component_p is simpler and more 
future proof than enumerating specific codes.

Jason

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

* V7 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-17 13:53             ` Jason Merrill
@ 2018-12-18 14:11               ` H.J. Lu
  2018-12-18 20:36                 ` Jason Merrill
  0 siblings, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-12-18 14:11 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

On Mon, Dec 17, 2018 at 08:53:32AM -0500, Jason Merrill wrote:
> On 12/17/18 7:42 AM, H.J. Lu wrote:
> > On Mon, Dec 17, 2018 at 1:39 AM Richard Biener
> > <richard.guenther@gmail.com> wrote:
> > > 
> > > On Fri, Dec 14, 2018 at 11:48 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > > 
> > > > On Fri, Dec 14, 2018 at 2:10 PM Jason Merrill <jason@redhat.com> wrote:
> > > > > 
> > > > > On 12/13/18 6:56 PM, H.J. Lu wrote:
> > > > > > On Thu, Dec 13, 2018 at 12:50 PM Jason Merrill <jason@redhat.com> wrote:
> > > > > > > 
> > > > > > > On 9/25/18 11:46 AM, H.J. Lu wrote:
> > > > > > > > On Fri, Aug 31, 2018 at 2:04 PM, Jason Merrill <jason@redhat.com> wrote:
> > > > > > > > > On 07/23/2018 05:24 PM, H.J. Lu wrote:
> > > > > > > > > > 
> > > > > > > > > > On Mon, Jun 18, 2018 at 12:26 PM, Joseph Myers <joseph@codesourcery.com>
> > > > > > > > > > wrote:
> > > > > > > > > > > 
> > > > > > > > > > > On Mon, 18 Jun 2018, Jason Merrill wrote:
> > > > > > > > > > > 
> > > > > > > > > > > > On Mon, Jun 18, 2018 at 11:59 AM, Joseph Myers <joseph@codesourcery.com>
> > > > > > > > > > > > wrote:
> > > > > > > > > > > > > 
> > > > > > > > > > > > > On Mon, 18 Jun 2018, Jason Merrill wrote:
> > > > > > > > > > > > > 
> > > > > > > > > > > > > > > +  if (TREE_CODE (rhs) == COND_EXPR)
> > > > > > > > > > > > > > > +    {
> > > > > > > > > > > > > > > +      /* Check the THEN path first.  */
> > > > > > > > > > > > > > > +      tree op1 = TREE_OPERAND (rhs, 1);
> > > > > > > > > > > > > > > +      context = check_address_of_packed_member (type, op1);
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > This should handle the GNU extension of re-using operand 0 if operand
> > > > > > > > > > > > > > 1 is omitted.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Doesn't that just use a SAVE_EXPR?
> > > > > > > > > > > > 
> > > > > > > > > > > > 
> > > > > > > > > > > > Hmm, I suppose it does, but many places in the compiler seem to expect
> > > > > > > > > > > > that it produces a COND_EXPR with TREE_OPERAND 1 as NULL_TREE.
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > Maybe that's used somewhere inside the C++ front end.  For C a SAVE_EXPR
> > > > > > > > > > > is produced directly.
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > Here is the updated patch.  Changes from the last one:
> > > > > > > > > > 
> > > > > > > > > > 1. Handle COMPOUND_EXPR.
> > > > > > > > > > 2. Fixed typos in comments.
> > > > > > > > > > 3. Combined warn_for_pointer_of_packed_member and
> > > > > > > > > > warn_for_address_of_packed_member into
> > > > > > > > > > warn_for_address_or_pointer_of_packed_member.
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > > c.i:4:33: warning: converting a packed ‘struct C *’ pointer increases the
> > > > > > > > > > alignment of ‘long int *’ pointer from 1 to 8 [-Waddress-of-packed-member]
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > I think this would read better as
> > > > > > > > > 
> > > > > > > > > c.i:4:33: warning: converting a packed ‘struct C *’ pointer (alignment 1) to
> > > > > > > > > ‘long int *’ (alignment 8) may result in an unaligned pointer value
> > > > > > > > > [-Waddress-of-packed-member]
> > > > > > > > 
> > > > > > > > Fixed.
> > > > > > > > 
> > > > > > > > > > +      while (TREE_CODE (base) == ARRAY_REF)
> > > > > > > > > > +       base = TREE_OPERAND (base, 0);
> > > > > > > > > > +      if (TREE_CODE (base) != COMPONENT_REF)
> > > > > > > > > > +       return NULL_TREE;
> > > > > > > > > 
> > > > > > > > > 
> > > > > > > > > Are you deliberately not handling the other handled_component_p cases? If
> > > > > > > > > so, there should be a comment.
> > > > > > > > 
> > > > > > > > I changed it to
> > > > > > > > 
> > > > > > > >         while (handled_component_p (base))
> > > > > > > >            {
> > > > > > > >              enum tree_code code = TREE_CODE (base);
> > > > > > > >              if (code == COMPONENT_REF)
> > > > > > > >                break;
> > > > > > > >              switch (code)
> > > > > > > >                {
> > > > > > > >                case ARRAY_REF:
> > > > > > > >                  base = TREE_OPERAND (base, 0);
> > > > > > > >                  break;
> > > > > > > >                default:
> > > > > > > >                  /* FIXME: Can it ever happen?  */
> > > > > > > >                  gcc_unreachable ();
> > > > > > > >                  break;
> > > > > > > >                }
> > > > > > > >            }
> > > > > > > > 
> > > > > > > > Is there a testcase to trigger this ICE? I couldn't find one.
> > > > > > > 
> > > > > > > You can take the address of an element of complex:
> > > > > > > 
> > > > > > >      __complex int i;
> > > > > > >      int *p = &__real(i);
> > > > > > > 
> > > > > > > You may get VIEW_CONVERT_EXPR with location wrappers.
> > > > > > 
> > > > > > Fixed.  I replaced gcc_unreachable with return NULL_TREE;
> > > > > 
> > > > > Then we're back to my earlier question: are you deliberately not
> > > > > handling the other cases?  Why not look through them as well?  What if
> > > > > e.g. the operand of __real is a packed field?
> > > > > 
> > > > 
> > > > Here is the updated patch with
> > > > 
> > > > diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> > > > index 615134cfdac..f105742598e 100644
> > > > --- a/gcc/c-family/c-warn.c
> > > > +++ b/gcc/c-family/c-warn.c
> > > > @@ -2669,6 +2669,9 @@ check_address_of_packed_member (tree type, tree rhs)
> > > >      switch (code)
> > > >        {
> > > >        case ARRAY_REF:
> > > > +     case REALPART_EXPR:
> > > > +     case IMAGPART_EXPR:
> > > > +     case VIEW_CONVERT_EXPR:
> > > >          base = TREE_OPERAND (base, 0);
> > > >          break;
> > > >        default:
> > > 
> > > don't we have handled_component_p () for this?  (you're still
> > > missing BIT_FIELD_REF which might be used for vector
> > > element accesses)
> > > 
> > 
> > Do you have a testcase?
> 
> Is there a reason you only want to handle some component references and not
> others?  If not, checking handled_component_p is simpler and more future
> proof than enumerating specific codes.
> 

Here is the updated patch.  The difference from the last patch is

      while (handled_component_p (base))
        {
          if (TREE_CODE (base) == COMPONENT_REF)
            break;
          base = TREE_OPERAND (base, 0);
        }

OK for trunk?

H.J.
---
When address of packed member of struct or union is taken, it may result
in an unaligned pointer value.  This patch adds -Waddress-of-packed-member
to check alignment at pointer assignment and warn unaligned address as
well as unaligned pointer:

$ cat x.i
struct pair_t
{
  char c;
  int i;
} __attribute__ ((packed));

extern struct pair_t p;
int *addr = &p.i;
$ gcc -O2 -S x.i
x.i:8:13: warning: taking address of packed member of ‘struct pair_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
8 | int *addr = &p.i;
  |             ^

$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
$ gcc -O2 -S c.i -Wno-incompatible-pointer-types
c.i: In function ‘g8’:
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment 1) to ‘long int *’ (alignment 8) may may result in an unaligned pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
$

This warning is enabled by default.  Since read_encoded_value_with_base
in unwind-pe.h has

  union unaligned
    {
      void *ptr;
      unsigned u2 __attribute__ ((mode (HI)));
      unsigned u4 __attribute__ ((mode (SI)));
      unsigned u8 __attribute__ ((mode (DI)));
      signed s2 __attribute__ ((mode (HI)));
      signed s4 __attribute__ ((mode (SI)));
      signed s8 __attribute__ ((mode (DI)));
    } __attribute__((__packed__));
  _Unwind_Internal_Ptr result;

and GCC warns:

gcc/libgcc/unwind-pe.h:210:37: warning: taking address of packed member of 'union unaligned' may result in an unaligned pointer value [-Waddress-of-packed-member]
    result = (_Unwind_Internal_Ptr) u->ptr;
                                    ^
we need to add GCC pragma to ignore -Waddress-of-packed-member.

gcc/c/

	PR c/51628
	* doc/invoke.texi: Document -Wno-address-of-packed-member.

gcc/c-family/

	PR c/51628
	* c-common.h (warn_for_address_or_pointer_of_packed_member): New.
	* c-warn.c (check_alignment_of_packed_member): New function.
	(check_address_of_packed_member): Likewise.
	(check_and_warn_address_of_packed_member): Likewise.
	(warn_for_address_or_pointer_of_packed_member): Likewise.
	* c.opt: Add -Wno-address-of-packed-member.

gcc/c/

	PR c/51628
	* c-typeck.c (convert_for_assignment): Call
	warn_for_address_or_pointer_of_packed_member.

gcc/cp/

	PR c/51628
	* call.c (convert_for_arg_passing): Call
	warn_for_address_or_pointer_of_packed_member.
	* typeck.c (convert_for_assignment): Likewise.

gcc/testsuite/

	PR c/51628
	* c-c++-common/pr51628-1.c: New test.
	* c-c++-common/pr51628-2.c: Likewise.
	* c-c++-common/pr51628-3.c: Likewise.
	* c-c++-common/pr51628-4.c: Likewise.
	* c-c++-common/pr51628-5.c: Likewise.
	* c-c++-common/pr51628-6.c: Likewise.
	* c-c++-common/pr51628-7.c: Likewise.
	* c-c++-common/pr51628-8.c: Likewise.
	* c-c++-common/pr51628-9.c: Likewise.
	* c-c++-common/pr51628-10.c: Likewise.
	* c-c++-common/pr51628-11.c: Likewise.
	* c-c++-common/pr51628-12.c: Likewise.
	* c-c++-common/pr51628-13.c: Likewise.
	* c-c++-common/pr51628-14.c: Likewise.
	* c-c++-common/pr51628-15.c: Likewise.
	* c-c++-common/pr51628-26.c: Likewise.
	* c-c++-common/pr51628-27.c: Likewise.
	* c-c++-common/pr51628-28.c: Likewise.
	* c-c++-common/pr51628-29.c: Likewise.
	* c-c++-common/pr51628-30.c: Likewise.
	* c-c++-common/pr51628-31.c: Likewise.
	* gcc.dg/pr51628-17.c: Likewise.
	* gcc.dg/pr51628-18.c: Likewise.
	* gcc.dg/pr51628-19.c: Likewise.
	* gcc.dg/pr51628-20.c: Likewise.
	* gcc.dg/pr51628-21.c: Likewise.
	* gcc.dg/pr51628-22.c: Likewise.
	* gcc.dg/pr51628-23.c: Likewise.
	* gcc.dg/pr51628-24.c: Likewise.
	* gcc.dg/pr51628-25.c: Likewise.
	* c-c++-common/asan/misalign-1.c: Add
	-Wno-address-of-packed-member.
	* c-c++-common/asan/misalign-2.c: Likewise.
	* c-c++-common/ubsan/align-2.c: Likewise.
	* c-c++-common/ubsan/align-4.c: Likewise.
	* c-c++-common/ubsan/align-6.c: Likewise.
	* c-c++-common/ubsan/align-7.c: Likewise.
	* c-c++-common/ubsan/align-8.c: Likewise.
	* c-c++-common/ubsan/align-10.c: Likewise.
	* g++.dg/ubsan/align-2.C: Likewise.
	* gcc.target/i386/avx512bw-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu64-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu64-2.c: Likewise.

libgcc/

	* unwind-pe.h (read_encoded_value_with_base): Add GCC pragma
	to ignore -Waddress-of-packed-member.
---
 gcc/c-family/c-common.h                       |   1 +
 gcc/c-family/c-warn.c                         | 184 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  11 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |   8 +
 gcc/testsuite/c-c++-common/asan/misalign-1.c  |   2 +-
 gcc/testsuite/c-c++-common/asan/misalign-2.c  |   2 +-
 gcc/testsuite/c-c++-common/pr51628-1.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-10.c       |  24 +++
 gcc/testsuite/c-c++-common/pr51628-11.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-12.c       |  18 ++
 gcc/testsuite/c-c++-common/pr51628-13.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-14.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-15.c       |  14 ++
 gcc/testsuite/c-c++-common/pr51628-16.c       |  13 ++
 gcc/testsuite/c-c++-common/pr51628-2.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-26.c       |  33 ++++
 gcc/testsuite/c-c++-common/pr51628-27.c       |  12 ++
 gcc/testsuite/c-c++-common/pr51628-28.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-29.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-3.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-30.c       |  23 +++
 gcc/testsuite/c-c++-common/pr51628-31.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-4.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-5.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-6.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-7.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-8.c        |  36 ++++
 gcc/testsuite/c-c++-common/pr51628-9.c        |  36 ++++
 gcc/testsuite/c-c++-common/ubsan/align-10.c   |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-2.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-4.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-6.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-7.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-8.c    |   2 +-
 gcc/testsuite/g++.dg/ubsan/align-2.C          |   2 +-
 gcc/testsuite/gcc.dg/pr51628-17.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-18.c             |  23 +++
 gcc/testsuite/gcc.dg/pr51628-19.c             |  26 +++
 gcc/testsuite/gcc.dg/pr51628-20.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-21.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-22.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-23.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-24.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-25.c             |   9 +
 .../gcc.target/i386/avx512bw-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu32-2.c     |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu64-2.c     |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu32-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu64-2.c    |   2 +-
 libgcc/unwind-pe.h                            |   5 +
 54 files changed, 870 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-10.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-11.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-12.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-13.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-14.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-15.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-16.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-26.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-27.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-28.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-29.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-30.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-31.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-4.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-5.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-6.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-7.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-8.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-9.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-17.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-18.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-19.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-20.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-21.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-22.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-23.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-24.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-25.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343c0b3..eb0ad60940d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1282,6 +1282,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern bool warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_for_address_or_pointer_of_packed_member (bool, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 798ad1bcb39..ca28dd66918 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2616,3 +2616,187 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
 }
+
+/* Return struct or union type if the alignment of data memeber, FIELD,
+   is less than the alignment of TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_alignment_of_packed_member (tree type, tree field)
+{
+  /* Check alignment of the data member.  */
+  if (TREE_CODE (field) == FIELD_DECL
+      && (DECL_PACKED (field)
+	  || TYPE_PACKED (TREE_TYPE (field))))
+    {
+      /* Check the expected alignment against the field alignment.  */
+      unsigned int type_align = TYPE_ALIGN (type);
+      tree context = DECL_CONTEXT (field);
+      unsigned int record_align = TYPE_ALIGN (context);
+      if ((record_align % type_align) != 0)
+	return context;
+      tree field_off = byte_position (field);
+      if (!multiple_of_p (TREE_TYPE (field_off), field_off,
+			  size_int (type_align / BITS_PER_UNIT)))
+	return context;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return struct or union type if the right hand value, RHS, takes the
+   unaligned address of packed member of struct or union when assigning
+   to TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_address_of_packed_member (tree type, tree rhs)
+{
+  tree base;
+  tree object;
+  tree field;
+
+  if (INDIRECT_REF_P (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+
+  switch (TREE_CODE (rhs))
+    {
+    case ADDR_EXPR:
+      base = TREE_OPERAND (rhs, 0);
+      while (handled_component_p (base))
+	{
+	  if (TREE_CODE (base) == COMPONENT_REF)
+	    break;
+	  base = TREE_OPERAND (base, 0);
+	}
+      if (TREE_CODE (base) != COMPONENT_REF)
+	return NULL_TREE;
+      object = TREE_OPERAND (base, 0);
+      field = TREE_OPERAND (base, 1);
+      break;
+    case COMPONENT_REF:
+      object = TREE_OPERAND (rhs, 0);
+      field = TREE_OPERAND (rhs, 1);
+      break;
+    default:
+      return NULL_TREE;
+    }
+
+  tree context = check_alignment_of_packed_member (type, field);
+  if (context)
+    return context;
+
+  /* Check alignment of the object.  */
+  while (TREE_CODE (object) == COMPONENT_REF)
+    {
+      field = TREE_OPERAND (object, 1);
+      context = check_alignment_of_packed_member (type, field);
+      if (context)
+	return context;
+      object = TREE_OPERAND (object, 0);
+    }
+
+  return NULL_TREE;
+}
+
+/* Check and warn if the right hand value, RHS, takes the unaligned
+   address of packed member of struct or union when assigning to TYPE.  */
+
+static void
+check_and_warn_address_of_packed_member (tree type, tree rhs)
+{
+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      tree context = check_address_of_packed_member (type, rhs);
+      if (context)
+	{
+	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
+	  warning_at (loc, OPT_Waddress_of_packed_member,
+		      "taking address of packed member of %qT may result "
+		      "in an unaligned pointer value",
+		      context);
+	}
+      return;
+    }
+
+  /* Check the THEN path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
+
+  /* Check the ELSE path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
+}
+
+/* Warn if the right hand value, RHS:
+   1. For CONVERT_P == true, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+   2. For CONVERT_P == false, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool convert_p, tree type,
+					      tree rhs)
+{
+  if (!warn_address_of_packed_member)
+    return;
+
+  /* Don't warn if we don't assign RHS to a pointer.  */
+  if (!POINTER_TYPE_P (type))
+    return;
+
+  while (TREE_CODE (rhs) == COMPOUND_EXPR)
+    rhs = TREE_OPERAND (rhs, 1);
+
+  if (convert_p)
+    {
+      bool rhspointer_p;
+      tree rhstype;
+
+      /* Check the original type of RHS.  */
+      switch (TREE_CODE (rhs))
+	{
+	case PARM_DECL:
+	case VAR_DECL:
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = POINTER_TYPE_P (rhstype);
+	  break;
+	case NOP_EXPR:
+	  rhs = TREE_OPERAND (rhs, 0);
+	  if (TREE_CODE (rhs) == ADDR_EXPR)
+	    rhs = TREE_OPERAND (rhs, 0);
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
+	  break;
+	default:
+	  return;
+	}
+
+      if (rhspointer_p && TYPE_PACKED (TREE_TYPE (rhstype)))
+	{
+	  unsigned int type_align = TYPE_ALIGN_UNIT (TREE_TYPE (type));
+	  unsigned int rhs_align = TYPE_ALIGN_UNIT (TREE_TYPE (rhstype));
+	  if ((rhs_align % type_align) != 0)
+	    {
+	      location_t location = EXPR_LOC_OR_LOC (rhs, input_location);
+	      warning_at (location, OPT_Waddress_of_packed_member,
+			  "converting a packed %qT pointer (alignment %d) "
+			  "to %qT (alignment %d) may may result in an "
+			  "unaligned pointer value",
+			  rhstype, rhs_align, type, type_align);
+	      tree decl = TYPE_STUB_DECL (TREE_TYPE (rhstype));
+	      inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	      decl = TYPE_STUB_DECL (TREE_TYPE (type));
+	      if (decl)
+		inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	    }
+	}
+    }
+  else
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+
+      check_and_warn_address_of_packed_member (type, rhs);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 07ff1c84f96..22ccf910a85 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -625,6 +625,10 @@ Wincompatible-pointer-types
 C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning
 Warn when there is a conversion between pointers that have incompatible types.
 
+Waddress-of-packed-member
+C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning
+Warn when the address of packed member of struct or union is taken.
+
 Winit-self
 C ObjC C++ ObjC++ Var(warn_init_self) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about variables which are initialized to themselves.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1a897273088..da4a8169d56 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6724,7 +6724,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    return rhs;
+    {
+      warn_for_address_or_pointer_of_packed_member (false, type,
+						    orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7279,6 +7283,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	    }
 	}
 
+      /* If RHS is't an address, check pointer or array of packed
+	 struct or union.  */
+      warn_for_address_or_pointer_of_packed_member
+	(TREE_CODE (orig_rhs) != ADDR_EXPR, type, orig_rhs);
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36b604..40ffc863091 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7618,6 +7618,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	}
       maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
     }
+
+  warn_for_address_or_pointer_of_packed_member (false, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 47ddad16fc1..70b60a928f4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9036,6 +9036,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (false, type, rhs);
+
   return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
 					    complain, flags);
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ac2ee59d92c..47f2fc3f518 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -358,6 +358,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
 -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
 -Wwrite-strings @gol
+-Waddress-of-packed-member @gol
 -Wzero-as-null-pointer-constant  -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -6981,6 +6982,13 @@ behavior and are not portable in C, so they usually indicate that the
 programmer intended to use @code{strcmp}.  This warning is enabled by
 @option{-Wall}.
 
+@item -Waddress-of-packed-member
+@opindex Waddress-of-packed-member
+@opindex Wno-address-of-packed-member
+Warn when the address of packed member of struct or union is taken,
+which usually results in an unaligned pointer value.  This is
+enabled by default.
+
 @item -Wlogical-op
 @opindex Wlogical-op
 @opindex Wno-logical-op
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-1.c b/gcc/testsuite/c-c++-common/asan/misalign-1.c
index 5cd605ac045..ebeb0306706 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-1.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-2.c b/gcc/testsuite/c-c++-common/asan/misalign-2.c
index a6ed49bac05..b27e22d35a8 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-2.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/pr51628-1.c b/gcc/testsuite/c-c++-common/pr51628-1.c
new file mode 100644
index 00000000000..5324f9cc964
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-1.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-10.c b/gcc/testsuite/c-c++-common/pr51628-10.c
new file mode 100644
index 00000000000..085fe1608c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-10.c
@@ -0,0 +1,24 @@
+/* PR c/51628.  */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+struct pair_t
+{
+  char c;
+  __int128_t i;
+} __attribute__ ((packed));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__((packed)) unaligned_int128_t;
+
+struct pair_t p = {0, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *) &p.i;
+
+int 
+main() 
+{
+  addr->value = ~(__int128_t)0;
+  return (p.i != 1) ? 0 : 1;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-11.c b/gcc/testsuite/c-c++-common/pr51628-11.c
new file mode 100644
index 00000000000..7661232ac88
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-11.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[12];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
diff --git a/gcc/testsuite/c-c++-common/pr51628-12.c b/gcc/testsuite/c-c++-common/pr51628-12.c
new file mode 100644
index 00000000000..bc221fa87ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-12.c
@@ -0,0 +1,18 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[10];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-13.c b/gcc/testsuite/c-c++-common/pr51628-13.c
new file mode 100644
index 00000000000..0edd5e7f84d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-13.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* h4 (struct C *p) { return &p->b.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-14.c b/gcc/testsuite/c-c++-common/pr51628-14.c
new file mode 100644
index 00000000000..f50378b8651
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-14.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+void* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/c-c++-common/pr51628-15.c b/gcc/testsuite/c-c++-common/pr51628-15.c
new file mode 100644
index 00000000000..bcac6d70ad5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-15.c
@@ -0,0 +1,14 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+int*
+f (struct A *p, int *q)
+{
+  return q ? q : &p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-16.c b/gcc/testsuite/c-c++-common/pr51628-16.c
new file mode 100644
index 00000000000..cd502fe76b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-16.c
@@ -0,0 +1,13 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct __attribute__ ((packed)) A { int i; };
+struct B {
+  struct A a;
+} b;
+
+int *p = (int*)&b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+int *q = (int*)&b.a;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-2.c b/gcc/testsuite/c-c++-common/pr51628-2.c
new file mode 100644
index 00000000000..abfb84ddd05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-2.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (8)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-26.c b/gcc/testsuite/c-c++-common/pr51628-26.c
new file mode 100644
index 00000000000..2042379860a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-26.c
@@ -0,0 +1,33 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+struct A p = {1};
+int *addr;
+
+int i, j;
+
+void
+foo1 (void)
+{
+  addr = (i = -1, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo2 (void)
+{
+  addr = (i = -1, j = -2, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo3 (void)
+{
+  addr = (i = -1, (j = -2, &p.i));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-27.c b/gcc/testsuite/c-c++-common/pr51628-27.c
new file mode 100644
index 00000000000..9ae1efd7afb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-27.c
@@ -0,0 +1,12 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; } __attribute__ ((packed));
+struct B { struct A a; };
+struct C { struct B b; };
+
+extern struct C *p;
+
+int* g8 (void) { return &p->b.a.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-28.c b/gcc/testsuite/c-c++-common/pr51628-28.c
new file mode 100644
index 00000000000..e8c752d0b12
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-28.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { 
+  int i;
+} __attribute__ ((packed));
+
+int *
+foo3 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 
+	  ? &p1->i
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? &p2->i : q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-29.c b/gcc/testsuite/c-c++-common/pr51628-29.c
new file mode 100644
index 00000000000..94b3722d2c8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-29.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+g8 (void)
+{
+  return &p->b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-3.c b/gcc/testsuite/c-c++-common/pr51628-3.c
new file mode 100644
index 00000000000..0ea94c845a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-3.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (2)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-30.c b/gcc/testsuite/c-c++-common/pr51628-30.c
new file mode 100644
index 00000000000..578edf4e8f9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-30.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { __complex int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+foo1 (void)
+{
+  return &__real(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo2 (void)
+{
+  return &__imag(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-31.c b/gcc/testsuite/c-c++-common/pr51628-31.c
new file mode 100644
index 00000000000..9730f53f582
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-31.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+struct X
+{
+  v4si x;
+} __attribute__((packed)) x;
+
+int *
+foo()
+{
+  return &x.x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-4.c b/gcc/testsuite/c-c++-common/pr51628-4.c
new file mode 100644
index 00000000000..c4c1fb72d6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-4.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-5.c b/gcc/testsuite/c-c++-common/pr51628-5.c
new file mode 100644
index 00000000000..9d7c309a0ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-5.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-6.c b/gcc/testsuite/c-c++-common/pr51628-6.c
new file mode 100644
index 00000000000..52aa07a4cf3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-6.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-7.c b/gcc/testsuite/c-c++-common/pr51628-7.c
new file mode 100644
index 00000000000..ae4a681f966
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-7.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+  bar (p0);
+  p1 = &p->i[1];
+  bar (p1);
+  bar (p->i);
+  bar (&p->i[2]);
+  x = p->i;
+  return &p->i[3];
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-8.c b/gcc/testsuite/c-c++-common/pr51628-8.c
new file mode 100644
index 00000000000..cc2dae096ae
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-8.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i[4];
+} __attribute__ ((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-9.c b/gcc/testsuite/c-c++-common/pr51628-9.c
new file mode 100644
index 00000000000..0470aa3b93d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-9.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__ ((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-10.c b/gcc/testsuite/c-c++-common/ubsan/align-10.c
index 56ae9ebfe30..6210533173c 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-10.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct R { int a; } r;
 struct S { struct R a; char b; long long c; short d[10]; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-2.c b/gcc/testsuite/c-c++-common/ubsan/align-2.c
index 071de8c202a..336b1c3c907 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-2.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=alignment" } */
+/* { dg-options "-fsanitize=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-4.c b/gcc/testsuite/c-c++-common/ubsan/align-4.c
index 3252595d330..d5feeee29c6 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-4.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=null,alignment" } */
+/* { dg-options "-fsanitize=null,alignment -Wno-address-of-packed-member" } */
 
 #include "align-2.c"
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-6.c b/gcc/testsuite/c-c++-common/ubsan/align-6.c
index 3364746fb27..0302b7b8894 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-6.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-7.c b/gcc/testsuite/c-c++-common/ubsan/align-7.c
index ec4e87f56d5..dd1e8c91cef 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-7.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-7.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-8.c b/gcc/testsuite/c-c++-common/ubsan/align-8.c
index 61c1ceb6682..5fe0e0fe931 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-8.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/g++.dg/ubsan/align-2.C b/gcc/testsuite/g++.dg/ubsan/align-2.C
index 3e4f5485d02..c97ede88392 100644
--- a/gcc/testsuite/g++.dg/ubsan/align-2.C
+++ b/gcc/testsuite/g++.dg/ubsan/align-2.C
@@ -1,6 +1,6 @@
 // Limit this to known non-strict alignment targets.
 // { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
-// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -Wno-address-of-packed-member -std=c++11" }
 
 typedef const long int L;
 struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
diff --git a/gcc/testsuite/gcc.dg/pr51628-17.c b/gcc/testsuite/gcc.dg/pr51628-17.c
new file mode 100644
index 00000000000..0be95b2294e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-17.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+long* f8 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-18.c b/gcc/testsuite/gcc.dg/pr51628-18.c
new file mode 100644
index 00000000000..03a04eff75c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-18.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    int c[k];
+    int x[n];
+  } __attribute__ ((packed, aligned (4)));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+  foo (p0);
+  p1 = &p->x[1];
+  foo (p1);
+  return &p->x[1];
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-19.c b/gcc/testsuite/gcc.dg/pr51628-19.c
new file mode 100644
index 00000000000..7ff03e85cea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-19.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    char c[k];
+    int x[n];
+  } __attribute__ ((packed));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p0);
+  p1 = &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p1);
+  return &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-20.c b/gcc/testsuite/gcc.dg/pr51628-20.c
new file mode 100644
index 00000000000..80888283b73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-20.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C *p;
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-21.c b/gcc/testsuite/gcc.dg/pr51628-21.c
new file mode 100644
index 00000000000..3077e72c8d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-21.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C p[];
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-22.c b/gcc/testsuite/gcc.dg/pr51628-22.c
new file mode 100644
index 00000000000..1bd5d791639
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-22.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* g4 (struct C *p) { return &p->b; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-23.c b/gcc/testsuite/gcc.dg/pr51628-23.c
new file mode 100644
index 00000000000..5709be60ac8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-23.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+char* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/gcc.dg/pr51628-24.c b/gcc/testsuite/gcc.dg/pr51628-24.c
new file mode 100644
index 00000000000..3ad99cd2f16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-24.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+short* f2 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-25.c b/gcc/testsuite/gcc.dg/pr51628-25.c
new file mode 100644
index 00000000000..2fc5c028711
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-25.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+long* g8 (struct C *p) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
index a61609c40d2..c6e3ebdc507 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw" } */
+/* { dg-options "-O2 -mavx512bw -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512bw } */
 
 #define AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
index f2edc3dff7b..95a657fc5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
index 14176965ace..954b091d976 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
index 45ae83d4552..81465f8d9a0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 /* { dg-require-effective-target avx512bw } */
 
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
index 4b928d0cd42..19390664bd0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
index 1863ed3616f..aea0c12a5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index dd5ae95fc2c..05c2fb4dd50 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -177,6 +177,9 @@ read_sleb128 (const unsigned char *p, _sleb128_t *val)
    The function returns P incremented past the value.  BASE is as given
    by base_of_encoded_value for this encoding in the appropriate context.  */
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 static const unsigned char *
 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
 			      const unsigned char *p, _Unwind_Ptr *val)
@@ -270,6 +273,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
   return p;
 }
 
+#pragma GCC diagnostic pop
+
 #ifndef NO_BASE_OF_ENCODED_VALUE
 
 /* Like read_encoded_value_with_base, but get the base from the context
-- 
2.19.2

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

* Re: V7 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-18 14:11               ` V7 " H.J. Lu
@ 2018-12-18 20:36                 ` Jason Merrill
  2018-12-18 21:13                   ` V8 " H.J. Lu
  0 siblings, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-18 20:36 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

On 12/18/18 9:10 AM, H.J. Lu wrote:
> +  switch (TREE_CODE (rhs))
> +    {
> +    case ADDR_EXPR:
> +      base = TREE_OPERAND (rhs, 0);
> +      while (handled_component_p (base))
> +	{
> +	  if (TREE_CODE (base) == COMPONENT_REF)
> +	    break;
> +	  base = TREE_OPERAND (base, 0);
> +	}
> +      if (TREE_CODE (base) != COMPONENT_REF)
> +	return NULL_TREE;
> +      object = TREE_OPERAND (base, 0);
> +      field = TREE_OPERAND (base, 1);
> +      break;
> +    case COMPONENT_REF:
> +      object = TREE_OPERAND (rhs, 0);
> +      field = TREE_OPERAND (rhs, 1);
> +      break;
> +    default:
> +      return NULL_TREE;
> +    }
> +
> +  tree context = check_alignment_of_packed_member (type, field);
> +  if (context)
> +    return context;
> +
> +  /* Check alignment of the object.  */
> +  while (TREE_CODE (object) == COMPONENT_REF)
> +    {
> +      field = TREE_OPERAND (object, 1);
> +      context = check_alignment_of_packed_member (type, field);
> +      if (context)
> +	return context;
> +      object = TREE_OPERAND (object, 0);
> +    }
> +

You can see interleaved COMPONENT_REF and ARRAY_REF that this still 
doesn't look like it will handle, something like

struct A
{
   int i;
};

struct B
{
   char c;
   __attribute ((packed)) A ar[4];
};

B b;

int *p = &b.ar[1].i;

Rather than have a loop in the ADDR_EXPR case of the switch, you can 
handle everything in the lower loop.  And not have a switch at all, just 
strip any ADDR_EXPR before the loop.

> +check_and_warn_address_of_packed_member (tree type, tree rhs)
> +{
> +  if (TREE_CODE (rhs) != COND_EXPR)
> +    {
> +      tree context = check_address_of_packed_member (type, rhs);
> +      if (context)
> +	{
> +	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
> +	  warning_at (loc, OPT_Waddress_of_packed_member,
> +		      "taking address of packed member of %qT may result "
> +		      "in an unaligned pointer value",
> +		      context);
> +	}
> +      return;
> +    }
> +
> +  /* Check the THEN path.  */
> +  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
> +
> +  /* Check the ELSE path.  */
> +  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
> +}

You probably also want to handle COMPOUND_EXPR.

Jason

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

* V8 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-18 20:36                 ` Jason Merrill
@ 2018-12-18 21:13                   ` H.J. Lu
  2018-12-18 22:14                     ` Jason Merrill
  2018-12-19  3:19                     ` V8 " Sandra Loosemore
  0 siblings, 2 replies; 23+ messages in thread
From: H.J. Lu @ 2018-12-18 21:13 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

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

On Tue, Dec 18, 2018 at 12:36 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 12/18/18 9:10 AM, H.J. Lu wrote:
> > +  switch (TREE_CODE (rhs))
> > +    {
> > +    case ADDR_EXPR:
> > +      base = TREE_OPERAND (rhs, 0);
> > +      while (handled_component_p (base))
> > +     {
> > +       if (TREE_CODE (base) == COMPONENT_REF)
> > +         break;
> > +       base = TREE_OPERAND (base, 0);
> > +     }
> > +      if (TREE_CODE (base) != COMPONENT_REF)
> > +     return NULL_TREE;
> > +      object = TREE_OPERAND (base, 0);
> > +      field = TREE_OPERAND (base, 1);
> > +      break;
> > +    case COMPONENT_REF:
> > +      object = TREE_OPERAND (rhs, 0);
> > +      field = TREE_OPERAND (rhs, 1);
> > +      break;
> > +    default:
> > +      return NULL_TREE;
> > +    }
> > +
> > +  tree context = check_alignment_of_packed_member (type, field);
> > +  if (context)
> > +    return context;
> > +
> > +  /* Check alignment of the object.  */
> > +  while (TREE_CODE (object) == COMPONENT_REF)
> > +    {
> > +      field = TREE_OPERAND (object, 1);
> > +      context = check_alignment_of_packed_member (type, field);
> > +      if (context)
> > +     return context;
> > +      object = TREE_OPERAND (object, 0);
> > +    }
> > +
>
> You can see interleaved COMPONENT_REF and ARRAY_REF that this still
> doesn't look like it will handle, something like
>
> struct A
> {
>    int i;
> };
>
> struct B
> {
>    char c;
>    __attribute ((packed)) A ar[4];
> };
>
> B b;
>
> int *p = &b.ar[1].i;
>
> Rather than have a loop in the ADDR_EXPR case of the switch, you can
> handle everything in the lower loop.  And not have a switch at all, just
> strip any ADDR_EXPR before the loop.

I changed it to

 if (TREE_CODE (rhs) == ADDR_EXPR)
    rhs = TREE_OPERAND (rhs, 0);
  while (handled_component_p (rhs))
    {
      if (TREE_CODE (rhs) == COMPONENT_REF)
        break;
      rhs = TREE_OPERAND (rhs, 0);
    }

  if (TREE_CODE (rhs) != COMPONENT_REF)
    return NULL_TREE;

  object = TREE_OPERAND (rhs, 0);
  field = TREE_OPERAND (rhs, 1);

[hjl@gnu-cfl-1 pr51628-6]$ cat a.i
struct A
{
   int i;
} __attribute ((packed));

struct B
{
   char c;
   struct A ar[4];
};

struct B b;

int *p = &b.ar[1].i;
[hjl@gnu-cfl-1 pr51628-6]$ make a.s
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S a.i
a.i:14:10: warning: taking address of packed member of ‘struct A’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
   14 | int *p = &b.ar[1].i;
      |          ^~~~~~~~~~
[hjl@gnu-cfl-1 pr51628-6]$

> > +check_and_warn_address_of_packed_member (tree type, tree rhs)
> > +{
> > +  if (TREE_CODE (rhs) != COND_EXPR)
> > +    {
> > +      tree context = check_address_of_packed_member (type, rhs);
> > +      if (context)
> > +     {
> > +       location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
> > +       warning_at (loc, OPT_Waddress_of_packed_member,
> > +                   "taking address of packed member of %qT may result "
> > +                   "in an unaligned pointer value",
> > +                   context);
> > +     }
> > +      return;
> > +    }
> > +
> > +  /* Check the THEN path.  */
> > +  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
> > +
> > +  /* Check the ELSE path.  */
> > +  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
> > +}
>
> You probably also want to handle COMPOUND_EXPR.
>

Done.

[hjl@gnu-cfl-1 pr51628-5]$ cat c.i
struct A {
  int i;
} __attribute__ ((packed));

int*
foo3 (struct A *p1, int *q1, int *q2, struct A *p2)
{
  return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q2 = 2, &p2->i): q2);
}
[hjl@gnu-cfl-1 pr51628-5]$
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S c.i
c.i: In function ‘foo3’:
c.i:8:25: warning: taking address of packed member of ‘struct A’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
    8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q2 = 2, &p2->i): q2);
      |                         ^~~~~~
c.i:8:51: warning: taking address of packed member of ‘struct A’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
    8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q2 = 2, &p2->i): q2);
      |                                                   ^~~~~~
[hjl@gnu-cfl-1 pr51628-5]$

Here is the updated patch.  OK for trunk?

Thanks.


-- 
H.J.

[-- Attachment #2: 0001-C-C-Add-Waddress-of-packed-member.patch --]
[-- Type: text/x-patch, Size: 51900 bytes --]

From 22e60a16ca5fd9c591e6b44c0245cc51f12d5b6c Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 12 Jan 2018 21:12:05 -0800
Subject: [PATCH] C/C++: Add -Waddress-of-packed-member
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When address of packed member of struct or union is taken, it may result
in an unaligned pointer value.  This patch adds -Waddress-of-packed-member
to check alignment at pointer assignment and warn unaligned address as
well as unaligned pointer:

$ cat x.i
struct pair_t
{
  char c;
  int i;
} __attribute__ ((packed));

extern struct pair_t p;
int *addr = &p.i;
$ gcc -O2 -S x.i
x.i:8:13: warning: taking address of packed member of ‘struct pair_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
8 | int *addr = &p.i;
  |             ^

$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
$ gcc -O2 -S c.i -Wno-incompatible-pointer-types
c.i: In function ‘g8’:
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment 1) to ‘long int *’ (alignment 8) may may result in an unaligned pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
$

This warning is enabled by default.  Since read_encoded_value_with_base
in unwind-pe.h has

  union unaligned
    {
      void *ptr;
      unsigned u2 __attribute__ ((mode (HI)));
      unsigned u4 __attribute__ ((mode (SI)));
      unsigned u8 __attribute__ ((mode (DI)));
      signed s2 __attribute__ ((mode (HI)));
      signed s4 __attribute__ ((mode (SI)));
      signed s8 __attribute__ ((mode (DI)));
    } __attribute__((__packed__));
  _Unwind_Internal_Ptr result;

and GCC warns:

gcc/libgcc/unwind-pe.h:210:37: warning: taking address of packed member of 'union unaligned' may result in an unaligned pointer value [-Waddress-of-packed-member]
    result = (_Unwind_Internal_Ptr) u->ptr;
                                    ^
we need to add GCC pragma to ignore -Waddress-of-packed-member.

gcc/c/

	PR c/51628
	* doc/invoke.texi: Document -Wno-address-of-packed-member.

gcc/c-family/

	PR c/51628
	* c-common.h (warn_for_address_or_pointer_of_packed_member): New.
	* c-warn.c (check_alignment_of_packed_member): New function.
	(check_address_of_packed_member): Likewise.
	(check_and_warn_address_of_packed_member): Likewise.
	(warn_for_address_or_pointer_of_packed_member): Likewise.
	* c.opt: Add -Wno-address-of-packed-member.

gcc/c/

	PR c/51628
	* c-typeck.c (convert_for_assignment): Call
	warn_for_address_or_pointer_of_packed_member.

gcc/cp/

	PR c/51628
	* call.c (convert_for_arg_passing): Call
	warn_for_address_or_pointer_of_packed_member.
	* typeck.c (convert_for_assignment): Likewise.

gcc/testsuite/

	PR c/51628
	* c-c++-common/pr51628-1.c: New test.
	* c-c++-common/pr51628-2.c: Likewise.
	* c-c++-common/pr51628-3.c: Likewise.
	* c-c++-common/pr51628-4.c: Likewise.
	* c-c++-common/pr51628-5.c: Likewise.
	* c-c++-common/pr51628-6.c: Likewise.
	* c-c++-common/pr51628-7.c: Likewise.
	* c-c++-common/pr51628-8.c: Likewise.
	* c-c++-common/pr51628-9.c: Likewise.
	* c-c++-common/pr51628-10.c: Likewise.
	* c-c++-common/pr51628-11.c: Likewise.
	* c-c++-common/pr51628-12.c: Likewise.
	* c-c++-common/pr51628-13.c: Likewise.
	* c-c++-common/pr51628-14.c: Likewise.
	* c-c++-common/pr51628-15.c: Likewise.
	* c-c++-common/pr51628-26.c: Likewise.
	* c-c++-common/pr51628-27.c: Likewise.
	* c-c++-common/pr51628-28.c: Likewise.
	* c-c++-common/pr51628-29.c: Likewise.
	* c-c++-common/pr51628-30.c: Likewise.
	* c-c++-common/pr51628-31.c: Likewise.
	* c-c++-common/pr51628-32.c: Likewise.
	* gcc.dg/pr51628-17.c: Likewise.
	* gcc.dg/pr51628-18.c: Likewise.
	* gcc.dg/pr51628-19.c: Likewise.
	* gcc.dg/pr51628-20.c: Likewise.
	* gcc.dg/pr51628-21.c: Likewise.
	* gcc.dg/pr51628-22.c: Likewise.
	* gcc.dg/pr51628-23.c: Likewise.
	* gcc.dg/pr51628-24.c: Likewise.
	* gcc.dg/pr51628-25.c: Likewise.
	* c-c++-common/asan/misalign-1.c: Add
	-Wno-address-of-packed-member.
	* c-c++-common/asan/misalign-2.c: Likewise.
	* c-c++-common/ubsan/align-2.c: Likewise.
	* c-c++-common/ubsan/align-4.c: Likewise.
	* c-c++-common/ubsan/align-6.c: Likewise.
	* c-c++-common/ubsan/align-7.c: Likewise.
	* c-c++-common/ubsan/align-8.c: Likewise.
	* c-c++-common/ubsan/align-10.c: Likewise.
	* g++.dg/ubsan/align-2.C: Likewise.
	* gcc.target/i386/avx512bw-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu64-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu64-2.c: Likewise.

libgcc/

	* unwind-pe.h (read_encoded_value_with_base): Add GCC pragma
	to ignore -Waddress-of-packed-member.
---
 gcc/c-family/c-common.h                       |   1 +
 gcc/c-family/c-warn.c                         | 178 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  11 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |   8 +
 gcc/testsuite/c-c++-common/asan/misalign-1.c  |   2 +-
 gcc/testsuite/c-c++-common/asan/misalign-2.c  |   2 +-
 gcc/testsuite/c-c++-common/pr51628-1.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-10.c       |  24 +++
 gcc/testsuite/c-c++-common/pr51628-11.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-12.c       |  18 ++
 gcc/testsuite/c-c++-common/pr51628-13.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-14.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-15.c       |  14 ++
 gcc/testsuite/c-c++-common/pr51628-16.c       |  13 ++
 gcc/testsuite/c-c++-common/pr51628-2.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-26.c       |  33 ++++
 gcc/testsuite/c-c++-common/pr51628-27.c       |  12 ++
 gcc/testsuite/c-c++-common/pr51628-28.c       |  26 +++
 gcc/testsuite/c-c++-common/pr51628-29.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-3.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-30.c       |  23 +++
 gcc/testsuite/c-c++-common/pr51628-31.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-32.c       |  19 ++
 gcc/testsuite/c-c++-common/pr51628-4.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-5.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-6.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-7.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-8.c        |  36 ++++
 gcc/testsuite/c-c++-common/pr51628-9.c        |  36 ++++
 gcc/testsuite/c-c++-common/ubsan/align-10.c   |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-2.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-4.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-6.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-7.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-8.c    |   2 +-
 gcc/testsuite/g++.dg/ubsan/align-2.C          |   2 +-
 gcc/testsuite/gcc.dg/pr51628-17.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-18.c             |  23 +++
 gcc/testsuite/gcc.dg/pr51628-19.c             |  26 +++
 gcc/testsuite/gcc.dg/pr51628-20.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-21.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-22.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-23.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-24.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-25.c             |   9 +
 .../gcc.target/i386/avx512bw-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu32-2.c     |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu64-2.c     |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu32-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu64-2.c    |   2 +-
 libgcc/unwind-pe.h                            |   5 +
 55 files changed, 892 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-10.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-11.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-12.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-13.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-14.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-15.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-16.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-26.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-27.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-28.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-29.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-30.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-31.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-32.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-4.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-5.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-6.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-7.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-8.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-9.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-17.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-18.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-19.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-20.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-21.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-22.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-23.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-24.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-25.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343c0b3..eb0ad60940d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1282,6 +1282,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern bool warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_for_address_or_pointer_of_packed_member (bool, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 798ad1bcb39..9b2895eddb5 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2616,3 +2616,181 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
 }
+
+/* Return struct or union type if the alignment of data memeber, FIELD,
+   is less than the alignment of TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_alignment_of_packed_member (tree type, tree field)
+{
+  /* Check alignment of the data member.  */
+  if (TREE_CODE (field) == FIELD_DECL
+      && (DECL_PACKED (field)
+	  || TYPE_PACKED (TREE_TYPE (field))))
+    {
+      /* Check the expected alignment against the field alignment.  */
+      unsigned int type_align = TYPE_ALIGN (type);
+      tree context = DECL_CONTEXT (field);
+      unsigned int record_align = TYPE_ALIGN (context);
+      if ((record_align % type_align) != 0)
+	return context;
+      tree field_off = byte_position (field);
+      if (!multiple_of_p (TREE_TYPE (field_off), field_off,
+			  size_int (type_align / BITS_PER_UNIT)))
+	return context;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return struct or union type if the right hand value, RHS, takes the
+   unaligned address of packed member of struct or union when assigning
+   to TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_address_of_packed_member (tree type, tree rhs)
+{
+  tree object;
+  tree field;
+
+  if (INDIRECT_REF_P (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+
+  if (TREE_CODE (rhs) == ADDR_EXPR)
+    rhs = TREE_OPERAND (rhs, 0);
+  while (handled_component_p (rhs))
+    {
+      if (TREE_CODE (rhs) == COMPONENT_REF)
+	break;
+      rhs = TREE_OPERAND (rhs, 0);
+    }
+
+  if (TREE_CODE (rhs) != COMPONENT_REF)
+    return NULL_TREE;
+
+  object = TREE_OPERAND (rhs, 0);
+  field = TREE_OPERAND (rhs, 1);
+
+  tree context = check_alignment_of_packed_member (type, field);
+  if (context)
+    return context;
+
+  /* Check alignment of the object.  */
+  while (TREE_CODE (object) == COMPONENT_REF)
+    {
+      field = TREE_OPERAND (object, 1);
+      context = check_alignment_of_packed_member (type, field);
+      if (context)
+	return context;
+      object = TREE_OPERAND (object, 0);
+    }
+
+  return NULL_TREE;
+}
+
+/* Check and warn if the right hand value, RHS, takes the unaligned
+   address of packed member of struct or union when assigning to TYPE.  */
+
+static void
+check_and_warn_address_of_packed_member (tree type, tree rhs)
+{
+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      while (TREE_CODE (rhs) == COMPOUND_EXPR)
+	rhs = TREE_OPERAND (rhs, 1);
+
+      tree context = check_address_of_packed_member (type, rhs);
+      if (context)
+	{
+	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
+	  warning_at (loc, OPT_Waddress_of_packed_member,
+		      "taking address of packed member of %qT may result "
+		      "in an unaligned pointer value",
+		      context);
+	}
+      return;
+    }
+
+  /* Check the THEN path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
+
+  /* Check the ELSE path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
+}
+
+/* Warn if the right hand value, RHS:
+   1. For CONVERT_P == true, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+   2. For CONVERT_P == false, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool convert_p, tree type,
+					      tree rhs)
+{
+  if (!warn_address_of_packed_member)
+    return;
+
+  /* Don't warn if we don't assign RHS to a pointer.  */
+  if (!POINTER_TYPE_P (type))
+    return;
+
+  while (TREE_CODE (rhs) == COMPOUND_EXPR)
+    rhs = TREE_OPERAND (rhs, 1);
+
+  if (convert_p)
+    {
+      bool rhspointer_p;
+      tree rhstype;
+
+      /* Check the original type of RHS.  */
+      switch (TREE_CODE (rhs))
+	{
+	case PARM_DECL:
+	case VAR_DECL:
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = POINTER_TYPE_P (rhstype);
+	  break;
+	case NOP_EXPR:
+	  rhs = TREE_OPERAND (rhs, 0);
+	  if (TREE_CODE (rhs) == ADDR_EXPR)
+	    rhs = TREE_OPERAND (rhs, 0);
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
+	  break;
+	default:
+	  return;
+	}
+
+      if (rhspointer_p && TYPE_PACKED (TREE_TYPE (rhstype)))
+	{
+	  unsigned int type_align = TYPE_ALIGN_UNIT (TREE_TYPE (type));
+	  unsigned int rhs_align = TYPE_ALIGN_UNIT (TREE_TYPE (rhstype));
+	  if ((rhs_align % type_align) != 0)
+	    {
+	      location_t location = EXPR_LOC_OR_LOC (rhs, input_location);
+	      warning_at (location, OPT_Waddress_of_packed_member,
+			  "converting a packed %qT pointer (alignment %d) "
+			  "to %qT (alignment %d) may may result in an "
+			  "unaligned pointer value",
+			  rhstype, rhs_align, type, type_align);
+	      tree decl = TYPE_STUB_DECL (TREE_TYPE (rhstype));
+	      inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	      decl = TYPE_STUB_DECL (TREE_TYPE (type));
+	      if (decl)
+		inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	    }
+	}
+    }
+  else
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+
+      check_and_warn_address_of_packed_member (type, rhs);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 07ff1c84f96..22ccf910a85 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -625,6 +625,10 @@ Wincompatible-pointer-types
 C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning
 Warn when there is a conversion between pointers that have incompatible types.
 
+Waddress-of-packed-member
+C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning
+Warn when the address of packed member of struct or union is taken.
+
 Winit-self
 C ObjC C++ ObjC++ Var(warn_init_self) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about variables which are initialized to themselves.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1a897273088..da4a8169d56 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6724,7 +6724,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    return rhs;
+    {
+      warn_for_address_or_pointer_of_packed_member (false, type,
+						    orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7279,6 +7283,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	    }
 	}
 
+      /* If RHS is't an address, check pointer or array of packed
+	 struct or union.  */
+      warn_for_address_or_pointer_of_packed_member
+	(TREE_CODE (orig_rhs) != ADDR_EXPR, type, orig_rhs);
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36b604..40ffc863091 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7618,6 +7618,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	}
       maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
     }
+
+  warn_for_address_or_pointer_of_packed_member (false, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 47ddad16fc1..70b60a928f4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9036,6 +9036,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (false, type, rhs);
+
   return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
 					    complain, flags);
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ac2ee59d92c..47f2fc3f518 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -358,6 +358,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
 -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
 -Wwrite-strings @gol
+-Waddress-of-packed-member @gol
 -Wzero-as-null-pointer-constant  -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -6981,6 +6982,13 @@ behavior and are not portable in C, so they usually indicate that the
 programmer intended to use @code{strcmp}.  This warning is enabled by
 @option{-Wall}.
 
+@item -Waddress-of-packed-member
+@opindex Waddress-of-packed-member
+@opindex Wno-address-of-packed-member
+Warn when the address of packed member of struct or union is taken,
+which usually results in an unaligned pointer value.  This is
+enabled by default.
+
 @item -Wlogical-op
 @opindex Wlogical-op
 @opindex Wno-logical-op
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-1.c b/gcc/testsuite/c-c++-common/asan/misalign-1.c
index 5cd605ac045..ebeb0306706 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-1.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-2.c b/gcc/testsuite/c-c++-common/asan/misalign-2.c
index a6ed49bac05..b27e22d35a8 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-2.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/pr51628-1.c b/gcc/testsuite/c-c++-common/pr51628-1.c
new file mode 100644
index 00000000000..5324f9cc964
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-1.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-10.c b/gcc/testsuite/c-c++-common/pr51628-10.c
new file mode 100644
index 00000000000..085fe1608c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-10.c
@@ -0,0 +1,24 @@
+/* PR c/51628.  */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+struct pair_t
+{
+  char c;
+  __int128_t i;
+} __attribute__ ((packed));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__((packed)) unaligned_int128_t;
+
+struct pair_t p = {0, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *) &p.i;
+
+int 
+main() 
+{
+  addr->value = ~(__int128_t)0;
+  return (p.i != 1) ? 0 : 1;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-11.c b/gcc/testsuite/c-c++-common/pr51628-11.c
new file mode 100644
index 00000000000..7661232ac88
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-11.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[12];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
diff --git a/gcc/testsuite/c-c++-common/pr51628-12.c b/gcc/testsuite/c-c++-common/pr51628-12.c
new file mode 100644
index 00000000000..bc221fa87ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-12.c
@@ -0,0 +1,18 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[10];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-13.c b/gcc/testsuite/c-c++-common/pr51628-13.c
new file mode 100644
index 00000000000..0edd5e7f84d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-13.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* h4 (struct C *p) { return &p->b.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-14.c b/gcc/testsuite/c-c++-common/pr51628-14.c
new file mode 100644
index 00000000000..f50378b8651
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-14.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+void* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/c-c++-common/pr51628-15.c b/gcc/testsuite/c-c++-common/pr51628-15.c
new file mode 100644
index 00000000000..bcac6d70ad5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-15.c
@@ -0,0 +1,14 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+int*
+f (struct A *p, int *q)
+{
+  return q ? q : &p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-16.c b/gcc/testsuite/c-c++-common/pr51628-16.c
new file mode 100644
index 00000000000..cd502fe76b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-16.c
@@ -0,0 +1,13 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct __attribute__ ((packed)) A { int i; };
+struct B {
+  struct A a;
+} b;
+
+int *p = (int*)&b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+int *q = (int*)&b.a;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-2.c b/gcc/testsuite/c-c++-common/pr51628-2.c
new file mode 100644
index 00000000000..abfb84ddd05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-2.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (8)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-26.c b/gcc/testsuite/c-c++-common/pr51628-26.c
new file mode 100644
index 00000000000..2042379860a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-26.c
@@ -0,0 +1,33 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+struct A p = {1};
+int *addr;
+
+int i, j;
+
+void
+foo1 (void)
+{
+  addr = (i = -1, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo2 (void)
+{
+  addr = (i = -1, j = -2, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo3 (void)
+{
+  addr = (i = -1, (j = -2, &p.i));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-27.c b/gcc/testsuite/c-c++-common/pr51628-27.c
new file mode 100644
index 00000000000..9ae1efd7afb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-27.c
@@ -0,0 +1,12 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; } __attribute__ ((packed));
+struct B { struct A a; };
+struct C { struct B b; };
+
+extern struct C *p;
+
+int* g8 (void) { return &p->b.a.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-28.c b/gcc/testsuite/c-c++-common/pr51628-28.c
new file mode 100644
index 00000000000..38dd116c5bb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-28.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { 
+  int i;
+} __attribute__ ((packed));
+
+int *
+foo3 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 
+	  ? &p1->i
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? &p2->i : q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo4 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 ? (*q1 = 1, &p1->i)
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? (*q2 = 2, &p2->i): q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-29.c b/gcc/testsuite/c-c++-common/pr51628-29.c
new file mode 100644
index 00000000000..94b3722d2c8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-29.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+g8 (void)
+{
+  return &p->b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-3.c b/gcc/testsuite/c-c++-common/pr51628-3.c
new file mode 100644
index 00000000000..0ea94c845a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-3.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (2)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-30.c b/gcc/testsuite/c-c++-common/pr51628-30.c
new file mode 100644
index 00000000000..578edf4e8f9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-30.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { __complex int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+foo1 (void)
+{
+  return &__real(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo2 (void)
+{
+  return &__imag(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-31.c b/gcc/testsuite/c-c++-common/pr51628-31.c
new file mode 100644
index 00000000000..9730f53f582
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-31.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+struct X
+{
+  v4si x;
+} __attribute__((packed)) x;
+
+int *
+foo()
+{
+  return &x.x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-32.c b/gcc/testsuite/c-c++-common/pr51628-32.c
new file mode 100644
index 00000000000..b5c42cd0e73
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-32.c
@@ -0,0 +1,19 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A
+{
+   int i;
+} __attribute ((packed));
+
+struct B
+{
+   char c;
+   struct A ar[4];
+};
+
+struct B b;
+
+int *p = &b.ar[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-4.c b/gcc/testsuite/c-c++-common/pr51628-4.c
new file mode 100644
index 00000000000..c4c1fb72d6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-4.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-5.c b/gcc/testsuite/c-c++-common/pr51628-5.c
new file mode 100644
index 00000000000..9d7c309a0ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-5.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-6.c b/gcc/testsuite/c-c++-common/pr51628-6.c
new file mode 100644
index 00000000000..52aa07a4cf3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-6.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-7.c b/gcc/testsuite/c-c++-common/pr51628-7.c
new file mode 100644
index 00000000000..ae4a681f966
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-7.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+  bar (p0);
+  p1 = &p->i[1];
+  bar (p1);
+  bar (p->i);
+  bar (&p->i[2]);
+  x = p->i;
+  return &p->i[3];
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-8.c b/gcc/testsuite/c-c++-common/pr51628-8.c
new file mode 100644
index 00000000000..cc2dae096ae
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-8.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i[4];
+} __attribute__ ((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-9.c b/gcc/testsuite/c-c++-common/pr51628-9.c
new file mode 100644
index 00000000000..0470aa3b93d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-9.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__ ((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-10.c b/gcc/testsuite/c-c++-common/ubsan/align-10.c
index 56ae9ebfe30..6210533173c 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-10.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct R { int a; } r;
 struct S { struct R a; char b; long long c; short d[10]; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-2.c b/gcc/testsuite/c-c++-common/ubsan/align-2.c
index 071de8c202a..336b1c3c907 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-2.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=alignment" } */
+/* { dg-options "-fsanitize=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-4.c b/gcc/testsuite/c-c++-common/ubsan/align-4.c
index 3252595d330..d5feeee29c6 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-4.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=null,alignment" } */
+/* { dg-options "-fsanitize=null,alignment -Wno-address-of-packed-member" } */
 
 #include "align-2.c"
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-6.c b/gcc/testsuite/c-c++-common/ubsan/align-6.c
index 3364746fb27..0302b7b8894 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-6.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-7.c b/gcc/testsuite/c-c++-common/ubsan/align-7.c
index ec4e87f56d5..dd1e8c91cef 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-7.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-7.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-8.c b/gcc/testsuite/c-c++-common/ubsan/align-8.c
index 61c1ceb6682..5fe0e0fe931 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-8.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/g++.dg/ubsan/align-2.C b/gcc/testsuite/g++.dg/ubsan/align-2.C
index 3e4f5485d02..c97ede88392 100644
--- a/gcc/testsuite/g++.dg/ubsan/align-2.C
+++ b/gcc/testsuite/g++.dg/ubsan/align-2.C
@@ -1,6 +1,6 @@
 // Limit this to known non-strict alignment targets.
 // { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
-// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -Wno-address-of-packed-member -std=c++11" }
 
 typedef const long int L;
 struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
diff --git a/gcc/testsuite/gcc.dg/pr51628-17.c b/gcc/testsuite/gcc.dg/pr51628-17.c
new file mode 100644
index 00000000000..0be95b2294e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-17.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+long* f8 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-18.c b/gcc/testsuite/gcc.dg/pr51628-18.c
new file mode 100644
index 00000000000..03a04eff75c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-18.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    int c[k];
+    int x[n];
+  } __attribute__ ((packed, aligned (4)));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+  foo (p0);
+  p1 = &p->x[1];
+  foo (p1);
+  return &p->x[1];
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-19.c b/gcc/testsuite/gcc.dg/pr51628-19.c
new file mode 100644
index 00000000000..7ff03e85cea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-19.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    char c[k];
+    int x[n];
+  } __attribute__ ((packed));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p0);
+  p1 = &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p1);
+  return &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-20.c b/gcc/testsuite/gcc.dg/pr51628-20.c
new file mode 100644
index 00000000000..80888283b73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-20.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C *p;
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-21.c b/gcc/testsuite/gcc.dg/pr51628-21.c
new file mode 100644
index 00000000000..3077e72c8d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-21.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C p[];
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-22.c b/gcc/testsuite/gcc.dg/pr51628-22.c
new file mode 100644
index 00000000000..1bd5d791639
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-22.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* g4 (struct C *p) { return &p->b; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-23.c b/gcc/testsuite/gcc.dg/pr51628-23.c
new file mode 100644
index 00000000000..5709be60ac8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-23.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+char* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/gcc.dg/pr51628-24.c b/gcc/testsuite/gcc.dg/pr51628-24.c
new file mode 100644
index 00000000000..3ad99cd2f16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-24.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+short* f2 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-25.c b/gcc/testsuite/gcc.dg/pr51628-25.c
new file mode 100644
index 00000000000..2fc5c028711
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-25.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+long* g8 (struct C *p) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
index a61609c40d2..c6e3ebdc507 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw" } */
+/* { dg-options "-O2 -mavx512bw -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512bw } */
 
 #define AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
index f2edc3dff7b..95a657fc5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
index 14176965ace..954b091d976 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
index 45ae83d4552..81465f8d9a0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 /* { dg-require-effective-target avx512bw } */
 
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
index 4b928d0cd42..19390664bd0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
index 1863ed3616f..aea0c12a5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index dd5ae95fc2c..05c2fb4dd50 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -177,6 +177,9 @@ read_sleb128 (const unsigned char *p, _sleb128_t *val)
    The function returns P incremented past the value.  BASE is as given
    by base_of_encoded_value for this encoding in the appropriate context.  */
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 static const unsigned char *
 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
 			      const unsigned char *p, _Unwind_Ptr *val)
@@ -270,6 +273,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
   return p;
 }
 
+#pragma GCC diagnostic pop
+
 #ifndef NO_BASE_OF_ENCODED_VALUE
 
 /* Like read_encoded_value_with_base, but get the base from the context
-- 
2.19.2


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

* Re: V8 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-18 21:13                   ` V8 " H.J. Lu
@ 2018-12-18 22:14                     ` Jason Merrill
  2018-12-19 14:52                       ` H.J. Lu
  2018-12-19  3:19                     ` V8 " Sandra Loosemore
  1 sibling, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-18 22:14 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

On 12/18/18 4:12 PM, H.J. Lu wrote:
> On Tue, Dec 18, 2018 at 12:36 PM Jason Merrill <jason@redhat.com> wrote:
>>
>> On 12/18/18 9:10 AM, H.J. Lu wrote:
>>> +  switch (TREE_CODE (rhs))
>>> +    {
>>> +    case ADDR_EXPR:
>>> +      base = TREE_OPERAND (rhs, 0);
>>> +      while (handled_component_p (base))
>>> +     {
>>> +       if (TREE_CODE (base) == COMPONENT_REF)
>>> +         break;
>>> +       base = TREE_OPERAND (base, 0);
>>> +     }
>>> +      if (TREE_CODE (base) != COMPONENT_REF)
>>> +     return NULL_TREE;
>>> +      object = TREE_OPERAND (base, 0);
>>> +      field = TREE_OPERAND (base, 1);
>>> +      break;
>>> +    case COMPONENT_REF:
>>> +      object = TREE_OPERAND (rhs, 0);
>>> +      field = TREE_OPERAND (rhs, 1);
>>> +      break;
>>> +    default:
>>> +      return NULL_TREE;
>>> +    }
>>> +
>>> +  tree context = check_alignment_of_packed_member (type, field);
>>> +  if (context)
>>> +    return context;
>>> +
>>> +  /* Check alignment of the object.  */
>>> +  while (TREE_CODE (object) == COMPONENT_REF)
>>> +    {
>>> +      field = TREE_OPERAND (object, 1);
>>> +      context = check_alignment_of_packed_member (type, field);
>>> +      if (context)
>>> +     return context;
>>> +      object = TREE_OPERAND (object, 0);
>>> +    }
>>> +
>>
>> You can see interleaved COMPONENT_REF and ARRAY_REF that this still
>> doesn't look like it will handle, something like
>>
>> struct A
>> {
>>     int i;
>> };
>>
>> struct B
>> {
>>     char c;
>>     __attribute ((packed)) A ar[4];
>> };
>>
>> B b;
>>
>> int *p = &b.ar[1].i;
>>
>> Rather than have a loop in the ADDR_EXPR case of the switch, you can
>> handle everything in the lower loop.  And not have a switch at all, just
>> strip any ADDR_EXPR before the loop.
> 
> I changed it to
> 
>   if (TREE_CODE (rhs) == ADDR_EXPR)
>      rhs = TREE_OPERAND (rhs, 0);
>    while (handled_component_p (rhs))
>      {
>        if (TREE_CODE (rhs) == COMPONENT_REF)
>          break;
>        rhs = TREE_OPERAND (rhs, 0);
>      }
> 
>    if (TREE_CODE (rhs) != COMPONENT_REF)
>      return NULL_TREE;
> 
>    object = TREE_OPERAND (rhs, 0);
>    field = TREE_OPERAND (rhs, 1);

That still doesn't warn about my testcase above.

> [hjl@gnu-cfl-1 pr51628-6]$ cat a.i
> struct A
> {
>     int i;
> } __attribute ((packed));
> 
> struct B
> {
>     char c;
>     struct A ar[4];
> };
> 
> struct B b;
> 
> int *p = &b.ar[1].i;

This testcase is importantly different because 'i' is packed, whereas in 
my testcase only the ar member of B is packed.

My suggestion was that this loop:

> +  /* Check alignment of the object.  */
> +  while (TREE_CODE (object) == COMPONENT_REF)
> +    {
> +      field = TREE_OPERAND (object, 1);
> +      context = check_alignment_of_packed_member (type, field);
> +      if (context)
> +	return context;
> +      object = TREE_OPERAND (object, 0);
> +    }

could loop over all handled_component_p, but only call 
check_alignment_of_packed_member for COMPONENT_REF.

> +  if (TREE_CODE (rhs) != COND_EXPR)
> +    {
> +      while (TREE_CODE (rhs) == COMPOUND_EXPR)
> +	rhs = TREE_OPERAND (rhs, 1);

What if you have a COND_EXPR inside a COMPOUND_EXPR?

Jason

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

* Re: V8 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-18 21:13                   ` V8 " H.J. Lu
  2018-12-18 22:14                     ` Jason Merrill
@ 2018-12-19  3:19                     ` Sandra Loosemore
  2018-12-19 14:53                       ` H.J. Lu
  1 sibling, 1 reply; 23+ messages in thread
From: Sandra Loosemore @ 2018-12-19  3:19 UTC (permalink / raw)
  To: H.J. Lu, Jason Merrill
  Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

On 12/18/18 2:12 PM, H.J. Lu wrote:
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index ac2ee59d92c..47f2fc3f518 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -358,6 +358,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
>  -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
>  -Wwrite-strings @gol
> +-Waddress-of-packed-member @gol
>  -Wzero-as-null-pointer-constant  -Whsa}
>  
>  @item C and Objective-C-only Warning Options

Minor documentation nit:  it looks like some effort has been made to 
alphabetize that list.  Can you please put -Waddress-of-packed member in 
the right place, and also fix the misplaced -Whsa at the end?

-Sandra

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

* Re: V8 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-18 22:14                     ` Jason Merrill
@ 2018-12-19 14:52                       ` H.J. Lu
  2018-12-19 17:36                         ` V9 " H.J. Lu
  0 siblings, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-12-19 14:52 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

On Tue, Dec 18, 2018 at 2:14 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 12/18/18 4:12 PM, H.J. Lu wrote:
> > On Tue, Dec 18, 2018 at 12:36 PM Jason Merrill <jason@redhat.com> wrote:
> >>
> >> On 12/18/18 9:10 AM, H.J. Lu wrote:
> >>> +  switch (TREE_CODE (rhs))
> >>> +    {
> >>> +    case ADDR_EXPR:
> >>> +      base = TREE_OPERAND (rhs, 0);
> >>> +      while (handled_component_p (base))
> >>> +     {
> >>> +       if (TREE_CODE (base) == COMPONENT_REF)
> >>> +         break;
> >>> +       base = TREE_OPERAND (base, 0);
> >>> +     }
> >>> +      if (TREE_CODE (base) != COMPONENT_REF)
> >>> +     return NULL_TREE;
> >>> +      object = TREE_OPERAND (base, 0);
> >>> +      field = TREE_OPERAND (base, 1);
> >>> +      break;
> >>> +    case COMPONENT_REF:
> >>> +      object = TREE_OPERAND (rhs, 0);
> >>> +      field = TREE_OPERAND (rhs, 1);
> >>> +      break;
> >>> +    default:
> >>> +      return NULL_TREE;
> >>> +    }
> >>> +
> >>> +  tree context = check_alignment_of_packed_member (type, field);
> >>> +  if (context)
> >>> +    return context;
> >>> +
> >>> +  /* Check alignment of the object.  */
> >>> +  while (TREE_CODE (object) == COMPONENT_REF)
> >>> +    {
> >>> +      field = TREE_OPERAND (object, 1);
> >>> +      context = check_alignment_of_packed_member (type, field);
> >>> +      if (context)
> >>> +     return context;
> >>> +      object = TREE_OPERAND (object, 0);
> >>> +    }
> >>> +
> >>
> >> You can see interleaved COMPONENT_REF and ARRAY_REF that this still
> >> doesn't look like it will handle, something like
> >>
> >> struct A
> >> {
> >>     int i;
> >> };
> >>
> >> struct B
> >> {
> >>     char c;
> >>     __attribute ((packed)) A ar[4];
> >> };
> >>
> >> B b;
> >>
> >> int *p = &b.ar[1].i;
> >>
> >> Rather than have a loop in the ADDR_EXPR case of the switch, you can
> >> handle everything in the lower loop.  And not have a switch at all, just
> >> strip any ADDR_EXPR before the loop.
> >
> > I changed it to
> >
> >   if (TREE_CODE (rhs) == ADDR_EXPR)
> >      rhs = TREE_OPERAND (rhs, 0);
> >    while (handled_component_p (rhs))
> >      {
> >        if (TREE_CODE (rhs) == COMPONENT_REF)
> >          break;
> >        rhs = TREE_OPERAND (rhs, 0);
> >      }
> >
> >    if (TREE_CODE (rhs) != COMPONENT_REF)
> >      return NULL_TREE;
> >
> >    object = TREE_OPERAND (rhs, 0);
> >    field = TREE_OPERAND (rhs, 1);
>
> That still doesn't warn about my testcase above.
>
> > [hjl@gnu-cfl-1 pr51628-6]$ cat a.i
> > struct A
> > {
> >     int i;
> > } __attribute ((packed));
> >
> > struct B
> > {
> >     char c;
> >     struct A ar[4];
> > };
> >
> > struct B b;
> >
> > int *p = &b.ar[1].i;
>
> This testcase is importantly different because 'i' is packed, whereas in
> my testcase only the ar member of B is packed.
>
> My suggestion was that this loop:
>
> > +  /* Check alignment of the object.  */
> > +  while (TREE_CODE (object) == COMPONENT_REF)
> > +    {
> > +      field = TREE_OPERAND (object, 1);
> > +      context = check_alignment_of_packed_member (type, field);
> > +      if (context)
> > +     return context;
> > +      object = TREE_OPERAND (object, 0);
> > +    }
>
> could loop over all handled_component_p, but only call
> check_alignment_of_packed_member for COMPONENT_REF.

Thanks for the hint.  I changed it to

  /* Check alignment of the object.  */
  while (handled_component_p (object))
    {
      if (TREE_CODE (object) == COMPONENT_REF)
        {
          do
            {
              field = TREE_OPERAND (object, 1);
              context = check_alignment_of_packed_member (type, field);
              if (context)
                return context;
              object = TREE_OPERAND (object, 0);
            }
          while (TREE_CODE (object) == COMPONENT_REF);
        }
      else
        object = TREE_OPERAND (object, 0);
    }

> > +  if (TREE_CODE (rhs) != COND_EXPR)
> > +    {
> > +      while (TREE_CODE (rhs) == COMPOUND_EXPR)
> > +     rhs = TREE_OPERAND (rhs, 1);
>
> What if you have a COND_EXPR inside a COMPOUND_EXPR?
>

It works for me:

[hjl@gnu-cfl-1 pr51628-5]$ cat c.i
struct A {
  int i;
} __attribute__ ((packed));

int*
foo3 (struct A *p1, int **q1, int *q2, int *q3, struct A *p2)
{
  return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 = 2, &p2->i): q2);
}
[hjl@gnu-cfl-1 pr51628-5]$
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S c.i
c.i: In function \u2018foo3\u2019:
c.i:8:20: warning: assignment to \u2018int *\u2019 from
\u2018int\u2019 makes pointer from integer without a cast
[-Wint-conversion]
    8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
2, &p2->i): q2);
      |                    ^
c.i:8:48: warning: taking address of packed member of \u2018struct
A\u2019 may result in an unaligned pointer value
[-Waddress-of-packed-member]
    8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
2, &p2->i): q2);
      |                                                ^~~~~~
c.i:8:25: warning: taking address of packed member of \u2018struct
A\u2019 may result in an unaligned pointer value
[-Waddress-of-packed-member]
    8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
2, &p2->i): q2);
      |                         ^~~~~~
c.i:8:65: warning: taking address of packed member of \u2018struct
A\u2019 may result in an unaligned pointer value
[-Waddress-of-packed-member]
    8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
2, &p2->i): q2);
      |                                                                 ^~~~~~
[hjl@gnu-cfl-1 pr51628-5]$

If it isn't what you meant, can you give me a testcase?

Thanks.

-- 
H.J.

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

* Re: V8 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-19  3:19                     ` V8 " Sandra Loosemore
@ 2018-12-19 14:53                       ` H.J. Lu
  0 siblings, 0 replies; 23+ messages in thread
From: H.J. Lu @ 2018-12-19 14:53 UTC (permalink / raw)
  To: Sandra Loosemore
  Cc: Jason Merrill, Richard Guenther, Joseph S. Myers, Martin Sebor,
	GCC Patches

On Tue, Dec 18, 2018 at 7:19 PM Sandra Loosemore
<sandra@codesourcery.com> wrote:
>
> On 12/18/18 2:12 PM, H.J. Lu wrote:
> >
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index ac2ee59d92c..47f2fc3f518 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -358,6 +358,7 @@ Objective-C and Objective-C++ Dialects}.
> >  -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
> >  -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
> >  -Wwrite-strings @gol
> > +-Waddress-of-packed-member @gol
> >  -Wzero-as-null-pointer-constant  -Whsa}
> >
> >  @item C and Objective-C-only Warning Options
>
> Minor documentation nit:  it looks like some effort has been made to
> alphabetize that list.  Can you please put -Waddress-of-packed member in
> the right place, and also fix the misplaced -Whsa at the end?
>

I am applying

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 47f2fc3f518..14365fba501 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -281,7 +281,8 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
--w  -Wextra  -Wall  -Waddress  -Waggregate-return  -Waligned-new @gol
+-w  -Wextra  -Wall  -Waddress  -Waddress-of-packed-member @gol
+-Waggregate-return  -Waligned-new @gol
 -Walloc-zero  -Walloc-size-larger-than=@var{byte-size} @gol
 -Walloca  -Walloca-larger-than=@var{byte-size} @gol
 -Wno-aggressive-loop-optimizations  -Warray-bounds  -Warray-bounds=@var{n} @gol
@@ -310,7 +311,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address @gol
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object @gol
 -Wjump-misses-init @gol
--Wif-not-aligned @gol
+-Whsa  -Wif-not-aligned @gol
 -Wignored-qualifiers  -Wignored-attributes  -Wincompatible-pointer-types @gol
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n} @gol
 -Wimplicit-function-declaration  -Wimplicit-int @gol
@@ -358,8 +359,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
 -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
 -Wwrite-strings @gol
--Waddress-of-packed-member @gol
--Wzero-as-null-pointer-constant  -Whsa}
+-Wzero-as-null-pointer-constant}

 @item C and Objective-C-only Warning Options
 @gccoptlist{-Wbad-function-cast  -Wmissing-declarations @gol

Thanks.

-- 
H.J.

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

* V9 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-19 14:52                       ` H.J. Lu
@ 2018-12-19 17:36                         ` H.J. Lu
  2018-12-20 19:40                           ` Jason Merrill
  0 siblings, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-12-19 17:36 UTC (permalink / raw)
  To: Jason Merrill, Sandra Loosemore
  Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

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

On Wed, Dec 19, 2018 at 6:51 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Tue, Dec 18, 2018 at 2:14 PM Jason Merrill <jason@redhat.com> wrote:
> >
> > On 12/18/18 4:12 PM, H.J. Lu wrote:
> > > On Tue, Dec 18, 2018 at 12:36 PM Jason Merrill <jason@redhat.com> wrote:
> > >>
> > >> On 12/18/18 9:10 AM, H.J. Lu wrote:
> > >>> +  switch (TREE_CODE (rhs))
> > >>> +    {
> > >>> +    case ADDR_EXPR:
> > >>> +      base = TREE_OPERAND (rhs, 0);
> > >>> +      while (handled_component_p (base))
> > >>> +     {
> > >>> +       if (TREE_CODE (base) == COMPONENT_REF)
> > >>> +         break;
> > >>> +       base = TREE_OPERAND (base, 0);
> > >>> +     }
> > >>> +      if (TREE_CODE (base) != COMPONENT_REF)
> > >>> +     return NULL_TREE;
> > >>> +      object = TREE_OPERAND (base, 0);
> > >>> +      field = TREE_OPERAND (base, 1);
> > >>> +      break;
> > >>> +    case COMPONENT_REF:
> > >>> +      object = TREE_OPERAND (rhs, 0);
> > >>> +      field = TREE_OPERAND (rhs, 1);
> > >>> +      break;
> > >>> +    default:
> > >>> +      return NULL_TREE;
> > >>> +    }
> > >>> +
> > >>> +  tree context = check_alignment_of_packed_member (type, field);
> > >>> +  if (context)
> > >>> +    return context;
> > >>> +
> > >>> +  /* Check alignment of the object.  */
> > >>> +  while (TREE_CODE (object) == COMPONENT_REF)
> > >>> +    {
> > >>> +      field = TREE_OPERAND (object, 1);
> > >>> +      context = check_alignment_of_packed_member (type, field);
> > >>> +      if (context)
> > >>> +     return context;
> > >>> +      object = TREE_OPERAND (object, 0);
> > >>> +    }
> > >>> +
> > >>
> > >> You can see interleaved COMPONENT_REF and ARRAY_REF that this still
> > >> doesn't look like it will handle, something like
> > >>
> > >> struct A
> > >> {
> > >>     int i;
> > >> };
> > >>
> > >> struct B
> > >> {
> > >>     char c;
> > >>     __attribute ((packed)) A ar[4];
> > >> };
> > >>
> > >> B b;
> > >>
> > >> int *p = &b.ar[1].i;
> > >>
> > >> Rather than have a loop in the ADDR_EXPR case of the switch, you can
> > >> handle everything in the lower loop.  And not have a switch at all, just
> > >> strip any ADDR_EXPR before the loop.
> > >
> > > I changed it to
> > >
> > >   if (TREE_CODE (rhs) == ADDR_EXPR)
> > >      rhs = TREE_OPERAND (rhs, 0);
> > >    while (handled_component_p (rhs))
> > >      {
> > >        if (TREE_CODE (rhs) == COMPONENT_REF)
> > >          break;
> > >        rhs = TREE_OPERAND (rhs, 0);
> > >      }
> > >
> > >    if (TREE_CODE (rhs) != COMPONENT_REF)
> > >      return NULL_TREE;
> > >
> > >    object = TREE_OPERAND (rhs, 0);
> > >    field = TREE_OPERAND (rhs, 1);
> >
> > That still doesn't warn about my testcase above.
> >
> > > [hjl@gnu-cfl-1 pr51628-6]$ cat a.i
> > > struct A
> > > {
> > >     int i;
> > > } __attribute ((packed));
> > >
> > > struct B
> > > {
> > >     char c;
> > >     struct A ar[4];
> > > };
> > >
> > > struct B b;
> > >
> > > int *p = &b.ar[1].i;
> >
> > This testcase is importantly different because 'i' is packed, whereas in
> > my testcase only the ar member of B is packed.
> >
> > My suggestion was that this loop:
> >
> > > +  /* Check alignment of the object.  */
> > > +  while (TREE_CODE (object) == COMPONENT_REF)
> > > +    {
> > > +      field = TREE_OPERAND (object, 1);
> > > +      context = check_alignment_of_packed_member (type, field);
> > > +      if (context)
> > > +     return context;
> > > +      object = TREE_OPERAND (object, 0);
> > > +    }
> >
> > could loop over all handled_component_p, but only call
> > check_alignment_of_packed_member for COMPONENT_REF.
>
> Thanks for the hint.  I changed it to
>
>   /* Check alignment of the object.  */
>   while (handled_component_p (object))
>     {
>       if (TREE_CODE (object) == COMPONENT_REF)
>         {
>           do
>             {
>               field = TREE_OPERAND (object, 1);
>               context = check_alignment_of_packed_member (type, field);
>               if (context)
>                 return context;
>               object = TREE_OPERAND (object, 0);
>             }
>           while (TREE_CODE (object) == COMPONENT_REF);
>         }
>       else
>         object = TREE_OPERAND (object, 0);
>     }

I got
[hjl@gnu-cfl-1 pr51628-6]$ cat a.i
struct A
{
   int i;
};

struct B
{
   char c;
   __attribute ((packed)) struct A ar[4];
};

struct B b;

int *p = &b.ar[1].i;
[hjl@gnu-cfl-1 pr51628-6]$ make a.s
/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
-B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
-S a.i
a.i:14:10: warning: taking address of packed member of ‘struct B’ may
result in an unaligned pointer value [-Waddress-of-packed-member]
   14 | int *p = &b.ar[1].i;
      |          ^~~~~~~~~~
[hjl@gnu-cfl-1 pr51628-6]$

> > > +  if (TREE_CODE (rhs) != COND_EXPR)
> > > +    {
> > > +      while (TREE_CODE (rhs) == COMPOUND_EXPR)
> > > +     rhs = TREE_OPERAND (rhs, 1);
> >
> > What if you have a COND_EXPR inside a COMPOUND_EXPR?
> >
>
> It works for me:
>
> [hjl@gnu-cfl-1 pr51628-5]$ cat c.i
> struct A {
>   int i;
> } __attribute__ ((packed));
>
> int*
> foo3 (struct A *p1, int **q1, int *q2, int *q3, struct A *p2)
> {
>   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 = 2, &p2->i): q2);
> }
> [hjl@gnu-cfl-1 pr51628-5]$
> /export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/xgcc
> -B/export/build/gnu/tools-build/gcc-debug/build-x86_64-linux/gcc/ -O2
> -S c.i
> c.i: In function \u2018foo3\u2019:
> c.i:8:20: warning: assignment to \u2018int *\u2019 from
> \u2018int\u2019 makes pointer from integer without a cast
> [-Wint-conversion]
>     8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
> 2, &p2->i): q2);
>       |                    ^
> c.i:8:48: warning: taking address of packed member of \u2018struct
> A\u2019 may result in an unaligned pointer value
> [-Waddress-of-packed-member]
>     8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
> 2, &p2->i): q2);
>       |                                                ^~~~~~
> c.i:8:25: warning: taking address of packed member of \u2018struct
> A\u2019 may result in an unaligned pointer value
> [-Waddress-of-packed-member]
>     8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
> 2, &p2->i): q2);
>       |                         ^~~~~~
> c.i:8:65: warning: taking address of packed member of \u2018struct
> A\u2019 may result in an unaligned pointer value
> [-Waddress-of-packed-member]
>     8 |   return q1 ? (*q1 = 1, &p1->i) : (q2 ? (*q1 = &p1->i, *q2 =
> 2, &p2->i): q2);
>       |                                                                 ^~~~~~
> [hjl@gnu-cfl-1 pr51628-5]$
>
> If it isn't what you meant, can you give me a testcase?
>

Here is the updated patch.  OK for trunk?

Thanks.

-- 
H.J.

[-- Attachment #2: 0001-C-C-Add-Waddress-of-packed-member.patch --]
[-- Type: text/x-patch, Size: 53309 bytes --]

From 4a5418d5e93369cb5648ba6c0f33203bb6fa8a3f Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 12 Jan 2018 21:12:05 -0800
Subject: [PATCH] C/C++: Add -Waddress-of-packed-member
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When address of packed member of struct or union is taken, it may result
in an unaligned pointer value.  This patch adds -Waddress-of-packed-member
to check alignment at pointer assignment and warn unaligned address as
well as unaligned pointer:

$ cat x.i
struct pair_t
{
  char c;
  int i;
} __attribute__ ((packed));

extern struct pair_t p;
int *addr = &p.i;
$ gcc -O2 -S x.i
x.i:8:13: warning: taking address of packed member of ‘struct pair_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
8 | int *addr = &p.i;
  |             ^

$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
$ gcc -O2 -S c.i -Wno-incompatible-pointer-types
c.i: In function ‘g8’:
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment 1) to ‘long int *’ (alignment 8) may may result in an unaligned pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
$

This warning is enabled by default.  Since read_encoded_value_with_base
in unwind-pe.h has

  union unaligned
    {
      void *ptr;
      unsigned u2 __attribute__ ((mode (HI)));
      unsigned u4 __attribute__ ((mode (SI)));
      unsigned u8 __attribute__ ((mode (DI)));
      signed s2 __attribute__ ((mode (HI)));
      signed s4 __attribute__ ((mode (SI)));
      signed s8 __attribute__ ((mode (DI)));
    } __attribute__((__packed__));
  _Unwind_Internal_Ptr result;

and GCC warns:

gcc/libgcc/unwind-pe.h:210:37: warning: taking address of packed member of 'union unaligned' may result in an unaligned pointer value [-Waddress-of-packed-member]
    result = (_Unwind_Internal_Ptr) u->ptr;
                                    ^
we need to add GCC pragma to ignore -Waddress-of-packed-member.

gcc/c/

	PR c/51628
	* doc/invoke.texi: Document -Wno-address-of-packed-member.

gcc/c-family/

	PR c/51628
	* c-common.h (warn_for_address_or_pointer_of_packed_member): New.
	* c-warn.c (check_alignment_of_packed_member): New function.
	(check_address_of_packed_member): Likewise.
	(check_and_warn_address_of_packed_member): Likewise.
	(warn_for_address_or_pointer_of_packed_member): Likewise.
	* c.opt: Add -Wno-address-of-packed-member.

gcc/c/

	PR c/51628
	* c-typeck.c (convert_for_assignment): Call
	warn_for_address_or_pointer_of_packed_member.

gcc/cp/

	PR c/51628
	* call.c (convert_for_arg_passing): Call
	warn_for_address_or_pointer_of_packed_member.
	* typeck.c (convert_for_assignment): Likewise.

gcc/testsuite/

	PR c/51628
	* c-c++-common/pr51628-1.c: New test.
	* c-c++-common/pr51628-2.c: Likewise.
	* c-c++-common/pr51628-3.c: Likewise.
	* c-c++-common/pr51628-4.c: Likewise.
	* c-c++-common/pr51628-5.c: Likewise.
	* c-c++-common/pr51628-6.c: Likewise.
	* c-c++-common/pr51628-7.c: Likewise.
	* c-c++-common/pr51628-8.c: Likewise.
	* c-c++-common/pr51628-9.c: Likewise.
	* c-c++-common/pr51628-10.c: Likewise.
	* c-c++-common/pr51628-11.c: Likewise.
	* c-c++-common/pr51628-12.c: Likewise.
	* c-c++-common/pr51628-13.c: Likewise.
	* c-c++-common/pr51628-14.c: Likewise.
	* c-c++-common/pr51628-15.c: Likewise.
	* c-c++-common/pr51628-26.c: Likewise.
	* c-c++-common/pr51628-27.c: Likewise.
	* c-c++-common/pr51628-28.c: Likewise.
	* c-c++-common/pr51628-29.c: Likewise.
	* c-c++-common/pr51628-30.c: Likewise.
	* c-c++-common/pr51628-31.c: Likewise.
	* c-c++-common/pr51628-32.c: Likewise.
	* gcc.dg/pr51628-17.c: Likewise.
	* gcc.dg/pr51628-18.c: Likewise.
	* gcc.dg/pr51628-19.c: Likewise.
	* gcc.dg/pr51628-20.c: Likewise.
	* gcc.dg/pr51628-21.c: Likewise.
	* gcc.dg/pr51628-22.c: Likewise.
	* gcc.dg/pr51628-23.c: Likewise.
	* gcc.dg/pr51628-24.c: Likewise.
	* gcc.dg/pr51628-25.c: Likewise.
	* c-c++-common/asan/misalign-1.c: Add
	-Wno-address-of-packed-member.
	* c-c++-common/asan/misalign-2.c: Likewise.
	* c-c++-common/ubsan/align-2.c: Likewise.
	* c-c++-common/ubsan/align-4.c: Likewise.
	* c-c++-common/ubsan/align-6.c: Likewise.
	* c-c++-common/ubsan/align-7.c: Likewise.
	* c-c++-common/ubsan/align-8.c: Likewise.
	* c-c++-common/ubsan/align-10.c: Likewise.
	* g++.dg/ubsan/align-2.C: Likewise.
	* gcc.target/i386/avx512bw-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu64-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu64-2.c: Likewise.

libgcc/

	* unwind-pe.h (read_encoded_value_with_base): Add GCC pragma
	to ignore -Waddress-of-packed-member.
---
 gcc/c-family/c-common.h                       |   1 +
 gcc/c-family/c-warn.c                         | 187 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  11 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |  14 +-
 gcc/testsuite/c-c++-common/asan/misalign-1.c  |   2 +-
 gcc/testsuite/c-c++-common/asan/misalign-2.c  |   2 +-
 gcc/testsuite/c-c++-common/pr51628-1.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-10.c       |  24 +++
 gcc/testsuite/c-c++-common/pr51628-11.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-12.c       |  18 ++
 gcc/testsuite/c-c++-common/pr51628-13.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-14.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-15.c       |  14 ++
 gcc/testsuite/c-c++-common/pr51628-16.c       |  13 ++
 gcc/testsuite/c-c++-common/pr51628-2.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-26.c       |  33 ++++
 gcc/testsuite/c-c++-common/pr51628-27.c       |  12 ++
 gcc/testsuite/c-c++-common/pr51628-28.c       |  31 +++
 gcc/testsuite/c-c++-common/pr51628-29.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-3.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-30.c       |  23 +++
 gcc/testsuite/c-c++-common/pr51628-31.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-32.c       |  19 ++
 gcc/testsuite/c-c++-common/pr51628-4.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-5.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-6.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-7.c        |  29 +++
 gcc/testsuite/c-c++-common/pr51628-8.c        |  36 ++++
 gcc/testsuite/c-c++-common/pr51628-9.c        |  36 ++++
 gcc/testsuite/c-c++-common/ubsan/align-10.c   |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-2.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-4.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-6.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-7.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-8.c    |   2 +-
 gcc/testsuite/g++.dg/ubsan/align-2.C          |   2 +-
 gcc/testsuite/gcc.dg/pr51628-17.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-18.c             |  23 +++
 gcc/testsuite/gcc.dg/pr51628-19.c             |  26 +++
 gcc/testsuite/gcc.dg/pr51628-20.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-21.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-22.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-23.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-24.c             |  10 +
 gcc/testsuite/gcc.dg/pr51628-25.c             |   9 +
 .../gcc.target/i386/avx512bw-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu32-2.c     |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu64-2.c     |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu32-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu64-2.c    |   2 +-
 libgcc/unwind-pe.h                            |   5 +
 55 files changed, 909 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-10.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-11.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-12.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-13.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-14.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-15.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-16.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-26.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-27.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-28.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-29.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-30.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-31.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-32.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-4.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-5.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-6.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-7.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-8.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-9.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-17.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-18.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-19.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-20.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-21.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-22.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-23.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-24.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-25.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343c0b3..eb0ad60940d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1282,6 +1282,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern bool warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_for_address_or_pointer_of_packed_member (bool, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 798ad1bcb39..2c2aefbd63f 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2616,3 +2616,190 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
 }
+
+/* Return struct or union type if the alignment of data memeber, FIELD,
+   is less than the alignment of TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_alignment_of_packed_member (tree type, tree field)
+{
+  /* Check alignment of the data member.  */
+  if (TREE_CODE (field) == FIELD_DECL
+      && (DECL_PACKED (field)
+	  || TYPE_PACKED (TREE_TYPE (field))))
+    {
+      /* Check the expected alignment against the field alignment.  */
+      unsigned int type_align = TYPE_ALIGN (type);
+      tree context = DECL_CONTEXT (field);
+      unsigned int record_align = TYPE_ALIGN (context);
+      if ((record_align % type_align) != 0)
+	return context;
+      tree field_off = byte_position (field);
+      if (!multiple_of_p (TREE_TYPE (field_off), field_off,
+			  size_int (type_align / BITS_PER_UNIT)))
+	return context;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return struct or union type if the right hand value, RHS, takes the
+   unaligned address of packed member of struct or union when assigning
+   to TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_address_of_packed_member (tree type, tree rhs)
+{
+  tree object;
+  tree field;
+
+  if (INDIRECT_REF_P (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+
+  if (TREE_CODE (rhs) == ADDR_EXPR)
+    rhs = TREE_OPERAND (rhs, 0);
+  while (handled_component_p (rhs))
+    {
+      if (TREE_CODE (rhs) == COMPONENT_REF)
+	break;
+      rhs = TREE_OPERAND (rhs, 0);
+    }
+
+  if (TREE_CODE (rhs) != COMPONENT_REF)
+    return NULL_TREE;
+
+  object = TREE_OPERAND (rhs, 0);
+  field = TREE_OPERAND (rhs, 1);
+
+  tree context = check_alignment_of_packed_member (type, field);
+  if (context)
+    return context;
+
+  /* Check alignment of the object.  */
+  while (handled_component_p (object))
+    {
+      if (TREE_CODE (object) == COMPONENT_REF)
+	{
+	  do
+	    {
+	      field = TREE_OPERAND (object, 1);
+	      context = check_alignment_of_packed_member (type, field);
+	      if (context)
+		return context;
+	      object = TREE_OPERAND (object, 0);
+	    }
+	  while (TREE_CODE (object) == COMPONENT_REF);
+	}
+      else
+	object = TREE_OPERAND (object, 0);
+    }
+
+  return NULL_TREE;
+}
+
+/* Check and warn if the right hand value, RHS, takes the unaligned
+   address of packed member of struct or union when assigning to TYPE.  */
+
+static void
+check_and_warn_address_of_packed_member (tree type, tree rhs)
+{
+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      while (TREE_CODE (rhs) == COMPOUND_EXPR)
+	rhs = TREE_OPERAND (rhs, 1);
+
+      tree context = check_address_of_packed_member (type, rhs);
+      if (context)
+	{
+	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
+	  warning_at (loc, OPT_Waddress_of_packed_member,
+		      "taking address of packed member of %qT may result "
+		      "in an unaligned pointer value",
+		      context);
+	}
+      return;
+    }
+
+  /* Check the THEN path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
+
+  /* Check the ELSE path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
+}
+
+/* Warn if the right hand value, RHS:
+   1. For CONVERT_P == true, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+   2. For CONVERT_P == false, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool convert_p, tree type,
+					      tree rhs)
+{
+  if (!warn_address_of_packed_member)
+    return;
+
+  /* Don't warn if we don't assign RHS to a pointer.  */
+  if (!POINTER_TYPE_P (type))
+    return;
+
+  while (TREE_CODE (rhs) == COMPOUND_EXPR)
+    rhs = TREE_OPERAND (rhs, 1);
+
+  if (convert_p)
+    {
+      bool rhspointer_p;
+      tree rhstype;
+
+      /* Check the original type of RHS.  */
+      switch (TREE_CODE (rhs))
+	{
+	case PARM_DECL:
+	case VAR_DECL:
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = POINTER_TYPE_P (rhstype);
+	  break;
+	case NOP_EXPR:
+	  rhs = TREE_OPERAND (rhs, 0);
+	  if (TREE_CODE (rhs) == ADDR_EXPR)
+	    rhs = TREE_OPERAND (rhs, 0);
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
+	  break;
+	default:
+	  return;
+	}
+
+      if (rhspointer_p && TYPE_PACKED (TREE_TYPE (rhstype)))
+	{
+	  unsigned int type_align = TYPE_ALIGN_UNIT (TREE_TYPE (type));
+	  unsigned int rhs_align = TYPE_ALIGN_UNIT (TREE_TYPE (rhstype));
+	  if ((rhs_align % type_align) != 0)
+	    {
+	      location_t location = EXPR_LOC_OR_LOC (rhs, input_location);
+	      warning_at (location, OPT_Waddress_of_packed_member,
+			  "converting a packed %qT pointer (alignment %d) "
+			  "to %qT (alignment %d) may may result in an "
+			  "unaligned pointer value",
+			  rhstype, rhs_align, type, type_align);
+	      tree decl = TYPE_STUB_DECL (TREE_TYPE (rhstype));
+	      inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	      decl = TYPE_STUB_DECL (TREE_TYPE (type));
+	      if (decl)
+		inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	    }
+	}
+    }
+  else
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+
+      check_and_warn_address_of_packed_member (type, rhs);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 07ff1c84f96..22ccf910a85 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -625,6 +625,10 @@ Wincompatible-pointer-types
 C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning
 Warn when there is a conversion between pointers that have incompatible types.
 
+Waddress-of-packed-member
+C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning
+Warn when the address of packed member of struct or union is taken.
+
 Winit-self
 C ObjC C++ ObjC++ Var(warn_init_self) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about variables which are initialized to themselves.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1a897273088..da4a8169d56 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6724,7 +6724,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    return rhs;
+    {
+      warn_for_address_or_pointer_of_packed_member (false, type,
+						    orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7279,6 +7283,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	    }
 	}
 
+      /* If RHS is't an address, check pointer or array of packed
+	 struct or union.  */
+      warn_for_address_or_pointer_of_packed_member
+	(TREE_CODE (orig_rhs) != ADDR_EXPR, type, orig_rhs);
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36b604..40ffc863091 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7618,6 +7618,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	}
       maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
     }
+
+  warn_for_address_or_pointer_of_packed_member (false, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 47ddad16fc1..70b60a928f4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9036,6 +9036,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (false, type, rhs);
+
   return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
 					    complain, flags);
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ac2ee59d92c..14365fba501 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -281,7 +281,8 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
--w  -Wextra  -Wall  -Waddress  -Waggregate-return  -Waligned-new @gol
+-w  -Wextra  -Wall  -Waddress  -Waddress-of-packed-member @gol
+-Waggregate-return  -Waligned-new @gol
 -Walloc-zero  -Walloc-size-larger-than=@var{byte-size} @gol
 -Walloca  -Walloca-larger-than=@var{byte-size} @gol
 -Wno-aggressive-loop-optimizations  -Warray-bounds  -Warray-bounds=@var{n} @gol
@@ -310,7 +311,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address @gol
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object @gol
 -Wjump-misses-init @gol
--Wif-not-aligned @gol
+-Whsa  -Wif-not-aligned @gol
 -Wignored-qualifiers  -Wignored-attributes  -Wincompatible-pointer-types @gol
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n} @gol
 -Wimplicit-function-declaration  -Wimplicit-int @gol
@@ -358,7 +359,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
 -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
 -Wwrite-strings @gol
--Wzero-as-null-pointer-constant  -Whsa}
+-Wzero-as-null-pointer-constant}
 
 @item C and Objective-C-only Warning Options
 @gccoptlist{-Wbad-function-cast  -Wmissing-declarations @gol
@@ -6981,6 +6982,13 @@ behavior and are not portable in C, so they usually indicate that the
 programmer intended to use @code{strcmp}.  This warning is enabled by
 @option{-Wall}.
 
+@item -Waddress-of-packed-member
+@opindex Waddress-of-packed-member
+@opindex Wno-address-of-packed-member
+Warn when the address of packed member of struct or union is taken,
+which usually results in an unaligned pointer value.  This is
+enabled by default.
+
 @item -Wlogical-op
 @opindex Wlogical-op
 @opindex Wno-logical-op
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-1.c b/gcc/testsuite/c-c++-common/asan/misalign-1.c
index 5cd605ac045..ebeb0306706 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-1.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-2.c b/gcc/testsuite/c-c++-common/asan/misalign-2.c
index a6ed49bac05..b27e22d35a8 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-2.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/pr51628-1.c b/gcc/testsuite/c-c++-common/pr51628-1.c
new file mode 100644
index 00000000000..5324f9cc964
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-1.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-10.c b/gcc/testsuite/c-c++-common/pr51628-10.c
new file mode 100644
index 00000000000..085fe1608c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-10.c
@@ -0,0 +1,24 @@
+/* PR c/51628.  */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+struct pair_t
+{
+  char c;
+  __int128_t i;
+} __attribute__ ((packed));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__((packed)) unaligned_int128_t;
+
+struct pair_t p = {0, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *) &p.i;
+
+int 
+main() 
+{
+  addr->value = ~(__int128_t)0;
+  return (p.i != 1) ? 0 : 1;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-11.c b/gcc/testsuite/c-c++-common/pr51628-11.c
new file mode 100644
index 00000000000..7661232ac88
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-11.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[12];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
diff --git a/gcc/testsuite/c-c++-common/pr51628-12.c b/gcc/testsuite/c-c++-common/pr51628-12.c
new file mode 100644
index 00000000000..bc221fa87ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-12.c
@@ -0,0 +1,18 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[10];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-13.c b/gcc/testsuite/c-c++-common/pr51628-13.c
new file mode 100644
index 00000000000..0edd5e7f84d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-13.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* h4 (struct C *p) { return &p->b.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-14.c b/gcc/testsuite/c-c++-common/pr51628-14.c
new file mode 100644
index 00000000000..f50378b8651
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-14.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+void* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/c-c++-common/pr51628-15.c b/gcc/testsuite/c-c++-common/pr51628-15.c
new file mode 100644
index 00000000000..bcac6d70ad5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-15.c
@@ -0,0 +1,14 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+int*
+f (struct A *p, int *q)
+{
+  return q ? q : &p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-16.c b/gcc/testsuite/c-c++-common/pr51628-16.c
new file mode 100644
index 00000000000..cd502fe76b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-16.c
@@ -0,0 +1,13 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct __attribute__ ((packed)) A { int i; };
+struct B {
+  struct A a;
+} b;
+
+int *p = (int*)&b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+int *q = (int*)&b.a;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-2.c b/gcc/testsuite/c-c++-common/pr51628-2.c
new file mode 100644
index 00000000000..abfb84ddd05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-2.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (8)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-26.c b/gcc/testsuite/c-c++-common/pr51628-26.c
new file mode 100644
index 00000000000..2042379860a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-26.c
@@ -0,0 +1,33 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+struct A p = {1};
+int *addr;
+
+int i, j;
+
+void
+foo1 (void)
+{
+  addr = (i = -1, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo2 (void)
+{
+  addr = (i = -1, j = -2, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo3 (void)
+{
+  addr = (i = -1, (j = -2, &p.i));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-27.c b/gcc/testsuite/c-c++-common/pr51628-27.c
new file mode 100644
index 00000000000..9ae1efd7afb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-27.c
@@ -0,0 +1,12 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; } __attribute__ ((packed));
+struct B { struct A a; };
+struct C { struct B b; };
+
+extern struct C *p;
+
+int* g8 (void) { return &p->b.a.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-28.c b/gcc/testsuite/c-c++-common/pr51628-28.c
new file mode 100644
index 00000000000..3cc1fec1f71
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-28.c
@@ -0,0 +1,31 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { 
+  int i;
+} __attribute__ ((packed));
+
+int *
+foo3 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 
+	  ? &p1->i
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? &p2->i : q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo4 (struct A *p1, int **q1, int *q2, int *q3, struct A *p2)
+{
+  return (q1
+	  ? (*q1 = q2, &p1->i)
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2
+	     ? (*q1 = &p1->i,
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+		*q2 = 2, &p2->i)
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	     : q2));
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-29.c b/gcc/testsuite/c-c++-common/pr51628-29.c
new file mode 100644
index 00000000000..94b3722d2c8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-29.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+g8 (void)
+{
+  return &p->b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-3.c b/gcc/testsuite/c-c++-common/pr51628-3.c
new file mode 100644
index 00000000000..0ea94c845a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-3.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (2)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-30.c b/gcc/testsuite/c-c++-common/pr51628-30.c
new file mode 100644
index 00000000000..578edf4e8f9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-30.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { __complex int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+foo1 (void)
+{
+  return &__real(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo2 (void)
+{
+  return &__imag(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-31.c b/gcc/testsuite/c-c++-common/pr51628-31.c
new file mode 100644
index 00000000000..9730f53f582
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-31.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+struct X
+{
+  v4si x;
+} __attribute__((packed)) x;
+
+int *
+foo()
+{
+  return &x.x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-32.c b/gcc/testsuite/c-c++-common/pr51628-32.c
new file mode 100644
index 00000000000..a62e57d5b46
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-32.c
@@ -0,0 +1,19 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A
+{
+   int i;
+};
+
+struct B
+{
+   char c;
+   __attribute ((packed)) struct A ar[4];
+};
+
+struct B b;
+
+int *p = &b.ar[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-4.c b/gcc/testsuite/c-c++-common/pr51628-4.c
new file mode 100644
index 00000000000..c4c1fb72d6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-4.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-5.c b/gcc/testsuite/c-c++-common/pr51628-5.c
new file mode 100644
index 00000000000..9d7c309a0ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-5.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-6.c b/gcc/testsuite/c-c++-common/pr51628-6.c
new file mode 100644
index 00000000000..52aa07a4cf3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-6.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-7.c b/gcc/testsuite/c-c++-common/pr51628-7.c
new file mode 100644
index 00000000000..ae4a681f966
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-7.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+  bar (p0);
+  p1 = &p->i[1];
+  bar (p1);
+  bar (p->i);
+  bar (&p->i[2]);
+  x = p->i;
+  return &p->i[3];
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-8.c b/gcc/testsuite/c-c++-common/pr51628-8.c
new file mode 100644
index 00000000000..cc2dae096ae
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-8.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i[4];
+} __attribute__ ((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-9.c b/gcc/testsuite/c-c++-common/pr51628-9.c
new file mode 100644
index 00000000000..0470aa3b93d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-9.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__ ((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-10.c b/gcc/testsuite/c-c++-common/ubsan/align-10.c
index 56ae9ebfe30..6210533173c 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-10.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct R { int a; } r;
 struct S { struct R a; char b; long long c; short d[10]; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-2.c b/gcc/testsuite/c-c++-common/ubsan/align-2.c
index 071de8c202a..336b1c3c907 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-2.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=alignment" } */
+/* { dg-options "-fsanitize=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-4.c b/gcc/testsuite/c-c++-common/ubsan/align-4.c
index 3252595d330..d5feeee29c6 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-4.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=null,alignment" } */
+/* { dg-options "-fsanitize=null,alignment -Wno-address-of-packed-member" } */
 
 #include "align-2.c"
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-6.c b/gcc/testsuite/c-c++-common/ubsan/align-6.c
index 3364746fb27..0302b7b8894 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-6.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-7.c b/gcc/testsuite/c-c++-common/ubsan/align-7.c
index ec4e87f56d5..dd1e8c91cef 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-7.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-7.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-8.c b/gcc/testsuite/c-c++-common/ubsan/align-8.c
index 61c1ceb6682..5fe0e0fe931 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-8.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/g++.dg/ubsan/align-2.C b/gcc/testsuite/g++.dg/ubsan/align-2.C
index 3e4f5485d02..c97ede88392 100644
--- a/gcc/testsuite/g++.dg/ubsan/align-2.C
+++ b/gcc/testsuite/g++.dg/ubsan/align-2.C
@@ -1,6 +1,6 @@
 // Limit this to known non-strict alignment targets.
 // { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
-// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -Wno-address-of-packed-member -std=c++11" }
 
 typedef const long int L;
 struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
diff --git a/gcc/testsuite/gcc.dg/pr51628-17.c b/gcc/testsuite/gcc.dg/pr51628-17.c
new file mode 100644
index 00000000000..0be95b2294e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-17.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+long* f8 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-18.c b/gcc/testsuite/gcc.dg/pr51628-18.c
new file mode 100644
index 00000000000..03a04eff75c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-18.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    int c[k];
+    int x[n];
+  } __attribute__ ((packed, aligned (4)));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+  foo (p0);
+  p1 = &p->x[1];
+  foo (p1);
+  return &p->x[1];
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-19.c b/gcc/testsuite/gcc.dg/pr51628-19.c
new file mode 100644
index 00000000000..7ff03e85cea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-19.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    char c[k];
+    int x[n];
+  } __attribute__ ((packed));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p0);
+  p1 = &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p1);
+  return &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-20.c b/gcc/testsuite/gcc.dg/pr51628-20.c
new file mode 100644
index 00000000000..80888283b73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-20.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C *p;
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-21.c b/gcc/testsuite/gcc.dg/pr51628-21.c
new file mode 100644
index 00000000000..3077e72c8d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-21.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C p[];
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-22.c b/gcc/testsuite/gcc.dg/pr51628-22.c
new file mode 100644
index 00000000000..1bd5d791639
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-22.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* g4 (struct C *p) { return &p->b; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-23.c b/gcc/testsuite/gcc.dg/pr51628-23.c
new file mode 100644
index 00000000000..5709be60ac8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-23.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+char* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/gcc.dg/pr51628-24.c b/gcc/testsuite/gcc.dg/pr51628-24.c
new file mode 100644
index 00000000000..3ad99cd2f16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-24.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+short* f2 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-25.c b/gcc/testsuite/gcc.dg/pr51628-25.c
new file mode 100644
index 00000000000..2fc5c028711
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-25.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+long* g8 (struct C *p) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
index a61609c40d2..c6e3ebdc507 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw" } */
+/* { dg-options "-O2 -mavx512bw -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512bw } */
 
 #define AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
index f2edc3dff7b..95a657fc5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
index 14176965ace..954b091d976 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
index 45ae83d4552..81465f8d9a0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 /* { dg-require-effective-target avx512bw } */
 
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
index 4b928d0cd42..19390664bd0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
index 1863ed3616f..aea0c12a5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index dd5ae95fc2c..05c2fb4dd50 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -177,6 +177,9 @@ read_sleb128 (const unsigned char *p, _sleb128_t *val)
    The function returns P incremented past the value.  BASE is as given
    by base_of_encoded_value for this encoding in the appropriate context.  */
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 static const unsigned char *
 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
 			      const unsigned char *p, _Unwind_Ptr *val)
@@ -270,6 +273,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
   return p;
 }
 
+#pragma GCC diagnostic pop
+
 #ifndef NO_BASE_OF_ENCODED_VALUE
 
 /* Like read_encoded_value_with_base, but get the base from the context
-- 
2.19.2


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

* Re: V9 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-19 17:36                         ` V9 " H.J. Lu
@ 2018-12-20 19:40                           ` Jason Merrill
  2018-12-20 20:07                             ` V10 " H.J. Lu
  0 siblings, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-20 19:40 UTC (permalink / raw)
  To: H.J. Lu, Sandra Loosemore
  Cc: Richard Guenther, Joseph S. Myers, Martin Sebor, GCC Patches

On 12/19/18 12:35 PM, H.J. Lu wrote:
> +  while (handled_component_p (rhs))
> +    {
> +      if (TREE_CODE (rhs) == COMPONENT_REF)
> +	break;
> +      rhs = TREE_OPERAND (rhs, 0);
> +    }
> +
> +  if (TREE_CODE (rhs) != COMPONENT_REF)
> +    return NULL_TREE;
> +
> +  object = TREE_OPERAND (rhs, 0);
> +  field = TREE_OPERAND (rhs, 1);
> +
> +  tree context = check_alignment_of_packed_member (type, field);
> +  if (context)
> +    return context;

All the above looks unnecessary; it will be handled by the loop below.

> +  /* Check alignment of the object.  */
> +  while (handled_component_p (object))
> +    {
> +      if (TREE_CODE (object) == COMPONENT_REF)
> +	{
> +	  do
> +	    {
> +	      field = TREE_OPERAND (object, 1);
> +	      context = check_alignment_of_packed_member (type, field);
> +	      if (context)
> +		return context;
> +	      object = TREE_OPERAND (object, 0);
> +	    }
> +	  while (TREE_CODE (object) == COMPONENT_REF);

This inner loop also seems unnecessary.

> +	}
> +      else
> +	object = TREE_OPERAND (object, 0);
> +    }

Jason

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

* V10 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-20 19:40                           ` Jason Merrill
@ 2018-12-20 20:07                             ` H.J. Lu
  2018-12-20 21:31                               ` Jason Merrill
  0 siblings, 1 reply; 23+ messages in thread
From: H.J. Lu @ 2018-12-20 20:07 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Sandra Loosemore, Richard Guenther, Joseph S. Myers,
	Martin Sebor, GCC Patches

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

On Thu, Dec 20, 2018 at 11:28 AM Jason Merrill <jason@redhat.com> wrote:
>
> On 12/19/18 12:35 PM, H.J. Lu wrote:
> > +  while (handled_component_p (rhs))
> > +    {
> > +      if (TREE_CODE (rhs) == COMPONENT_REF)
> > +     break;
> > +      rhs = TREE_OPERAND (rhs, 0);
> > +    }
> > +
> > +  if (TREE_CODE (rhs) != COMPONENT_REF)
> > +    return NULL_TREE;
> > +
> > +  object = TREE_OPERAND (rhs, 0);
> > +  field = TREE_OPERAND (rhs, 1);
> > +
> > +  tree context = check_alignment_of_packed_member (type, field);
> > +  if (context)
> > +    return context;
>
> All the above looks unnecessary; it will be handled by the loop below.
>
> > +  /* Check alignment of the object.  */
> > +  while (handled_component_p (object))
> > +    {
> > +      if (TREE_CODE (object) == COMPONENT_REF)
> > +     {
> > +       do
> > +         {
> > +           field = TREE_OPERAND (object, 1);
> > +           context = check_alignment_of_packed_member (type, field);
> > +           if (context)
> > +             return context;
> > +           object = TREE_OPERAND (object, 0);
> > +         }
> > +       while (TREE_CODE (object) == COMPONENT_REF);
>
> This inner loop also seems unnecessary.
>
> > +     }
> > +      else
> > +     object = TREE_OPERAND (object, 0);
> > +    }
>
> Jason

I changed it to

static tree
check_address_of_packed_member (tree type, tree rhs)
{
  if (INDIRECT_REF_P (rhs))
    rhs = TREE_OPERAND (rhs, 0);

  if (TREE_CODE (rhs) == ADDR_EXPR)
    rhs = TREE_OPERAND (rhs, 0);

  tree context = NULL_TREE;

  /* Check alignment of the object.  */
  while (handled_component_p (rhs))
    {
      if (TREE_CODE (rhs) == COMPONENT_REF)
        {
          tree field = TREE_OPERAND (rhs, 1);
          context = check_alignment_of_packed_member (type, field);
          if (context)
            break;
        }
      rhs = TREE_OPERAND (rhs, 0);
    }

  return context;
}

Here is the updated patch.  OK for trunk?

Thanks.

-- 
H.J.

[-- Attachment #2: 0001-C-C-Add-Waddress-of-packed-member.patch --]
[-- Type: text/x-patch, Size: 52778 bytes --]

From f2982a694a2fab4dd1ce2a6819006b451fa0c9a7 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 12 Jan 2018 21:12:05 -0800
Subject: [PATCH] C/C++: Add -Waddress-of-packed-member
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When address of packed member of struct or union is taken, it may result
in an unaligned pointer value.  This patch adds -Waddress-of-packed-member
to check alignment at pointer assignment and warn unaligned address as
well as unaligned pointer:

$ cat x.i
struct pair_t
{
  char c;
  int i;
} __attribute__ ((packed));

extern struct pair_t p;
int *addr = &p.i;
$ gcc -O2 -S x.i
x.i:8:13: warning: taking address of packed member of ‘struct pair_t’ may result in an unaligned pointer value [-Waddress-of-packed-member]
8 | int *addr = &p.i;
  |             ^

$ cat c.i
struct B { int i; };
struct C { struct B b; } __attribute__ ((packed));

long* g8 (struct C *p) { return p; }
$ gcc -O2 -S c.i -Wno-incompatible-pointer-types
c.i: In function ‘g8’:
c.i:4:18: warning: converting a packed ‘struct C *’ pointer (alignment 1) to ‘long int *’ (alignment 8) may may result in an unaligned pointer value [-Waddress-of-packed-member]
4 | long* g8 (struct C *p) { return p; }
  |                  ^
c.i:2:8: note: defined here
2 | struct C { struct B b; } __attribute__ ((packed));
  |        ^
$

This warning is enabled by default.  Since read_encoded_value_with_base
in unwind-pe.h has

  union unaligned
    {
      void *ptr;
      unsigned u2 __attribute__ ((mode (HI)));
      unsigned u4 __attribute__ ((mode (SI)));
      unsigned u8 __attribute__ ((mode (DI)));
      signed s2 __attribute__ ((mode (HI)));
      signed s4 __attribute__ ((mode (SI)));
      signed s8 __attribute__ ((mode (DI)));
    } __attribute__((__packed__));
  _Unwind_Internal_Ptr result;

and GCC warns:

gcc/libgcc/unwind-pe.h:210:37: warning: taking address of packed member of 'union unaligned' may result in an unaligned pointer value [-Waddress-of-packed-member]
    result = (_Unwind_Internal_Ptr) u->ptr;
                                    ^
we need to add GCC pragma to ignore -Waddress-of-packed-member.

gcc/c/

	PR c/51628
	* doc/invoke.texi: Document -Wno-address-of-packed-member.

gcc/c-family/

	PR c/51628
	* c-common.h (warn_for_address_or_pointer_of_packed_member): New.
	* c-warn.c (check_alignment_of_packed_member): New function.
	(check_address_of_packed_member): Likewise.
	(check_and_warn_address_of_packed_member): Likewise.
	(warn_for_address_or_pointer_of_packed_member): Likewise.
	* c.opt: Add -Wno-address-of-packed-member.

gcc/c/

	PR c/51628
	* c-typeck.c (convert_for_assignment): Call
	warn_for_address_or_pointer_of_packed_member.

gcc/cp/

	PR c/51628
	* call.c (convert_for_arg_passing): Call
	warn_for_address_or_pointer_of_packed_member.
	* typeck.c (convert_for_assignment): Likewise.

gcc/testsuite/

	PR c/51628
	* c-c++-common/pr51628-1.c: New test.
	* c-c++-common/pr51628-2.c: Likewise.
	* c-c++-common/pr51628-3.c: Likewise.
	* c-c++-common/pr51628-4.c: Likewise.
	* c-c++-common/pr51628-5.c: Likewise.
	* c-c++-common/pr51628-6.c: Likewise.
	* c-c++-common/pr51628-7.c: Likewise.
	* c-c++-common/pr51628-8.c: Likewise.
	* c-c++-common/pr51628-9.c: Likewise.
	* c-c++-common/pr51628-10.c: Likewise.
	* c-c++-common/pr51628-11.c: Likewise.
	* c-c++-common/pr51628-12.c: Likewise.
	* c-c++-common/pr51628-13.c: Likewise.
	* c-c++-common/pr51628-14.c: Likewise.
	* c-c++-common/pr51628-15.c: Likewise.
	* c-c++-common/pr51628-26.c: Likewise.
	* c-c++-common/pr51628-27.c: Likewise.
	* c-c++-common/pr51628-28.c: Likewise.
	* c-c++-common/pr51628-29.c: Likewise.
	* c-c++-common/pr51628-30.c: Likewise.
	* c-c++-common/pr51628-31.c: Likewise.
	* c-c++-common/pr51628-32.c: Likewise.
	* gcc.dg/pr51628-17.c: Likewise.
	* gcc.dg/pr51628-18.c: Likewise.
	* gcc.dg/pr51628-19.c: Likewise.
	* gcc.dg/pr51628-20.c: Likewise.
	* gcc.dg/pr51628-21.c: Likewise.
	* gcc.dg/pr51628-22.c: Likewise.
	* gcc.dg/pr51628-23.c: Likewise.
	* gcc.dg/pr51628-24.c: Likewise.
	* gcc.dg/pr51628-25.c: Likewise.
	* c-c++-common/asan/misalign-1.c: Add
	-Wno-address-of-packed-member.
	* c-c++-common/asan/misalign-2.c: Likewise.
	* c-c++-common/ubsan/align-2.c: Likewise.
	* c-c++-common/ubsan/align-4.c: Likewise.
	* c-c++-common/ubsan/align-6.c: Likewise.
	* c-c++-common/ubsan/align-7.c: Likewise.
	* c-c++-common/ubsan/align-8.c: Likewise.
	* c-c++-common/ubsan/align-10.c: Likewise.
	* g++.dg/ubsan/align-2.C: Likewise.
	* gcc.target/i386/avx512bw-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512f-vmovdqu64-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu16-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu32-2.c: Likewise.
	* gcc.target/i386/avx512vl-vmovdqu64-2.c: Likewise.

libgcc/

	* unwind-pe.h (read_encoded_value_with_base): Add GCC pragma
	to ignore -Waddress-of-packed-member.
---
 gcc/c-family/c-common.h                       |   1 +
 gcc/c-family/c-warn.c                         | 164 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  11 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |  14 +-
 gcc/testsuite/c-c++-common/asan/misalign-1.c  |   2 +-
 gcc/testsuite/c-c++-common/asan/misalign-2.c  |   2 +-
 gcc/testsuite/c-c++-common/pr51628-1.c        |  29 ++++
 gcc/testsuite/c-c++-common/pr51628-10.c       |  24 +++
 gcc/testsuite/c-c++-common/pr51628-11.c       |  17 ++
 gcc/testsuite/c-c++-common/pr51628-12.c       |  18 ++
 gcc/testsuite/c-c++-common/pr51628-13.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-14.c       |   9 +
 gcc/testsuite/c-c++-common/pr51628-15.c       |  14 ++
 gcc/testsuite/c-c++-common/pr51628-16.c       |  13 ++
 gcc/testsuite/c-c++-common/pr51628-2.c        |  29 ++++
 gcc/testsuite/c-c++-common/pr51628-26.c       |  33 ++++
 gcc/testsuite/c-c++-common/pr51628-27.c       |  12 ++
 gcc/testsuite/c-c++-common/pr51628-28.c       |  31 ++++
 gcc/testsuite/c-c++-common/pr51628-29.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-3.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-30.c       |  23 +++
 gcc/testsuite/c-c++-common/pr51628-31.c       |  16 ++
 gcc/testsuite/c-c++-common/pr51628-32.c       |  19 ++
 gcc/testsuite/c-c++-common/pr51628-4.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-5.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-6.c        |  35 ++++
 gcc/testsuite/c-c++-common/pr51628-7.c        |  29 ++++
 gcc/testsuite/c-c++-common/pr51628-8.c        |  36 ++++
 gcc/testsuite/c-c++-common/pr51628-9.c        |  36 ++++
 gcc/testsuite/c-c++-common/ubsan/align-10.c   |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-2.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-4.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-6.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-7.c    |   2 +-
 gcc/testsuite/c-c++-common/ubsan/align-8.c    |   2 +-
 gcc/testsuite/g++.dg/ubsan/align-2.C          |   2 +-
 gcc/testsuite/gcc.dg/pr51628-17.c             |  10 ++
 gcc/testsuite/gcc.dg/pr51628-18.c             |  23 +++
 gcc/testsuite/gcc.dg/pr51628-19.c             |  26 +++
 gcc/testsuite/gcc.dg/pr51628-20.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-21.c             |  11 ++
 gcc/testsuite/gcc.dg/pr51628-22.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-23.c             |   9 +
 gcc/testsuite/gcc.dg/pr51628-24.c             |  10 ++
 gcc/testsuite/gcc.dg/pr51628-25.c             |   9 +
 .../gcc.target/i386/avx512bw-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu32-2.c     |   2 +-
 .../gcc.target/i386/avx512f-vmovdqu64-2.c     |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu16-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu32-2.c    |   2 +-
 .../gcc.target/i386/avx512vl-vmovdqu64-2.c    |   2 +-
 libgcc/unwind-pe.h                            |   5 +
 55 files changed, 886 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-1.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-10.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-11.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-12.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-13.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-14.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-15.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-16.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-2.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-26.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-27.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-28.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-29.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-3.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-30.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-31.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-32.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-4.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-5.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-6.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-7.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-8.c
 create mode 100644 gcc/testsuite/c-c++-common/pr51628-9.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-17.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-18.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-19.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-20.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-21.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-22.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-23.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-24.c
 create mode 100644 gcc/testsuite/gcc.dg/pr51628-25.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343c0b3..eb0ad60940d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1282,6 +1282,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern bool warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_for_address_or_pointer_of_packed_member (bool, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 798ad1bcb39..ba508425233 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2616,3 +2616,167 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
 }
+
+/* Return struct or union type if the alignment of data memeber, FIELD,
+   is less than the alignment of TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_alignment_of_packed_member (tree type, tree field)
+{
+  /* Check alignment of the data member.  */
+  if (TREE_CODE (field) == FIELD_DECL
+      && (DECL_PACKED (field)
+	  || TYPE_PACKED (TREE_TYPE (field))))
+    {
+      /* Check the expected alignment against the field alignment.  */
+      unsigned int type_align = TYPE_ALIGN (type);
+      tree context = DECL_CONTEXT (field);
+      unsigned int record_align = TYPE_ALIGN (context);
+      if ((record_align % type_align) != 0)
+	return context;
+      tree field_off = byte_position (field);
+      if (!multiple_of_p (TREE_TYPE (field_off), field_off,
+			  size_int (type_align / BITS_PER_UNIT)))
+	return context;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return struct or union type if the right hand value, RHS, takes the
+   unaligned address of packed member of struct or union when assigning
+   to TYPE.  Otherwise, return NULL_TREE.  */
+
+static tree
+check_address_of_packed_member (tree type, tree rhs)
+{
+  if (INDIRECT_REF_P (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+
+  if (TREE_CODE (rhs) == ADDR_EXPR)
+    rhs = TREE_OPERAND (rhs, 0);
+
+  tree context = NULL_TREE;
+
+  /* Check alignment of the object.  */
+  while (handled_component_p (rhs))
+    {
+      if (TREE_CODE (rhs) == COMPONENT_REF)
+	{
+	  tree field = TREE_OPERAND (rhs, 1);
+	  context = check_alignment_of_packed_member (type, field);
+	  if (context)
+	    break;
+	}
+      rhs = TREE_OPERAND (rhs, 0);
+    }
+
+  return context;
+}
+
+/* Check and warn if the right hand value, RHS, takes the unaligned
+   address of packed member of struct or union when assigning to TYPE.  */
+
+static void
+check_and_warn_address_of_packed_member (tree type, tree rhs)
+{
+  if (TREE_CODE (rhs) != COND_EXPR)
+    {
+      while (TREE_CODE (rhs) == COMPOUND_EXPR)
+	rhs = TREE_OPERAND (rhs, 1);
+
+      tree context = check_address_of_packed_member (type, rhs);
+      if (context)
+	{
+	  location_t loc = EXPR_LOC_OR_LOC (rhs, input_location);
+	  warning_at (loc, OPT_Waddress_of_packed_member,
+		      "taking address of packed member of %qT may result "
+		      "in an unaligned pointer value",
+		      context);
+	}
+      return;
+    }
+
+  /* Check the THEN path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 1));
+
+  /* Check the ELSE path.  */
+  check_and_warn_address_of_packed_member (type, TREE_OPERAND (rhs, 2));
+}
+
+/* Warn if the right hand value, RHS:
+   1. For CONVERT_P == true, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+   2. For CONVERT_P == false, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool convert_p, tree type,
+					      tree rhs)
+{
+  if (!warn_address_of_packed_member)
+    return;
+
+  /* Don't warn if we don't assign RHS to a pointer.  */
+  if (!POINTER_TYPE_P (type))
+    return;
+
+  while (TREE_CODE (rhs) == COMPOUND_EXPR)
+    rhs = TREE_OPERAND (rhs, 1);
+
+  if (convert_p)
+    {
+      bool rhspointer_p;
+      tree rhstype;
+
+      /* Check the original type of RHS.  */
+      switch (TREE_CODE (rhs))
+	{
+	case PARM_DECL:
+	case VAR_DECL:
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = POINTER_TYPE_P (rhstype);
+	  break;
+	case NOP_EXPR:
+	  rhs = TREE_OPERAND (rhs, 0);
+	  if (TREE_CODE (rhs) == ADDR_EXPR)
+	    rhs = TREE_OPERAND (rhs, 0);
+	  rhstype = TREE_TYPE (rhs);
+	  rhspointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
+	  break;
+	default:
+	  return;
+	}
+
+      if (rhspointer_p && TYPE_PACKED (TREE_TYPE (rhstype)))
+	{
+	  unsigned int type_align = TYPE_ALIGN_UNIT (TREE_TYPE (type));
+	  unsigned int rhs_align = TYPE_ALIGN_UNIT (TREE_TYPE (rhstype));
+	  if ((rhs_align % type_align) != 0)
+	    {
+	      location_t location = EXPR_LOC_OR_LOC (rhs, input_location);
+	      warning_at (location, OPT_Waddress_of_packed_member,
+			  "converting a packed %qT pointer (alignment %d) "
+			  "to %qT (alignment %d) may may result in an "
+			  "unaligned pointer value",
+			  rhstype, rhs_align, type, type_align);
+	      tree decl = TYPE_STUB_DECL (TREE_TYPE (rhstype));
+	      inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	      decl = TYPE_STUB_DECL (TREE_TYPE (type));
+	      if (decl)
+		inform (DECL_SOURCE_LOCATION (decl), "defined here");
+	    }
+	}
+    }
+  else
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+
+      check_and_warn_address_of_packed_member (type, rhs);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 07ff1c84f96..22ccf910a85 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -625,6 +625,10 @@ Wincompatible-pointer-types
 C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning
 Warn when there is a conversion between pointers that have incompatible types.
 
+Waddress-of-packed-member
+C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning
+Warn when the address of packed member of struct or union is taken.
+
 Winit-self
 C ObjC C++ ObjC++ Var(warn_init_self) Warning LangEnabledBy(C++ ObjC++,Wall)
 Warn about variables which are initialized to themselves.
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 1a897273088..da4a8169d56 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6724,7 +6724,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     }
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    return rhs;
+    {
+      warn_for_address_or_pointer_of_packed_member (false, type,
+						    orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7279,6 +7283,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	    }
 	}
 
+      /* If RHS is't an address, check pointer or array of packed
+	 struct or union.  */
+      warn_for_address_or_pointer_of_packed_member
+	(TREE_CODE (orig_rhs) != ADDR_EXPR, type, orig_rhs);
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36b604..40ffc863091 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7618,6 +7618,9 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	}
       maybe_warn_parm_abi (type, cp_expr_loc_or_loc (val, input_location));
     }
+
+  warn_for_address_or_pointer_of_packed_member (false, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 47ddad16fc1..70b60a928f4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9036,6 +9036,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (false, type, rhs);
+
   return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
 					    complain, flags);
 }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ac2ee59d92c..14365fba501 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -281,7 +281,8 @@ Objective-C and Objective-C++ Dialects}.
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
--w  -Wextra  -Wall  -Waddress  -Waggregate-return  -Waligned-new @gol
+-w  -Wextra  -Wall  -Waddress  -Waddress-of-packed-member @gol
+-Waggregate-return  -Waligned-new @gol
 -Walloc-zero  -Walloc-size-larger-than=@var{byte-size} @gol
 -Walloca  -Walloca-larger-than=@var{byte-size} @gol
 -Wno-aggressive-loop-optimizations  -Warray-bounds  -Warray-bounds=@var{n} @gol
@@ -310,7 +311,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-y2k  -Wframe-address @gol
 -Wframe-larger-than=@var{byte-size}  -Wno-free-nonheap-object @gol
 -Wjump-misses-init @gol
--Wif-not-aligned @gol
+-Whsa  -Wif-not-aligned @gol
 -Wignored-qualifiers  -Wignored-attributes  -Wincompatible-pointer-types @gol
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n} @gol
 -Wimplicit-function-declaration  -Wimplicit-int @gol
@@ -358,7 +359,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wuseless-cast  -Wvariadic-macros  -Wvector-operation-performance @gol
 -Wvla  -Wvla-larger-than=@var{byte-size}  -Wvolatile-register-var @gol
 -Wwrite-strings @gol
--Wzero-as-null-pointer-constant  -Whsa}
+-Wzero-as-null-pointer-constant}
 
 @item C and Objective-C-only Warning Options
 @gccoptlist{-Wbad-function-cast  -Wmissing-declarations @gol
@@ -6981,6 +6982,13 @@ behavior and are not portable in C, so they usually indicate that the
 programmer intended to use @code{strcmp}.  This warning is enabled by
 @option{-Wall}.
 
+@item -Waddress-of-packed-member
+@opindex Waddress-of-packed-member
+@opindex Wno-address-of-packed-member
+Warn when the address of packed member of struct or union is taken,
+which usually results in an unaligned pointer value.  This is
+enabled by default.
+
 @item -Wlogical-op
 @opindex Wlogical-op
 @opindex Wno-logical-op
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-1.c b/gcc/testsuite/c-c++-common/asan/misalign-1.c
index 5cd605ac045..ebeb0306706 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-1.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/asan/misalign-2.c b/gcc/testsuite/c-c++-common/asan/misalign-2.c
index a6ed49bac05..b27e22d35a8 100644
--- a/gcc/testsuite/c-c++-common/asan/misalign-2.c
+++ b/gcc/testsuite/c-c++-common/asan/misalign-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run { target { ilp32 || lp64 } } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -Wno-address-of-packed-member" } } */
 /* { dg-additional-options "-fno-omit-frame-pointer" { target *-*-darwin* } } */
 /* { dg-shouldfail "asan" } */
 
diff --git a/gcc/testsuite/c-c++-common/pr51628-1.c b/gcc/testsuite/c-c++-common/pr51628-1.c
new file mode 100644
index 00000000000..5324f9cc964
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-1.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-10.c b/gcc/testsuite/c-c++-common/pr51628-10.c
new file mode 100644
index 00000000000..085fe1608c4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-10.c
@@ -0,0 +1,24 @@
+/* PR c/51628.  */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+struct pair_t
+{
+  char c;
+  __int128_t i;
+} __attribute__ ((packed));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__((packed)) unaligned_int128_t;
+
+struct pair_t p = {0, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *) &p.i;
+
+int 
+main() 
+{
+  addr->value = ~(__int128_t)0;
+  return (p.i != 1) ? 0 : 1;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-11.c b/gcc/testsuite/c-c++-common/pr51628-11.c
new file mode 100644
index 00000000000..7661232ac88
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-11.c
@@ -0,0 +1,17 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[12];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
diff --git a/gcc/testsuite/c-c++-common/pr51628-12.c b/gcc/testsuite/c-c++-common/pr51628-12.c
new file mode 100644
index 00000000000..bc221fa87ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-12.c
@@ -0,0 +1,18 @@
+/* PR c/51628.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O" } */
+
+struct tuple_t
+{
+  char c[10];
+  __int128_t i;
+} __attribute__((packed, aligned (8)));
+
+typedef struct unaligned_int128_t_
+{
+  __int128_t value;
+} __attribute__ ((packed, aligned(4))) unaligned_int128_t;
+
+struct tuple_t p = {{0}, 1};
+unaligned_int128_t *addr = (unaligned_int128_t *)(&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-13.c b/gcc/testsuite/c-c++-common/pr51628-13.c
new file mode 100644
index 00000000000..0edd5e7f84d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-13.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* h4 (struct C *p) { return &p->b.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-14.c b/gcc/testsuite/c-c++-common/pr51628-14.c
new file mode 100644
index 00000000000..f50378b8651
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-14.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+void* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/c-c++-common/pr51628-15.c b/gcc/testsuite/c-c++-common/pr51628-15.c
new file mode 100644
index 00000000000..bcac6d70ad5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-15.c
@@ -0,0 +1,14 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+int*
+f (struct A *p, int *q)
+{
+  return q ? q : &p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-16.c b/gcc/testsuite/c-c++-common/pr51628-16.c
new file mode 100644
index 00000000000..cd502fe76b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-16.c
@@ -0,0 +1,13 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct __attribute__ ((packed)) A { int i; };
+struct B {
+  struct A a;
+} b;
+
+int *p = (int*)&b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+int *q = (int*)&b.a;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-2.c b/gcc/testsuite/c-c++-common/pr51628-2.c
new file mode 100644
index 00000000000..abfb84ddd05
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-2.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (8)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+  bar (p0);
+  p1 = &arr[1].i;
+  bar (p1);
+  bar (&p.i);
+  x = &p.i;
+  return &p.i;
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-26.c b/gcc/testsuite/c-c++-common/pr51628-26.c
new file mode 100644
index 00000000000..2042379860a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-26.c
@@ -0,0 +1,33 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+struct A p = {1};
+int *addr;
+
+int i, j;
+
+void
+foo1 (void)
+{
+  addr = (i = -1, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo2 (void)
+{
+  addr = (i = -1, j = -2, &p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+void
+foo3 (void)
+{
+  addr = (i = -1, (j = -2, &p.i));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-27.c b/gcc/testsuite/c-c++-common/pr51628-27.c
new file mode 100644
index 00000000000..9ae1efd7afb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-27.c
@@ -0,0 +1,12 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; } __attribute__ ((packed));
+struct B { struct A a; };
+struct C { struct B b; };
+
+extern struct C *p;
+
+int* g8 (void) { return &p->b.a.i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-28.c b/gcc/testsuite/c-c++-common/pr51628-28.c
new file mode 100644
index 00000000000..3cc1fec1f71
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-28.c
@@ -0,0 +1,31 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { 
+  int i;
+} __attribute__ ((packed));
+
+int *
+foo3 (struct A *p1, int *q1, int *q2, struct A *p2) 
+{
+  return (q1 
+	  ? &p1->i
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2 ? &p2->i : q2));
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo4 (struct A *p1, int **q1, int *q2, int *q3, struct A *p2)
+{
+  return (q1
+	  ? (*q1 = q2, &p1->i)
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	  : (q2
+	     ? (*q1 = &p1->i,
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+		*q2 = 2, &p2->i)
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+	     : q2));
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-29.c b/gcc/testsuite/c-c++-common/pr51628-29.c
new file mode 100644
index 00000000000..94b3722d2c8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-29.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+g8 (void)
+{
+  return &p->b.a.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-3.c b/gcc/testsuite/c-c++-common/pr51628-3.c
new file mode 100644
index 00000000000..0ea94c845a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-3.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed, aligned (2)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-30.c b/gcc/testsuite/c-c++-common/pr51628-30.c
new file mode 100644
index 00000000000..578edf4e8f9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-30.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A { __complex int i; };
+struct B { struct A a; };
+struct C { struct B b __attribute__ ((packed)); };
+
+extern struct C *p;
+
+int*
+foo1 (void)
+{
+  return &__real(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
+
+int*
+foo2 (void)
+{
+  return &__imag(p->b.a.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-31.c b/gcc/testsuite/c-c++-common/pr51628-31.c
new file mode 100644
index 00000000000..9730f53f582
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-31.c
@@ -0,0 +1,16 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+struct X
+{
+  v4si x;
+} __attribute__((packed)) x;
+
+int *
+foo()
+{
+  return &x.x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-32.c b/gcc/testsuite/c-c++-common/pr51628-32.c
new file mode 100644
index 00000000000..a62e57d5b46
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-32.c
@@ -0,0 +1,19 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct A
+{
+   int i;
+};
+
+struct B
+{
+   char c;
+   __attribute ((packed)) struct A ar[4];
+};
+
+struct B b;
+
+int *p = &b.ar[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/c-c++-common/pr51628-4.c b/gcc/testsuite/c-c++-common/pr51628-4.c
new file mode 100644
index 00000000000..c4c1fb72d6d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-4.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-5.c b/gcc/testsuite/c-c++-common/pr51628-5.c
new file mode 100644
index 00000000000..9d7c309a0ef
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-5.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-6.c b/gcc/testsuite/c-c++-common/pr51628-6.c
new file mode 100644
index 00000000000..52aa07a4cf3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-6.c
@@ -0,0 +1,35 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i;
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (void)
+{
+  struct pair_t arr[2] = { { 1, 10 }, { 2, 20 } };
+  int *p0, *p1;
+  p0 = &arr[0].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &arr[1].i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (&p.i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-7.c b/gcc/testsuite/c-c++-common/pr51628-7.c
new file mode 100644
index 00000000000..ae4a681f966
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-7.c
@@ -0,0 +1,29 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+  bar (p0);
+  p1 = &p->i[1];
+  bar (p1);
+  bar (p->i);
+  bar (&p->i[2]);
+  x = p->i;
+  return &p->i[3];
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-8.c b/gcc/testsuite/c-c++-common/pr51628-8.c
new file mode 100644
index 00000000000..cc2dae096ae
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-8.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  char x;
+  int i[4];
+} __attribute__ ((packed, aligned (4)));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr51628-9.c b/gcc/testsuite/c-c++-common/pr51628-9.c
new file mode 100644
index 00000000000..0470aa3b93d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr51628-9.c
@@ -0,0 +1,36 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+struct pair_t
+{
+  int x;
+  int i[4];
+} __attribute__ ((packed));
+
+extern struct pair_t p;
+extern int *x;
+extern void bar (int *);
+
+int *addr = p.i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+
+int *
+foo (struct pair_t *p)
+{
+  int *p0, *p1;
+  p0 = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p0);
+  p1 = &p->i[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (p1);
+  bar (p->i);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  bar (&p->i[2]);
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  x = p->i;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  return &p->i[3];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-10.c b/gcc/testsuite/c-c++-common/ubsan/align-10.c
index 56ae9ebfe30..6210533173c 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-10.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct R { int a; } r;
 struct S { struct R a; char b; long long c; short d[10]; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-2.c b/gcc/testsuite/c-c++-common/ubsan/align-2.c
index 071de8c202a..336b1c3c907 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-2.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=alignment" } */
+/* { dg-options "-fsanitize=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-4.c b/gcc/testsuite/c-c++-common/ubsan/align-4.c
index 3252595d330..d5feeee29c6 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-4.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-fsanitize=null,alignment" } */
+/* { dg-options "-fsanitize=null,alignment -Wno-address-of-packed-member" } */
 
 #include "align-2.c"
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-6.c b/gcc/testsuite/c-c++-common/ubsan/align-6.c
index 3364746fb27..0302b7b8894 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-6.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-recover=alignment -Wno-address-of-packed-member" } */
 
 struct S { int a; char b; long long c; short d[10]; };
 struct T { char a; long long b; };
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-7.c b/gcc/testsuite/c-c++-common/ubsan/align-7.c
index ec4e87f56d5..dd1e8c91cef 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-7.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-7.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fno-sanitize-recover=alignment -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/align-8.c b/gcc/testsuite/c-c++-common/ubsan/align-8.c
index 61c1ceb6682..5fe0e0fe931 100644
--- a/gcc/testsuite/c-c++-common/ubsan/align-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/align-8.c
@@ -1,6 +1,6 @@
 /* Limit this to known non-strict alignment targets.  */
 /* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
-/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -fdump-tree-sanopt-details" } */
+/* { dg-options "-O -fsanitize=alignment -fsanitize-undefined-trap-on-error -Wno-address-of-packed-member -fdump-tree-sanopt-details" } */
 /* { dg-skip-if "" { *-*-* } { "-flto -fno-fat-lto-objects" } } */
 /* { dg-shouldfail "ubsan" } */
 
diff --git a/gcc/testsuite/g++.dg/ubsan/align-2.C b/gcc/testsuite/g++.dg/ubsan/align-2.C
index 3e4f5485d02..c97ede88392 100644
--- a/gcc/testsuite/g++.dg/ubsan/align-2.C
+++ b/gcc/testsuite/g++.dg/ubsan/align-2.C
@@ -1,6 +1,6 @@
 // Limit this to known non-strict alignment targets.
 // { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } }
-// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -std=c++11" }
+// { dg-options "-fsanitize=alignment -Wall -Wno-unused-variable -Wno-address-of-packed-member -std=c++11" }
 
 typedef const long int L;
 struct S { long int l; char buf[1 + sizeof (int) + sizeof (L)]; } s;
diff --git a/gcc/testsuite/gcc.dg/pr51628-17.c b/gcc/testsuite/gcc.dg/pr51628-17.c
new file mode 100644
index 00000000000..0be95b2294e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-17.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+long* f8 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-18.c b/gcc/testsuite/gcc.dg/pr51628-18.c
new file mode 100644
index 00000000000..03a04eff75c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-18.c
@@ -0,0 +1,23 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    int c[k];
+    int x[n];
+  } __attribute__ ((packed, aligned (4)));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+  foo (p0);
+  p1 = &p->x[1];
+  foo (p1);
+  return &p->x[1];
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-19.c b/gcc/testsuite/gcc.dg/pr51628-19.c
new file mode 100644
index 00000000000..7ff03e85cea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-19.c
@@ -0,0 +1,26 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo (int *);
+
+int *
+bar (int n, int k, void *ptr)
+{
+  struct A
+  {
+    char c[k];
+    int x[n];
+  } __attribute__ ((packed));
+  struct A *p = (struct A *) ptr;
+
+  int *p0, *p1;
+  p0 = p->x;
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p0);
+  p1 = &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+  foo (p1);
+  return &p->x[1];
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr51628-20.c b/gcc/testsuite/gcc.dg/pr51628-20.c
new file mode 100644
index 00000000000..80888283b73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-20.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C *p;
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-21.c b/gcc/testsuite/gcc.dg/pr51628-21.c
new file mode 100644
index 00000000000..3077e72c8d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-21.c
@@ -0,0 +1,11 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+extern struct C p[];
+
+long* g8 (void) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-22.c b/gcc/testsuite/gcc.dg/pr51628-22.c
new file mode 100644
index 00000000000..1bd5d791639
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-22.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+int* g4 (struct C *p) { return &p->b; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-23.c b/gcc/testsuite/gcc.dg/pr51628-23.c
new file mode 100644
index 00000000000..5709be60ac8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-23.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+char* f0 (struct A *p) { return &p->i; }
diff --git a/gcc/testsuite/gcc.dg/pr51628-24.c b/gcc/testsuite/gcc.dg/pr51628-24.c
new file mode 100644
index 00000000000..3ad99cd2f16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-24.c
@@ -0,0 +1,10 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct A {
+  int i;
+} __attribute__ ((packed));
+
+short* f2 (struct A *p) { return &p->i; }
+/* { dg-warning "may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/pr51628-25.c b/gcc/testsuite/gcc.dg/pr51628-25.c
new file mode 100644
index 00000000000..2fc5c028711
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr51628-25.c
@@ -0,0 +1,9 @@
+/* PR c/51628.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wno-incompatible-pointer-types" } */
+
+struct B { int i; };
+struct C { struct B b; } __attribute__ ((packed));
+
+long* g8 (struct C *p) { return p; }
+/* { dg-warning "may may result in an unaligned pointer value" "" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
index a61609c40d2..c6e3ebdc507 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw" } */
+/* { dg-options "-O2 -mavx512bw -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512bw } */
 
 #define AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
index f2edc3dff7b..95a657fc5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
index 14176965ace..954b091d976 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512f" } */
+/* { dg-options "-O2 -mavx512f -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512f } */
 
 #define AVX512F
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
index 45ae83d4552..81465f8d9a0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu16-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 /* { dg-require-effective-target avx512bw } */
 
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
index 4b928d0cd42..19390664bd0 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu32-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
index 1863ed3616f..aea0c12a5ff 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vmovdqu64-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2 -mavx512vl" } */
+/* { dg-options "-O2 -mavx512vl -Wno-address-of-packed-member" } */
 /* { dg-require-effective-target avx512vl } */
 
 #define AVX512VL
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index dd5ae95fc2c..05c2fb4dd50 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -177,6 +177,9 @@ read_sleb128 (const unsigned char *p, _sleb128_t *val)
    The function returns P incremented past the value.  BASE is as given
    by base_of_encoded_value for this encoding in the appropriate context.  */
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 static const unsigned char *
 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
 			      const unsigned char *p, _Unwind_Ptr *val)
@@ -270,6 +273,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
   return p;
 }
 
+#pragma GCC diagnostic pop
+
 #ifndef NO_BASE_OF_ENCODED_VALUE
 
 /* Like read_encoded_value_with_base, but get the base from the context
-- 
2.19.2


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

* Re: V10 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-20 20:07                             ` V10 " H.J. Lu
@ 2018-12-20 21:31                               ` Jason Merrill
  2018-12-20 21:47                                 ` H.J. Lu
  0 siblings, 1 reply; 23+ messages in thread
From: Jason Merrill @ 2018-12-20 21:31 UTC (permalink / raw)
  To: H.J. Lu
  Cc: Sandra Loosemore, Richard Guenther, Joseph S. Myers,
	Martin Sebor, GCC Patches

On 12/20/18 2:52 PM, H.J. Lu wrote:
> On Thu, Dec 20, 2018 at 11:28 AM Jason Merrill <jason@redhat.com> wrote:
>>
>> On 12/19/18 12:35 PM, H.J. Lu wrote:
>>> +  while (handled_component_p (rhs))
>>> +    {
>>> +      if (TREE_CODE (rhs) == COMPONENT_REF)
>>> +     break;
>>> +      rhs = TREE_OPERAND (rhs, 0);
>>> +    }
>>> +
>>> +  if (TREE_CODE (rhs) != COMPONENT_REF)
>>> +    return NULL_TREE;
>>> +
>>> +  object = TREE_OPERAND (rhs, 0);
>>> +  field = TREE_OPERAND (rhs, 1);
>>> +
>>> +  tree context = check_alignment_of_packed_member (type, field);
>>> +  if (context)
>>> +    return context;
>>
>> All the above looks unnecessary; it will be handled by the loop below.
>>
>>> +  /* Check alignment of the object.  */
>>> +  while (handled_component_p (object))
>>> +    {
>>> +      if (TREE_CODE (object) == COMPONENT_REF)
>>> +     {
>>> +       do
>>> +         {
>>> +           field = TREE_OPERAND (object, 1);
>>> +           context = check_alignment_of_packed_member (type, field);
>>> +           if (context)
>>> +             return context;
>>> +           object = TREE_OPERAND (object, 0);
>>> +         }
>>> +       while (TREE_CODE (object) == COMPONENT_REF);
>>
>> This inner loop also seems unnecessary.
>>
>>> +     }
>>> +      else
>>> +     object = TREE_OPERAND (object, 0);
>>> +    }
>>
>> Jason
> 
> I changed it to
> 
> static tree
> check_address_of_packed_member (tree type, tree rhs)
> {
>    if (INDIRECT_REF_P (rhs))
>      rhs = TREE_OPERAND (rhs, 0);
> 
>    if (TREE_CODE (rhs) == ADDR_EXPR)
>      rhs = TREE_OPERAND (rhs, 0);
> 
>    tree context = NULL_TREE;
> 
>    /* Check alignment of the object.  */
>    while (handled_component_p (rhs))
>      {
>        if (TREE_CODE (rhs) == COMPONENT_REF)
>          {
>            tree field = TREE_OPERAND (rhs, 1);
>            context = check_alignment_of_packed_member (type, field);
>            if (context)
>              break;
>          }
>        rhs = TREE_OPERAND (rhs, 0);
>      }
> 
>    return context;
> }
> 
> Here is the updated patch.  OK for trunk?

OK.

Jason

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

* Re: V10 [PATCH] C/C++: Add -Waddress-of-packed-member
  2018-12-20 21:31                               ` Jason Merrill
@ 2018-12-20 21:47                                 ` H.J. Lu
  0 siblings, 0 replies; 23+ messages in thread
From: H.J. Lu @ 2018-12-20 21:47 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Sandra Loosemore, Richard Guenther, Joseph S. Myers,
	Martin Sebor, GCC Patches

On Thu, Dec 20, 2018 at 1:28 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 12/20/18 2:52 PM, H.J. Lu wrote:
> > On Thu, Dec 20, 2018 at 11:28 AM Jason Merrill <jason@redhat.com> wrote:
> >>
> >> On 12/19/18 12:35 PM, H.J. Lu wrote:
> >>> +  while (handled_component_p (rhs))
> >>> +    {
> >>> +      if (TREE_CODE (rhs) == COMPONENT_REF)
> >>> +     break;
> >>> +      rhs = TREE_OPERAND (rhs, 0);
> >>> +    }
> >>> +
> >>> +  if (TREE_CODE (rhs) != COMPONENT_REF)
> >>> +    return NULL_TREE;
> >>> +
> >>> +  object = TREE_OPERAND (rhs, 0);
> >>> +  field = TREE_OPERAND (rhs, 1);
> >>> +
> >>> +  tree context = check_alignment_of_packed_member (type, field);
> >>> +  if (context)
> >>> +    return context;
> >>
> >> All the above looks unnecessary; it will be handled by the loop below.
> >>
> >>> +  /* Check alignment of the object.  */
> >>> +  while (handled_component_p (object))
> >>> +    {
> >>> +      if (TREE_CODE (object) == COMPONENT_REF)
> >>> +     {
> >>> +       do
> >>> +         {
> >>> +           field = TREE_OPERAND (object, 1);
> >>> +           context = check_alignment_of_packed_member (type, field);
> >>> +           if (context)
> >>> +             return context;
> >>> +           object = TREE_OPERAND (object, 0);
> >>> +         }
> >>> +       while (TREE_CODE (object) == COMPONENT_REF);
> >>
> >> This inner loop also seems unnecessary.
> >>
> >>> +     }
> >>> +      else
> >>> +     object = TREE_OPERAND (object, 0);
> >>> +    }
> >>
> >> Jason
> >
> > I changed it to
> >
> > static tree
> > check_address_of_packed_member (tree type, tree rhs)
> > {
> >    if (INDIRECT_REF_P (rhs))
> >      rhs = TREE_OPERAND (rhs, 0);
> >
> >    if (TREE_CODE (rhs) == ADDR_EXPR)
> >      rhs = TREE_OPERAND (rhs, 0);
> >
> >    tree context = NULL_TREE;
> >
> >    /* Check alignment of the object.  */
> >    while (handled_component_p (rhs))
> >      {
> >        if (TREE_CODE (rhs) == COMPONENT_REF)
> >          {
> >            tree field = TREE_OPERAND (rhs, 1);
> >            context = check_alignment_of_packed_member (type, field);
> >            if (context)
> >              break;
> >          }
> >        rhs = TREE_OPERAND (rhs, 0);
> >      }
> >
> >    return context;
> > }
> >
> > Here is the updated patch.  OK for trunk?
>
> OK.
>

Checked in.  Thanks for everyone, especially Jason.

-- 
H.J.

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

end of thread, other threads:[~2018-12-20 21:43 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-25 15:47 V4 [PATCH] C/C++: Add -Waddress-of-packed-member H.J. Lu
2018-11-04 15:16 ` PING: " H.J. Lu
2018-11-25 14:38   ` PING^2: " H.J. Lu
2018-12-13 20:50 ` Jason Merrill
2018-12-14  0:09   ` V5 " H.J. Lu
2018-12-14 22:10     ` Jason Merrill
2018-12-14 22:48       ` V6 " H.J. Lu
2018-12-17  9:39         ` Richard Biener
2018-12-17 12:43           ` H.J. Lu
2018-12-17 13:34             ` Richard Biener
2018-12-17 13:53             ` Jason Merrill
2018-12-18 14:11               ` V7 " H.J. Lu
2018-12-18 20:36                 ` Jason Merrill
2018-12-18 21:13                   ` V8 " H.J. Lu
2018-12-18 22:14                     ` Jason Merrill
2018-12-19 14:52                       ` H.J. Lu
2018-12-19 17:36                         ` V9 " H.J. Lu
2018-12-20 19:40                           ` Jason Merrill
2018-12-20 20:07                             ` V10 " H.J. Lu
2018-12-20 21:31                               ` Jason Merrill
2018-12-20 21:47                                 ` H.J. Lu
2018-12-19  3:19                     ` V8 " Sandra Loosemore
2018-12-19 14:53                       ` H.J. Lu

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).