On Fri, May 18, 2018 at 7:36 AM, H.J. Lu <hjl.to...@gmail.com> wrote:
> On Thu, May 17, 2018 at 10:32:56AM -0700, H.J. Lu wrote:
>> On Mon, May 14, 2018 at 8:00 PM, Martin Sebor <mse...@gmail.com> wrote:
>> > On 05/14/2018 01:10 PM, H.J. Lu wrote:
>> >>
>> >> On Mon, May 14, 2018 at 10:40 AM, H.J. Lu <hjl.to...@gmail.com> wrote:
>> >>
>> >>>>>> $ 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: taking value of packed 'struct C *' may result in
>> >>>>>> an
>> >>>>>> unaligned pointer value [-Waddress-of-packed-member]
>> >>>>
>> >>>>
>> >>>>                              ^^^^^
>> >>>> That should read "taking address" (not value) but...
>> >>>
>> >>>
>> >>> The value of 'struct C *' is an address. There is no address taken here.
>> >>>
>> >>>> ...to help explain the problem I would suggest to mention the expected
>> >>>> and actual alignment in the warning message.  E.g.,
>> >>>>
>> >>>>   storing the address of a packed 'struct C' in 'struct C *' increases
>> >>>> the
>> >>>> alignment of the pointer from 1 to 4.
>> >>>
>> >>>
>> >>> I will take a look.
>> >>>
>> >>>> (IIUC, the source type and destination type need not be the same so
>> >>>> including both should be helpful in those cases.)
>> >>>>
>> >>>> Adding a note pointing to the declaration of either the struct or
>> >>>> the member would help users find it if it's a header far removed
>> >>>> from the point of use.
>> >>>
>> >>>
>> >>> I will see what I can do.
>> >>
>> >>
>> >> How about this
>> >>
>> >> [hjl@gnu-skx-1 pr51628]$ cat n9.i
>> >> struct B { int i; };
>> >> struct C { struct B b; } __attribute__ ((packed));
>> >>
>> >> long* g8 (struct C *p) { return p; }
>> >> [hjl@gnu-skx-1 pr51628]$
>> >> /export/build/gnu/gcc-test/build-x86_64-linux/gcc/xgcc
>> >> -B/export/build/gnu/gcc-test/build-x86_64-linux/gcc/ -O2 -S n9.i
>> >> n9.i: In function ‘g8’:
>> >> n9.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; }
>> >>                                  ^
>> >> n9.i:4:33: warning: taking value of packed ‘struct C *’ increases the
>> >> alignment of the pointer from 1 to 8 [-Waddress-of-packed-member]
>> >> n9.i:2:8: note: defined here
>> >>  struct C { struct B b; } __attribute__ ((packed));
>> >
>> >
>> > Mentioning the alignments looks good.
>> >
>> > I still find the "taking value" phrasing odd.  I think we would
>> > describe what's going on as "converting a pointer to a packed C
>> > to a pointer to C (with an alignment of 8)" so I'd suggest to
>> > use the term converting instead.
>>
>> How about this?
>>
>> [hjl@gnu-skx-1 pr51628]$ cat n12.i
>> struct B { int i; };
>> struct C { struct B b; } __attribute__ ((packed));
>>
>> struct B* g8 (struct C *p) { return p; }
>> [hjl@gnu-skx-1 pr51628]$ make n12.s
>> /export/build/gnu/gcc-test/build-x86_64-linux/gcc/xgcc
>> -B/export/build/gnu/gcc-test/build-x86_64-linux/gcc/ -O2 -S n12.i
>> n12.i: In function ‘g8’:
>> n12.i:4:37: warning: returning ‘struct C *’ from a function with
>> incompatible return type ‘struct B *’ [-Wincompatible-pointer-types]
>>  struct B* g8 (struct C *p) { return p; }
>>                                      ^
>> n12.i:4:37: warning: converting a pointer to packed ‘struct C *’
>> increases the alignment of the pointer to ‘struct B *’ from 1 to 4
>> [-Waddress-of-packed-member]
>> n12.i:2:8: note: defined here
>>  struct C { struct B b; } __attribute__ ((packed));
>>         ^
>> n12.i:1:8: note: defined here
>>  struct B { int i; };
>>         ^
>> [hjl@gnu-skx-1 pr51628]$
>>
>> > I also think mentioning both the source and the destination types
>> > is useful irrespective of -Wincompatible-pointer-types because
>> > the latter is often suppressed using a cast, as in:
>> >
>> >   struct __attribute__ ((packed)) A { int i; };
>> >   struct B {
>> >     struct A a;
>> >   } b;
>> >
>> >   long *p = (long*)&b.a.i;   // -Waddress-of-packed-member
>> >   int *q = (int*)&b.a;       // missing warning
>> >
>> > If the types above were obfuscated by macros, typedefs, or in
>> > C++ template parameters, it could be difficult to figure out
>> > what the type of the member is because neither it nor the name
>> > of the member appears in the message.
>>
>> How about this
>>
>> [hjl@gnu-skx-1 pr51628]$ cat n13.i
>> struct __attribute__ ((packed)) A { int i; };
>> struct B {
>>   struct A a;
>> } b;
>>
>> long *p = (long*)&b.a.i;
>> int *q = (int*)&b.a;
>> [hjl@gnu-skx-1 pr51628]$ make n13.s
>> /export/build/gnu/gcc-test/build-x86_64-linux/gcc/xgcc
>> -B/export/build/gnu/gcc-test/build-x86_64-linux/gcc/ -O2 -S n13.i
>> n13.i:6:18: warning: taking address of packed member of ‘struct A’ may
>> result in an unaligned pointer value [-Waddress-of-packed-member]
>>  long *p = (long*)&b.a.i;
>>                   ^~~~~~
>> n13.i:7:16: warning: taking address of packed member of ‘struct B’ may
>> result in an unaligned pointer value [-Waddress-of-packed-member]
>>  int *q = (int*)&b.a;
>>                 ^~~~
>> [hjl@gnu-skx-1 pr51628]$
>>
>>
>
> Here is the updated patch.  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]
>  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_of_packed_member): New.
>         * c-warn.c (check_address_of_packed_member): New function.
>         (warn_for_address_of_packed_member): Likewise.
>         * c.opt: Add -Wno-address-of-packed-member.
>
> gcc/c/
>
>         PR c/51628
>         * c-typeck.c (warn_for_pointer_of_packed_member): New function.
>         (convert_for_assignment): Call warn_for_address_of_packed_member
>         and warn_for_pointer_of_packed_member.
>
> gcc/cp/
>
>         PR c/51628
>         * call.c (convert_for_arg_passing): Call
>         warn_for_address_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.
>         * 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                         | 119 ++++++++++++++++++
>  gcc/c-family/c.opt                            |   4 +
>  gcc/c/c-typeck.c                              |  64 +++++++++-
>  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-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 +
>  48 files changed, 742 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-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 c266fee74c7..9da96b2e944 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -1270,6 +1270,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_of_packed_member (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 2614eb58f14..f17223af48f 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -2587,3 +2587,122 @@ 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:

When would we get a COMPONENT_REF without an ADDR_EXPR around it?

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

Do we need this check of TYPE_PACKED (TREE_TYPE (field))?  At this
point I'd expect TREE_TYPE (field) == type, and if that type is
packed, then type_align will be 1, which is always OK.

> +    {
> +      /* 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.  */

Shouldn't the above be a loop, rather than just checking two levels of
COMPONENT_REF, and only checking byte_position the first time?

> +  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, takes the unaligned address of
> +   packed member of struct or union when assigning to TYPE.  Otherwise,
> +   return NULL_TREE.  */
> +
> +void
> +warn_for_address_of_packed_member (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;
> +
> +  /* Get the type of the pointer pointing to.  */
> +  type = TREE_TYPE (type);
> +
> +  if (TREE_CODE (rhs) == NOP_EXPR)
> +    rhs = TREE_OPERAND (rhs, 0);
> +
> +  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);

This should handle the GNU extension of re-using operand 0 if operand
1 is omitted.

> +      if (context)
> +       rhs = op1;
> +      else
> +       {
> +         /* Check the ELSE path.  */
> +         rhs = TREE_OPERAND (rhs, 2);
> +         context = check_address_of_packed_member (type, rhs);
> +       }
> +    }

You probably also want to look through COMPOUND_EXPR.

> +  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 c48d6dced8d..9db4c9dba8a 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -599,6 +599,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 45a4529ed52..fe5198b0eb0 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -6289,6 +6289,58 @@ inform_for_arg (tree fundecl, location_t ploc, int 
> parmnum,
>           expected_type, actual_type);
>  }
>
> +/* Warn if the right hand poiner value RHS isn't aligned to a

"pointer"

> +   pointer type TYPE at LOCATION.  */
> +
> +static void
> +warn_for_pointer_of_packed_member (location_t location, tree type,
> +                                  tree rhs)
> +{
> +  if (!warn_address_of_packed_member || !POINTER_TYPE_P (type))
> +    return;
> +
> +  bool pointer_p;
> +  tree rhstype;
> +
> +  /* Check the original type of LHS.  */

"RHS"

> +  switch (TREE_CODE (rhs))
> +    {
> +    case PARM_DECL:
> +    case VAR_DECL:
> +      rhstype = TREE_TYPE (rhs);
> +      pointer_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);

So here you're kind of handling address-of again?  Perhaps these two
functions should be one that handles both address and non-address
cases.  Especially since you only call this function in one place,
while the other is called in multiple places.

> +      rhstype = TREE_TYPE (rhs);
> +      pointer_p = TREE_CODE (rhstype) == ARRAY_TYPE;
> +      break;
> +    default:
> +      return;
> +    }
> +
> +  if (pointer_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)
> +       {
> +         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");
> +       }
> +    }
> +}
> +
>  /* Convert value RHS to type TYPE as preparation for an assignment to
>     an lvalue of type TYPE.  If ORIGTYPE is not NULL_TREE, it is the
>     original type of RHS; this differs from TREE_TYPE (RHS) for enum
> @@ -6499,7 +6551,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_of_packed_member (type, orig_rhs);
> +      return rhs;
> +    }
>
>    if (coder == VOID_TYPE)
>      {
> @@ -6986,6 +7041,13 @@ 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.  */
> +      if (TREE_CODE (orig_rhs) != ADDR_EXPR)
> +       warn_for_pointer_of_packed_member (location, type, orig_rhs);
> +      else
> +       warn_for_address_of_packed_member (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 4d04785f2b9..39045d74566 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -7425,6 +7425,9 @@ convert_for_arg_passing (tree type, tree val, 
> tsubst_flags_t complain)
>         }
>        maybe_warn_parm_abi (type, EXPR_LOC_OR_LOC (val, input_location));
>      }
> +
> +  warn_for_address_of_packed_member (type, val);
> +
>    return val;
>  }
>
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index ecb334d19d2..ca0ccc77612 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -8904,6 +8904,8 @@ convert_for_assignment (tree type, tree rhs,
>        TREE_NO_WARNING (rhs) = 1;
>      }
>
> +  warn_for_address_of_packed_member (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 4023197c07c..90cbfb7e775 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -259,8 +259,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  @gol
> --Walloc-zero  -Walloc-size-larger-than=@var{n}
> +-w  -Wextra  -Wall  -Waddress -Waddress-of-packed-member @gol
> +-Waggregate-return -Walloc-zero -Walloc-size-larger-than=@var{n} @gol
>  -Walloca  -Walloca-larger-than=@var{n} @gol
>  -Wno-aggressive-loop-optimizations  -Warray-bounds  -Warray-bounds=@var{n} 
> @gol
>  -Wno-attributes  -Wbool-compare  -Wbool-operation @gol
> @@ -6441,6 +6441,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-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.0
>

Reply via email to