diff mbox series

V3 [PATCH] C/C++: Add -Waddress-of-packed-member

Message ID CAMe9rOr7eL5kJaoBTvkszGh4V-3x_UNrQR0LyRowswYbCBqHvQ@mail.gmail.com
State New
Headers show
Series V3 [PATCH] C/C++: Add -Waddress-of-packed-member | expand

Commit Message

H.J. Lu July 23, 2018, 9:24 p.m. UTC
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.

Tested on Linux/x86-64 and Linux/i686.  OK for trunk.

Thanks.

Comments

Jason Merrill Aug. 31, 2018, 9:04 p.m. UTC | #1
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]

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

> +  /* 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?

> +  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?

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

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.

Jason
diff mbox series

Patch

From 2ddae2d57d2875e80c9186b281edfabfddb42e86 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]
 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:33: warning: returning ‘struct C *’ from a function with incompatible return type ‘long int *’ [-Wincompatible-pointer-types]
 long* g8 (struct C *p) { return p; }
                                 ^
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]
c.i:2:8: note: defined here
 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.
	(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.
	* 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                         | 173 ++++++++++++++++++
 gcc/c-family/c.opt                            |   4 +
 gcc/c/c-typeck.c                              |  10 +-
 gcc/cp/call.c                                 |   3 +
 gcc/cp/typeck.c                               |   2 +
 gcc/doc/invoke.texi                           |   9 +-
 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-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 +
 49 files changed, 774 insertions(+), 17 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-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 fcec95b4f3b..620f0bfcb50 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1271,6 +1271,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 d34d6672937..dbf7a8e16b0 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2606,3 +2606,176 @@  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 (TREE_CODE (base) == ARRAY_REF)
+	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;
+  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;
+}
+
+/* Warn if the right hand value, RHS:
+   1. For ADDRESS_P == true, is an address which takes the unaligned
+      address of packed member of struct or union when assigning to TYPE.
+   2. For ADDRESS_P == false, is a pointer value which isn't aligned to a
+      pointer type TYPE.
+*/
+
+void
+warn_for_address_or_pointer_of_packed_member (bool address_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 (address_p)
+    {
+      /* Get the type of the pointer pointing to.  */
+      type = TREE_TYPE (type);
+
+      if (TREE_CODE (rhs) == NOP_EXPR)
+	rhs = TREE_OPERAND (rhs, 0);
+    }
+  else
+    {
+      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 increases the "
+			  "alignment of %qT pointer from %d to %d",
+			  rhstype, type, rhs_align, 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");
+	    }
+	}
+      return;
+    }
+
+  tree context;
+
+  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);
+	}
+    }
+  else
+    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);
+    }
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index d6148380710..04643ad5684 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -612,6 +612,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 90ae306c99a..b437b89cf5a 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -6514,7 +6514,10 @@  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 (true, type, orig_rhs);
+      return rhs;
+    }
 
   if (coder == VOID_TYPE)
     {
@@ -7001,6 +7004,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 209c1fd2f0e..ce8a30500e0 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7470,6 +7470,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 (true, type, val);
+
   return val;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 1335da5e9bc..9cd85b33cbd 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8914,6 +8914,8 @@  convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
+  warn_for_address_or_pointer_of_packed_member (true, 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 1dcdfb51c47..5f2b7cabc38 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -275,7 +275,7 @@  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  @gol
+-w -Wextra -Wall -Waddress -Waddress-of-packed-member -Waggregate-return @gol
 -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
@@ -6581,6 +6581,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-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..7d7865313c2
--- /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 "increases the alignment of '.*' pointer from 1 to " "" { 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..7fdcdaed77d
--- /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 "increases the alignment of '.*' pointer from 1 to " "" { 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..6bd78a8811c
--- /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 "increases the alignment of '.*' pointer from 1 to " "" { 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