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 >