This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFC: [PATCH] Add warn_if_not_aligned attribute


On Wed, Jun 7, 2017 at 6:30 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Tue, Jun 6, 2017 at 5:11 PM, Martin Sebor <msebor@gmail.com> wrote:
>> On 06/06/2017 04:57 PM, H.J. Lu wrote:
>>>
>>> On Tue, Jun 6, 2017 at 10:34 AM, Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 06/06/2017 10:59 AM, H.J. Lu wrote:
>>>>>
>>>>>
>>>>> On Tue, Jun 6, 2017 at 9:10 AM, Martin Sebor <msebor@gmail.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 06/06/2017 10:07 AM, Martin Sebor wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 06/05/2017 11:45 AM, H.J. Lu wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Mon, Jun 5, 2017 at 8:11 AM, Joseph Myers
>>>>>>>> <joseph@codesourcery.com>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> The new attribute needs documentation.  Should the test be in
>>>>>>>>> c-c++-common
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> This feature does support C++.  But C++ compiler issues a slightly
>>>>>>>> different warning at a different location.
>>>>>>>>
>>>>>>>>> or does this feature not support C++?
>>>>>>>>>
>>>>>>>>
>>>>>>>> Here is the updated patch with documentation and a C++ test.  This
>>>>>>>> patch caused a few testsuite failures:
>>>>>>>>
>>>>>>>> FAIL: gcc.dg/compat/struct-align-1 c_compat_x_tst.o compile
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> /export/gnu/import/git/sources/gcc/gcc/testsuite/gcc.dg/compat//struct-align-1.h:169:1:
>>>>>>>>
>>>>>>>> warning: alignment 1 of 'struct B2_m_inner_p_outer' is less than 16
>>>>>>>>
>>>>>>>> FAIL: g++.dg/torture/pr80334.C   -O0  (test for excess errors)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> /export/gnu/import/git/sources/gcc/gcc/testsuite/g++.dg/torture/pr80334.C:4:8:
>>>>>>>>
>>>>>>>> warning: alignment 1 of 'B' is less than 16
>>>>>>>>
>>>>>>>
>>>>>>> Users often want the ability to control a warning, even when it
>>>>>>> certainly indicates a bug.  I would suggest to add an option to
>>>>>>> make it possible for this warning as well.
>>>>>>>
>>>>>>> Btw., a bug related to some of those this warning is meant to
>>>>>>> detect is assigning the address of an underaligned object to
>>>>>>> a pointer of a natively aligned type.  Clang has an option
>>>>>>> to detect this problem: -Waddress-of-packed-member.  It might
>>>>>>> make a nice follow-on enhancement to add support for the same
>>>>>>> thing.  I mention this because I think it would make sense to
>>>>>>> consider this when choosing the name of the GCC option (i.e.,
>>>>>>> rather than having two distinct but closely related warnings,
>>>>>>> have one that detects both of these alignment type of bugs.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> A bug that has some additional context on this is pr 51628.
>>>>>> A possible name for the new option suggested there is -Wpacked.
>>>>>>
>>>>>> Martin
>>>>>
>>>>>
>>>>>
>>>>> Isn't -Waddress-of-packed-member a subset of or the same as
>>>>> -Wpacked?
>>>>
>>>>
>>>>
>>>> In Clang it's neither.  -Waddress-of-packed-member only triggers
>>>> when the address of a packed member is taken but not for the cases
>>>> in bug 53037 (i.e., reducing the alignment of a member).  It's
>>>> also enabled by default, while -Wpacked needs to be specified
>>>> explicitly (i.e., it's in neither -Wall or -Wextra).
>>>>
>>>> FWIW, I don't really have a strong opinion about the names of
>>>> the options.  My input is that the proliferation of fine-grained
>>>> warning options for closely related problems tends to make it
>>>> tricky to get their interactions right (both in the compiler
>>>> and for users).  Enabling both/all such options can lead to
>>>> multiple warnings for what boils down to essentially the same
>>>> bug in the same expression, overwhelming the user in repetitive
>>>> diagnostics.
>>>>
>>>
>>> There is already -Wpacked.  Should I overload it for this?
>>
>>
>> I'd say yes if -Wpacked were at least in -Wall.  But it's
>> an opt-in kind of warning that's not even in -Wextra, and
>> relaxing an explicitly specified alignment seems more like
>> a bug than just something that might be nice to know about.
>> I would expect warn_if_not_aligned to trigger a warning even
>> without -Wall (i.e., as you have it in your patch, but with
>> an option to control it).  That would suggest three levels
>> of warnings:
>>
>> 1) warn by default (warn_if_not_aligned violation)
>> 2) warn with -Wall (using a type with attribute aligned to
>>    define a member of a packed struct)
>> 3) warn if requested (current -Wpacked)
>>
>> So one way to deal with it would be to change -Wpacked to
>> take an argument between 0 and 3, set the default to
>> correspond to the (1) above, and have -Wall bump it up to
>> (2).
>>
>> If the equivalent of -Waddress-of-packed-member were to be
>> implemented in GCC it would probably be a candidate to add
>> to the (2) above.(*)
>>
>> This might be more involved than you envisioned.  A slightly
>> simpler alternative would be to add a different option, say
>> something like -Walign=N, and have it handle just (1) and
>> (2) above, leaving -Wpacked unchanged.
>>
>
> Since there is no agreement on -W options and changes
> may touch many places, I will do
>
> 1. Add -Wwarn-if-not-aligned and enable it by default.
> 2. Add -Wpacked-not-aligned and disable it by default.
>
> Once there is an agreement, I replace -Wpacked-not-aligned
> with the new option.
>
>

Here is the updated patch.

Add warn_if_not_aligned attribute as well as  command line options:
-Wif-not-aligned and -Wpacked-not-aligned.

__attribute__((warn_if_not_aligned(N))) causes compiler to issue a
warning if the field in a struct or union is not aligned to N:

typedef unsigned long long __u64
  __attribute__((aligned(4),warn_if_not_aligned(8)));

struct foo
{
  int i1;
  int i2;
  __u64 x;
};

__u64 is aligned to 4 bytes.  But inside struct foo, __u64 should be
aligned at 8 bytes.  It is used to define struct foo in such a way that
struct foo has the same layout and x has the same alignment when __u64
is aligned at either 4 or 8 bytes.

Since struct foo is normally aligned to 4 bytes, a warning will be issued:

warning: alignment 4 of ‘struct foo’ is less than 8

Align struct foo to 8 bytes:

struct foo
{
  int i1;
  int i2;
  __u64 x;
} __attribute__((aligned(8)));

silences the warning.  It also warns the field with misaligned offset:

struct foo
{
  int i1;
  int i2;
  int i3;
  __u64 x;
} __attribute__((aligned(8)));

warning: ‘x’ offset 12 in ‘struct foo’ isn't aligned to 8

This warning is controlled by -Wif-not-aligned and is enabled by default.

When -Wpacked-not-aligned is used, the same warning is also issued for
the field with explicitly specified alignment in a packed struct or union:

struct __attribute__ ((aligned (8))) S8 { char a[8]; };
struct __attribute__ ((packed)) S {
  struct S8 s8;
};

warning: alignment 1 of ‘struct S’ is less than 8

This warning is disabled by default and enabled by -Wall.

gcc/

PR c/53037
* print-tree.c (print_node): Support DECL_WARN_IF_NOT_ALIGN
and TYPE_WARN_IF_NOT_ALIGN.
* stor-layout.c (do_type_align): Merge DECL_WARN_IF_NOT_ALIGN.
(handle_warn_if_not_align): New.
(place_union_field): Call handle_warn_if_not_align.
(place_field): Call handle_warn_if_not_align.  Copy
TYPE_WARN_IF_NOT_ALIGN.
(finish_builtin_struct): Copy TYPE_WARN_IF_NOT_ALIGN.
(layout_type): Likewise.
* tree-core.h (tree_type_common): Add warn_if_not_align.  Set
spare to 18.
(tree_decl_common): Add warn_if_not_align.
* tree.c (build_range_type_1): Likewise.
* tree.h (TYPE_WARN_IF_NOT_ALIGN): New.
(SET_TYPE_WARN_IF_NOT_ALIGN): Likewise.
(DECL_WARN_IF_NOT_ALIGN): Likewise.
(SET_DECL_WARN_IF_NOT_ALIGN): Likewise.
* doc/extend.texi: Document warn_if_not_aligned attribute.
* doc/invoke.texi: Document -Wif-not-aligned and
-Wpacked-not-aligned.

gcc/c-family/

PR c/53037
* c-attribs.c (handle_warn_if_not_aligned_attribute): New.
(c_common_attribute_table): Add warn_if_not_aligned.
(handle_aligned_attribute): Renamed to ...
(common_handle_aligned_attribute): Remove argument, name, and add
argument, warn_if_not_aligned.  Handle warn_if_not_aligned.
(handle_aligned_attribute): New.
* c.opt: Add -Wif-not-aligned and -Wpacked-not-aligned.

gcc/c/

PR c/53037
* c-decl.c (merge_decls): Also merge TYPE_WARN_IF_NOT_ALIGN.

gcc/cp/

PR c/53037
* decl.c (duplicate_decls): Also merge TYPE_WARN_IF_NOT_ALIGN.

gcc/testsuite/

PR c/53037
* c-c++-common/pr53037-4.c: New test.
* g++.dg/pr53037-1.C: Likewise.
* g++.dg/pr53037-2.C: Likewise.
* g++.dg/pr53037-3.C: Likewise.
* gcc.dg/pr53037-1.c: Likewise.
* gcc.dg/pr53037-2.c: Likewise.
* gcc.dg/pr53037-3.c: Likewise.


-- 
H.J.
From 9759a2d5bdba339bdde489695039b30624e241f5 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Fri, 20 Apr 2012 13:49:05 -0700
Subject: [PATCH] Add warn_if_not_aligned attribute
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add warn_if_not_aligned attribute as well as  command line options:
-Wif-not-aligned and -Wpacked-not-aligned.

__attribute__((warn_if_not_aligned(N))) causes compiler to issue a
warning if the field in a struct or union is not aligned to N:

typedef unsigned long long __u64
  __attribute__((aligned(4),warn_if_not_aligned(8)));

struct foo
{
  int i1;
  int i2;
  __u64 x;
};

__u64 is aligned to 4 bytes.  But inside struct foo, __u64 should be
aligned at 8 bytes.  It is used to define struct foo in such a way that
struct foo has the same layout and x has the same alignment when __u64
is aligned at either 4 or 8 bytes.

Since struct foo is normally aligned to 4 bytes, a warning will be issued:

warning: alignment 4 of ‘struct foo’ is less than 8

Align struct foo to 8 bytes:

struct foo
{
  int i1;
  int i2;
  __u64 x;
} __attribute__((aligned(8)));

silences the warning.  It also warns the field with misaligned offset:

struct foo
{
  int i1;
  int i2;
  int i3;
  __u64 x;
} __attribute__((aligned(8)));

warning: ‘x’ offset 12 in ‘struct foo’ isn't aligned to 8

This warning is controlled by -Wif-not-aligned and is enabled by default.

When -Wpacked-not-aligned is used, the same warning is also issued for
the field with explicitly specified alignment in a packed struct or union:

struct __attribute__ ((aligned (8))) S8 { char a[8]; };
struct __attribute__ ((packed)) S {
  struct S8 s8;
};

warning: alignment 1 of ‘struct S’ is less than 8

This warning is disabled by default and enabled by -Wall.

gcc/

	PR c/53037
	* print-tree.c (print_node): Support DECL_WARN_IF_NOT_ALIGN
	and TYPE_WARN_IF_NOT_ALIGN.
	* stor-layout.c (do_type_align): Merge DECL_WARN_IF_NOT_ALIGN.
	(handle_warn_if_not_align): New.
	(place_union_field): Call handle_warn_if_not_align.
	(place_field): Call handle_warn_if_not_align.  Copy
	TYPE_WARN_IF_NOT_ALIGN.
	(finish_builtin_struct): Copy TYPE_WARN_IF_NOT_ALIGN.
	(layout_type): Likewise.
	* tree-core.h (tree_type_common): Add warn_if_not_align.  Set
	spare to 18.
	(tree_decl_common): Add warn_if_not_align.
	* tree.c (build_range_type_1): Likewise.
	* tree.h (TYPE_WARN_IF_NOT_ALIGN): New.
	(SET_TYPE_WARN_IF_NOT_ALIGN): Likewise.
	(DECL_WARN_IF_NOT_ALIGN): Likewise.
	(SET_DECL_WARN_IF_NOT_ALIGN): Likewise.
	* doc/extend.texi: Document warn_if_not_aligned attribute.
	* doc/invoke.texi: Document -Wif-not-aligned and
	-Wpacked-not-aligned.

gcc/c-family/

	PR c/53037
	* c-attribs.c (handle_warn_if_not_aligned_attribute): New.
	(c_common_attribute_table): Add warn_if_not_aligned.
	(handle_aligned_attribute): Renamed to ...
	(common_handle_aligned_attribute): Remove argument, name, and add
	argument, warn_if_not_aligned.  Handle warn_if_not_aligned.
	(handle_aligned_attribute): New.
	* c.opt: Add -Wif-not-aligned and -Wpacked-not-aligned.

gcc/c/

	PR c/53037
	* c-decl.c (merge_decls): Also merge TYPE_WARN_IF_NOT_ALIGN.

gcc/cp/

	PR c/53037
	* decl.c (duplicate_decls): Also merge TYPE_WARN_IF_NOT_ALIGN.

gcc/testsuite/

	PR c/53037
	* c-c++-common/pr53037-4.c: New test.
	* g++.dg/pr53037-1.C: Likewise.
	* g++.dg/pr53037-2.C: Likewise.
	* g++.dg/pr53037-3.C: Likewise.
	* gcc.dg/pr53037-1.c: Likewise.
	* gcc.dg/pr53037-2.c: Likewise.
	* gcc.dg/pr53037-3.c: Likewise.
---
 gcc/c-family/c-attribs.c               | 67 ++++++++++++++++++++++----
 gcc/c-family/c.opt                     |  8 ++++
 gcc/c/c-decl.c                         |  4 ++
 gcc/cp/decl.c                          |  4 ++
 gcc/doc/extend.texi                    | 87 ++++++++++++++++++++++++++++++++++
 gcc/doc/invoke.texi                    | 29 +++++++++++-
 gcc/print-tree.c                       |  9 ++--
 gcc/stor-layout.c                      | 56 ++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr53037-4.c | 81 +++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/pr53037-1.C       | 81 +++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/pr53037-2.C       | 37 +++++++++++++++
 gcc/testsuite/g++.dg/pr53037-3.C       | 37 +++++++++++++++
 gcc/testsuite/gcc.dg/pr53037-1.c       | 81 +++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr53037-2.c       | 37 +++++++++++++++
 gcc/testsuite/gcc.dg/pr53037-3.c       | 37 +++++++++++++++
 gcc/tree-core.h                        |  9 +++-
 gcc/tree.c                             |  1 +
 gcc/tree.h                             | 20 ++++++++
 18 files changed, 671 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr53037-4.c
 create mode 100644 gcc/testsuite/g++.dg/pr53037-1.C
 create mode 100644 gcc/testsuite/g++.dg/pr53037-2.C
 create mode 100644 gcc/testsuite/g++.dg/pr53037-3.C
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-3.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 695c58c..7e58990 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -85,6 +85,8 @@ static tree handle_destructor_attribute (tree *, tree, tree, int, bool *);
 static tree handle_mode_attribute (tree *, tree, tree, int, bool *);
 static tree handle_section_attribute (tree *, tree, tree, int, bool *);
 static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
+static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
+						  int, bool *);
 static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
@@ -208,6 +210,9 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_section_attribute, false },
   { "aligned",                0, 1, false, false, false,
 			      handle_aligned_attribute, false },
+  { "warn_if_not_aligned",    0, 1, false, false, false,
+			      handle_warn_if_not_aligned_attribute,
+			      false },
   { "weak",                   0, 0, true,  false, false,
 			      handle_weak_attribute, false },
   { "noplt",                   0, 0, true,  false, false,
@@ -1558,12 +1563,13 @@ check_cxx_fundamental_alignment_constraints (tree node,
   return !alignment_too_large_p;
 }
 
-/* Handle a "aligned" attribute; arguments as in
-   struct attribute_spec.handler.  */
+/* Common codes shared by handle_warn_if_not_aligned_attribute and
+   handle_aligned_attribute.  */
 
 static tree
-handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
-			  int flags, bool *no_add_attrs)
+common_handle_aligned_attribute (tree *node, tree args, int flags,
+				 bool *no_add_attrs,
+				 bool warn_if_not_aligned_p)
 {
   tree decl = NULL_TREE;
   tree *type = NULL;
@@ -1612,8 +1618,16 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       else
 	*type = build_variant_type_copy (*type);
 
-      SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
-      TYPE_USER_ALIGN (*type) = 1;
+      if (warn_if_not_aligned_p)
+	{
+	  SET_TYPE_WARN_IF_NOT_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+	  warn_if_not_aligned_p = false;
+	}
+      else
+	{
+	  SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+	  TYPE_USER_ALIGN (*type) = 1;
+	}
     }
   else if (! VAR_OR_FUNCTION_DECL_P (decl)
 	   && TREE_CODE (decl) != FIELD_DECL)
@@ -1646,13 +1660,50 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
     }
   else
     {
-      SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
-      DECL_USER_ALIGN (decl) = 1;
+      if (warn_if_not_aligned_p)
+	{
+	  SET_DECL_WARN_IF_NOT_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+	  warn_if_not_aligned_p = false;
+	}
+      else
+	{
+	  SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+	  DECL_USER_ALIGN (decl) = 1;
+	}
+    }
+
+  if (warn_if_not_aligned_p)
+    {
+      error ("warn_if_not_aligned may not be specified for %q+D", decl);
+      *no_add_attrs = true;
     }
 
   return NULL_TREE;
 }
 
+/* Handle a "aligned" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+			  int flags, bool *no_add_attrs)
+{
+  return common_handle_aligned_attribute (node, args, flags,
+					 no_add_attrs, false);
+}
+
+/* Handle a "warn_if_not_aligned" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_warn_if_not_aligned_attribute (tree *node, tree ARG_UNUSED (name),
+				      tree args, int flags,
+				      bool *no_add_attrs)
+{
+  return common_handle_aligned_attribute (node, args, flags,
+					  no_add_attrs, true);
+}
+
 /* Handle a "weak" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 37bb236..b324666 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -579,6 +579,10 @@ Wformat-truncation=
 C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 1, 0)
 Warn about calls to snprintf and similar functions that truncate output.
 
+Wif-not-aligned
+C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning
+Warn when the field in a struct is not aligned.
+
 Wignored-qualifiers
 C C++ Var(warn_ignored_qualifiers) Warning EnabledBy(Wextra)
 Warn whenever type qualifiers are ignored.
@@ -706,6 +710,10 @@ Wnamespaces
 C++ ObjC++ Var(warn_namespaces) Warning
 Warn on namespace definition.
 
+Wpacked-not-aligned
+C ObjC C++ ObjC++ Var(warn_packed_not_aligned) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
+Warn when fields in a struct with the packed attribute are misaligned.
+
 Wsized-deallocation
 C++ ObjC++ Var(warn_sized_deallocation) Warning EnabledBy(Wextra)
 Warn about missing sized deallocation functions.
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 3a0a4f5..5d1115d 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2383,6 +2383,10 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl));
 	  DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl);
 	}
+      if (DECL_WARN_IF_NOT_ALIGN (olddecl)
+	  > DECL_WARN_IF_NOT_ALIGN (newdecl))
+	SET_DECL_WARN_IF_NOT_ALIGN (newdecl,
+				    DECL_WARN_IF_NOT_ALIGN (olddecl));
     }
 
   /* Keep the old rtl since we can safely use it.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b144426..bb96901 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2526,6 +2526,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl);
     }
   DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl);
+  if (DECL_WARN_IF_NOT_ALIGN (olddecl)
+      > DECL_WARN_IF_NOT_ALIGN (newdecl))
+    SET_DECL_WARN_IF_NOT_ALIGN (newdecl,
+				DECL_WARN_IF_NOT_ALIGN (olddecl));
   if (TREE_CODE (newdecl) == FIELD_DECL)
     DECL_PACKED (olddecl) = DECL_PACKED (newdecl);
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7d39335..ccf90c5 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5685,6 +5685,41 @@ alignment.  See your linker documentation for further information.
 The @code{aligned} attribute can also be used for functions
 (@pxref{Common Function Attributes}.)
 
+@cindex @code{warn_if_not_aligned} variable attribute
+@item warn_if_not_aligned (@var{alignment})
+This attribute specifies a threshold for the structure field, measured
+in bytes.  If the structure field is aligned below the threshold, a
+warning will be issued.  For example, the declaration:
+
+@smallexample
+struct foo
+@{
+  int i1;
+  int i2;
+  unsigned long long x __attribute__((warn_if_not_aligned(16)));
+@};
+@end smallexample
+
+@noindent
+causes the compiler to issue an warning on @code{struct foo}, like
+@code{warning: alignment 8 of 'struct foo' is less than 16}.
+The compiler also issues a warning, like @code{warning: 'x' offset
+8 in 'struct foo' isn't aligned to 16}, when the structure field has
+the misaligned offset:
+
+@smallexample
+struct foo
+@{
+  int i1;
+  int i2;
+  unsigned long long x __attribute__((warn_if_not_aligned(16)));
+@} __attribute__((aligned(16)));
+@end smallexample
+
+This warning can be disabled by @option{-Wno-if-not-aligned}.
+The @code{warn_if_not_aligned } attribute can also be used for types
+(@pxref{Common Type Attributes}.)
+
 @item cleanup (@var{cleanup_function})
 @cindex @code{cleanup} variable attribute
 The @code{cleanup} attribute runs a function when the variable goes
@@ -6546,6 +6581,58 @@ alignment.  See your linker documentation for further information.
 The @code{aligned} attribute can only increase alignment.  Alignment
 can be decreased by specifying the @code{packed} attribute.  See below.
 
+@cindex @code{warn_if_not_aligned} type attribute
+@item warn_if_not_aligned (@var{alignment})
+This attribute specifies a threshold for the structure field, measured
+in bytes.  If the structure field is aligned below the threshold, a
+warning will be issued.  For example, the declaration:
+
+@smallexample
+typedef unsigned long long __u64
+   __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo
+@{
+  int i1;
+  int i2;
+  __u64 x;
+@};
+@end smallexample
+
+@noindent
+causes the compiler to issue an warning on @code{struct foo}, like
+@code{warning: alignment 4 of 'struct foo' is less than 8}.
+It is used to define @code{struct foo} in such a way that
+@code{struct foo} has the same layout and the structure field @code{x}
+has the same alignment when @code{__u64} is aligned at either 4 or
+8 bytes.  Align @code{struct foo} to 8 bytes:
+
+@smallexample
+struct foo
+@{
+  int i1;
+  int i2;
+  __u64 x;
+@} __attribute__((aligned(8)));
+@end smallexample
+
+@noindent
+silences the warning.  The compiler also issues a warning, like
+@code{warning: 'x' offset 12 in 'struct foo' isn't aligned to 8},
+when the structure field has the misaligned offset:
+
+@smallexample
+struct foo
+@{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x;
+@} __attribute__((aligned(8)));
+@end smallexample
+
+This warning can be disabled by @option{-Wno-if-not-aligned}.
+
 @item bnd_variable_size
 @cindex @code{bnd_variable_size} type attribute
 @cindex Pointer Bounds Checker attributes
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c116882..5c28df6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -283,6 +283,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wformat-security  -Wformat-signedness  -Wformat-truncation=@var{n} @gol
 -Wformat-y2k  -Wframe-address @gol
 -Wframe-larger-than=@var{len}  -Wno-free-nonheap-object  -Wjump-misses-init @gol
+-Wif-not-aligned @gol
 -Wignored-qualifiers  -Wignored-attributes  -Wincompatible-pointer-types @gol
 -Wimplicit  -Wimplicit-fallthrough  -Wimplicit-fallthrough=@var{n} @gol
 -Wimplicit-function-declaration  -Wimplicit-int @gol
@@ -297,7 +298,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
 -Wnull-dereference  -Wodr  -Wno-overflow  -Wopenmp-simd  @gol
 -Woverride-init-side-effects  -Woverlength-strings @gol
--Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
+-Wpacked  -Wpacked-bitfield-compat -Wpacked-not-aligned -Wpadded @gol
 -Wparentheses  -Wno-pedantic-ms-format @gol
 -Wplacement-new  -Wplacement-new=@var{n} @gol
 -Wpointer-arith  -Wpointer-compare  -Wno-pointer-to-int-cast @gol
@@ -4407,6 +4408,13 @@ switch (cond)
 
 The @option{-Wimplicit-fallthrough=3} warning is enabled by @option{-Wextra}.
 
+@item -Wif-not-aligned @r{(C, C++, Objective-C and Objective-C++ only)}
+@opindex Wif-not-aligned
+@opindex Wno-if-not-aligned
+Control if warning triggered by the @code{warn_if_not_aligned} attribute
+should be issued.  This is is enabled by default.
+Use @option{-Wno-if-not-aligned} to disable it.
+
 @item -Wignored-qualifiers @r{(C and C++ only)}
 @opindex Wignored-qualifiers
 @opindex Wno-ignored-qualifiers
@@ -6474,6 +6482,25 @@ struct foo
 This warning is enabled by default.  Use
 @option{-Wno-packed-bitfield-compat} to disable this warning.
 
+@item -Wpacked-not-aligned @r{(C, C++, Objective-C and Objective-C++ only)}
+@opindex Wpacked-not-aligned
+@opindex Wno-packed-not-aligned
+Warn if a structure field with explicitly specified alignment in a
+packed struct or union is misaligned.  For example, a warning will
+be issued on @code{struct S}, like, @code{warning: alignment 1 of
+'struct S' is less than 8}, in this code:
+
+@smallexample
+@group
+struct __attribute__ ((aligned (8))) S8 @{ char a[8]; @};
+struct __attribute__ ((packed)) S @{
+  struct S8 s8;
+@};
+@end group
+@end smallexample
+
+This warning is enabled by @option{-Wall}.
+
 @item -Wpadded
 @opindex Wpadded
 @opindex Wno-padded
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index ea26a0b..7fdff8f 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -458,7 +458,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
 	  if (DECL_USER_ALIGN (node))
 	    fprintf (file, " user");
 
-	  fprintf (file, " align %d", DECL_ALIGN (node));
+	  fprintf (file, " align %d warn_if_not_align %d",
+		   DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node));
 	  if (code == FIELD_DECL)
 	    fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED,
 		     DECL_OFFSET_ALIGN (node));
@@ -603,8 +604,10 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
       if (TYPE_USER_ALIGN (node))
 	fprintf (file, " user");
 
-      fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC,
-	       TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node),
+      fprintf (file, " align %d warn_if_not_align %d symtab %d alias set "
+	       HOST_WIDE_INT_PRINT_DEC,
+	       TYPE_ALIGN (node), TYPE_WARN_IF_NOT_ALIGN (node),
+	       TYPE_SYMTAB_ADDRESS (node),
 	       (HOST_WIDE_INT) TYPE_ALIAS_SET (node));
 
       if (TYPE_STRUCTURAL_EQUALITY_P (node))
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 1574e43..a74eed1 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -570,6 +570,8 @@ do_type_align (tree type, tree decl)
       if (TREE_CODE (decl) == FIELD_DECL)
 	DECL_USER_ALIGN (decl) = TYPE_USER_ALIGN (type);
     }
+  if (TYPE_WARN_IF_NOT_ALIGN (type) > DECL_WARN_IF_NOT_ALIGN (decl))
+    SET_DECL_WARN_IF_NOT_ALIGN (decl, TYPE_WARN_IF_NOT_ALIGN (type));
 }
 
 /* Set the size, mode and alignment of a ..._DECL node.
@@ -1074,6 +1076,47 @@ update_alignment_for_field (record_layout_info rli, tree field,
   return desired_align;
 }
 
+static void
+handle_warn_if_not_align (tree field, unsigned int record_align)
+{
+  tree type = TREE_TYPE (field);
+
+  if (type == error_mark_node)
+    return;
+
+  unsigned int warn_if_not_align = 0;
+
+  if (warn_if_not_aligned)
+    {
+      warn_if_not_align = DECL_WARN_IF_NOT_ALIGN (field);
+      if (!warn_if_not_align)
+	warn_if_not_align = TYPE_WARN_IF_NOT_ALIGN (type);
+    }
+
+  if (!warn_if_not_align
+      && warn_packed_not_aligned
+      && TYPE_USER_ALIGN (type))
+    warn_if_not_align = TYPE_ALIGN (type);
+
+  if (!warn_if_not_align)
+    return;
+
+  tree context = DECL_CONTEXT (field);
+
+  warn_if_not_align /= BITS_PER_UNIT;
+  record_align /= BITS_PER_UNIT;
+  if ((record_align % warn_if_not_align) != 0)
+    warning (0, "alignment %d of %qT is less than %d",
+	     record_align, context, warn_if_not_align);
+
+  unsigned int off
+    = (tree_to_uhwi (DECL_FIELD_OFFSET (field))
+       + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)) / BITS_PER_UNIT);
+  if ((off % warn_if_not_align) != 0)
+    warning (0, "%q+D offset %d in %qT isn't aligned to %d",
+	     field, off, context, warn_if_not_align);
+}
+
 /* Called from place_field to handle unions.  */
 
 static void
@@ -1084,6 +1127,7 @@ place_union_field (record_layout_info rli, tree field)
   DECL_FIELD_OFFSET (field) = size_zero_node;
   DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
   SET_DECL_OFFSET_ALIGN (field, BIGGEST_ALIGNMENT);
+  handle_warn_if_not_align (field, rli->record_align);
 
   /* If this is an ERROR_MARK return *after* having set the
      field at the start of the union. This helps when parsing
@@ -1169,6 +1213,7 @@ place_field (record_layout_info rli, tree field)
       DECL_FIELD_OFFSET (field) = rli->offset;
       DECL_FIELD_BIT_OFFSET (field) = rli->bitpos;
       SET_DECL_OFFSET_ALIGN (field, rli->offset_align);
+      handle_warn_if_not_align (field, rli->record_align);
       return;
     }
 
@@ -1290,6 +1335,9 @@ place_field (record_layout_info rli, tree field)
 
       if (! DECL_PACKED (field))
 	TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
+
+      SET_TYPE_WARN_IF_NOT_ALIGN (rli->t,
+				  TYPE_WARN_IF_NOT_ALIGN (type));
     }
 
 #ifdef BITFIELD_NBYTES_LIMITED
@@ -1328,6 +1376,8 @@ place_field (record_layout_info rli, tree field)
 	rli->bitpos = round_up (rli->bitpos, type_align);
 
       TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
+      SET_TYPE_WARN_IF_NOT_ALIGN (rli->t,
+				  TYPE_WARN_IF_NOT_ALIGN (type));
     }
 #endif
 
@@ -1478,6 +1528,7 @@ place_field (record_layout_info rli, tree field)
   DECL_FIELD_OFFSET (field) = rli->offset;
   DECL_FIELD_BIT_OFFSET (field) = rli->bitpos;
   SET_DECL_OFFSET_ALIGN (field, rli->offset_align);
+  handle_warn_if_not_align (field, rli->record_align);
 
   /* Evaluate nonconstant offsets only once, either now or as soon as safe.  */
   if (TREE_CODE (DECL_FIELD_OFFSET (field)) != INTEGER_CST)
@@ -2088,6 +2139,8 @@ finish_builtin_struct (tree type, const char *name, tree fields,
     {
       SET_TYPE_ALIGN (type, TYPE_ALIGN (align_type));
       TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (align_type);
+      SET_TYPE_WARN_IF_NOT_ALIGN (type,
+				  TYPE_WARN_IF_NOT_ALIGN (align_type));
     }
 
   layout_type (type);
@@ -2324,6 +2377,9 @@ layout_type (tree type)
 	  align = MAX (align, TYPE_ALIGN (type));
 	else
 	  TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);
+	if (!TYPE_WARN_IF_NOT_ALIGN (type))
+	  SET_TYPE_WARN_IF_NOT_ALIGN (type,
+				      TYPE_WARN_IF_NOT_ALIGN (element));
 #ifdef ROUND_TYPE_ALIGN
 	align = ROUND_TYPE_ALIGN (type, align, BITS_PER_UNIT);
 #else
diff --git a/gcc/testsuite/c-c++-common/pr53037-4.c b/gcc/testsuite/c-c++-common/pr53037-4.c
new file mode 100644
index 0000000..97d54b1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr53037-4.c
@@ -0,0 +1,81 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wno-if-not-aligned" } */
+
+typedef unsigned long long __u64
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo1
+{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x;
+};
+
+struct foo2
+{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+struct foo3
+{
+  int i1;
+  int i3;
+  __u64 x;
+};
+
+struct foo4
+{
+  int i1;
+  int i2;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+struct foo5
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16)));
+};
+
+struct foo6
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); 
+} __attribute__((aligned(16)));
+
+struct foo7
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int x __attribute__((warn_if_not_aligned(16)));
+} __attribute__((aligned(16)));
+
+union bar1
+{
+  int i1;
+  __u64 x;
+};
+
+union bar2
+{
+  int i1;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+union bar3
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); 
+};
+
+union bar4
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16)));
+} __attribute__((aligned(16)));
diff --git a/gcc/testsuite/g++.dg/pr53037-1.C b/gcc/testsuite/g++.dg/pr53037-1.C
new file mode 100644
index 0000000..a3d8f99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-1.C
@@ -0,0 +1,81 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+typedef unsigned long long __u64
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo1 /* { dg-warning "alignment 4 of 'foo1' is less than 8" } */
+{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x; /* { dg-warning "'foo1::x' offset 12 in 'foo1' isn't aligned to 8" } */
+};
+
+struct foo2
+{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x; /* { dg-warning "'foo2::x' offset 12 in 'foo2' isn't aligned to 8" } */
+} __attribute__((aligned(8)));
+
+struct foo3 /* { dg-warning "alignment 4 of 'foo3' is less than 8" } */
+{
+  int i1;
+  int i3;
+  __u64 x;
+};
+
+struct foo4
+{
+  int i1;
+  int i2;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+struct foo5 /* { dg-warning "alignment 4 of 'foo5' is less than 16" } */
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); /* { dg-warning "'foo5::x' offset 4 in 'foo5' isn't aligned to 16" } */
+};
+
+struct foo6
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); /* { dg-warning "'foo6::x' offset 4 in 'foo6' isn't aligned to 16" } */
+} __attribute__((aligned(16)));
+
+struct foo7
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int x __attribute__((warn_if_not_aligned(16)));
+} __attribute__((aligned(16)));
+
+union bar1 /* { dg-warning "alignment 4 of 'bar1' is less than 8" } */
+{
+  int i1;
+  __u64 x;
+};
+
+union bar2
+{
+  int i1;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+union bar3 /* { dg-warning "alignment 4 of 'bar3' is less than 16" } */
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); 
+};
+
+union bar4
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16)));
+} __attribute__((aligned(16)));
diff --git a/gcc/testsuite/g++.dg/pr53037-2.C b/gcc/testsuite/g++.dg/pr53037-2.C
new file mode 100644
index 0000000..e617f90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-2.C
@@ -0,0 +1,37 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wpacked-not-aligned" } */
+
+struct __attribute__ ((aligned (8))) S8 { char a[8]; };
+struct __attribute__ ((packed)) S1 { /* { dg-warning "alignment 1 of 'S1' is less than 8" } */
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed, aligned (8))) S2 {
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed, aligned (8))) S3 {
+  int i1;
+  struct S8 s8; /* { dg-warning "'S3::s8' offset 4 in 'S3' isn't aligned to 8" } */
+};
+
+struct __attribute__ ((packed, aligned (8))) S4 {
+  int i1;
+  int i2;
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed)) S5 {
+   long long ll;
+};
+
+union __attribute__ ((packed)) U1 { /* { dg-warning "alignment 1 of 'U1' is less than 8" } */
+  int i1;
+  struct S8 s8;
+};
+
+union __attribute__ ((packed, aligned (8))) U2 {
+  int i1;
+  struct S8 s8;
+};
diff --git a/gcc/testsuite/g++.dg/pr53037-3.C b/gcc/testsuite/g++.dg/pr53037-3.C
new file mode 100644
index 0000000..1ed6354
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-3.C
@@ -0,0 +1,37 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wall" } */
+
+struct __attribute__ ((aligned (8))) S8 { char a[8]; };
+struct __attribute__ ((packed)) S1 { /* { dg-warning "alignment 1 of 'S1' is less than 8" } */
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed, aligned (8))) S2 {
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed, aligned (8))) S3 {
+  int i1;
+  struct S8 s8; /* { dg-warning "'S3::s8' offset 4 in 'S3' isn't aligned to 8" } */
+};
+
+struct __attribute__ ((packed, aligned (8))) S4 {
+  int i1;
+  int i2;
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed)) S5 {
+   long long ll;
+};
+
+union __attribute__ ((packed)) U1 { /* { dg-warning "alignment 1 of 'U1' is less than 8" } */
+  int i1;
+  struct S8 s8;
+};
+
+union __attribute__ ((packed, aligned (8))) U2 {
+  int i1;
+  struct S8 s8;
+};
diff --git a/gcc/testsuite/gcc.dg/pr53037-1.c b/gcc/testsuite/gcc.dg/pr53037-1.c
new file mode 100644
index 0000000..93af0a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-1.c
@@ -0,0 +1,81 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+typedef unsigned long long __u64
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo1
+{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x; /* { dg-warning "'x' offset 12 in 'struct foo1' isn't aligned to 8" } */
+}; /* { dg-warning "alignment 4 of 'struct foo1' is less than 8" } */
+
+struct foo2
+{
+  int i1;
+  int i2;
+  int i3;
+  __u64 x; /* { dg-warning "'x' offset 12 in 'struct foo2' isn't aligned to 8" } */
+} __attribute__((aligned(8)));
+
+struct foo3
+{
+  int i1;
+  int i3;
+  __u64 x;
+}; /* { dg-warning "alignment 4 of 'struct foo3' is less than 8" } */
+
+struct foo4
+{
+  int i1;
+  int i2;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+struct foo5
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); /* { dg-warning "'x' offset 4 in 'struct foo5' isn't aligned to 16" } */
+}; /* { dg-warning "alignment 4 of 'struct foo5' is less than 16" } */
+
+struct foo6
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); /* { dg-warning "'x' offset 4 in 'struct foo6' isn't aligned to 16" } */
+} __attribute__((aligned(16)));
+
+struct foo7
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int x __attribute__((warn_if_not_aligned(16)));
+} __attribute__((aligned(16)));
+
+union bar1
+{
+  int i1;
+  __u64 x;
+}; /* { dg-warning "alignment 4 of 'union bar1' is less than 8" } */
+
+union bar2
+{
+  int i1;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+union bar3
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16))); 
+}; /* { dg-warning "alignment 4 of 'union bar3' is less than 16" } */
+
+union bar4
+{
+  int i1;
+  int x __attribute__((warn_if_not_aligned(16)));
+} __attribute__((aligned(16)));
diff --git a/gcc/testsuite/gcc.dg/pr53037-2.c b/gcc/testsuite/gcc.dg/pr53037-2.c
new file mode 100644
index 0000000..f9934a6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-2.c
@@ -0,0 +1,37 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wpacked-not-aligned" } */
+
+struct __attribute__ ((aligned (8))) S8 { char a[8]; };
+struct __attribute__ ((packed)) S1 {
+  struct S8 s8;
+}; /* { dg-warning "alignment 1 of 'struct S1' is less than 8" } */
+
+struct __attribute__ ((packed, aligned (8))) S2 {
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed, aligned (8))) S3 {
+  int i1;
+  struct S8 s8; /* { dg-warning "'s8' offset 4 in 'struct S3' isn't aligned to 8" } */
+};
+
+struct __attribute__ ((packed, aligned (8))) S4 {
+  int i1;
+  int i2;
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed)) S5 {
+   long long ll;
+};
+
+union __attribute__ ((packed)) U1 {
+  int i1;
+  struct S8 s8;
+}; /* { dg-warning "alignment 1 of 'union U1' is less than 8" } */
+
+union __attribute__ ((packed, aligned (8))) U2 {
+  int i1;
+  struct S8 s8;
+};
diff --git a/gcc/testsuite/gcc.dg/pr53037-3.c b/gcc/testsuite/gcc.dg/pr53037-3.c
new file mode 100644
index 0000000..fc69ae8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-3.c
@@ -0,0 +1,37 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wall" } */
+
+struct __attribute__ ((aligned (8))) S8 { char a[8]; };
+struct __attribute__ ((packed)) S1 {
+  struct S8 s8;
+}; /* { dg-warning "alignment 1 of 'struct S1' is less than 8" } */
+
+struct __attribute__ ((packed, aligned (8))) S2 {
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed, aligned (8))) S3 {
+  int i1;
+  struct S8 s8; /* { dg-warning "'s8' offset 4 in 'struct S3' isn't aligned to 8" } */
+};
+
+struct __attribute__ ((packed, aligned (8))) S4 {
+  int i1;
+  int i2;
+  struct S8 s8;
+};
+
+struct __attribute__ ((packed)) S5 {
+   long long ll;
+};
+
+union __attribute__ ((packed)) U1 {
+  int i1;
+  struct S8 s8;
+}; /* { dg-warning "alignment 1 of 'union U1' is less than 8" } */
+
+union __attribute__ ((packed, aligned (8))) U2 {
+  int i1;
+  struct S8 s8;
+};
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index ea73477..30d87e4 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1516,8 +1516,9 @@ struct GTY(()) tree_type_common {
      so we need to store the value 32 (not 31, as we need the zero
      as well), hence six bits.  */
   unsigned align : 6;
+  unsigned warn_if_not_align : 6;
   unsigned typeless_storage : 1;
-  unsigned spare : 24;
+  unsigned spare : 18;
 
   alias_set_type alias_set;
   tree pointer_to;
@@ -1624,7 +1625,11 @@ struct GTY(()) tree_decl_common {
   /* DECL_ALIGN.  It should have the same size as TYPE_ALIGN.  */
   unsigned int align : 6;
 
-  /* 20 bits unused.  */
+  /* DECL_WARN_IF_NOT_ALIGN.  It should have the same size as
+     TYPE_WARN_IF_NOT_ALIGN.  */
+  unsigned int warn_if_not_align : 6;
+
+  /* 14 bits unused.  */
 
   /* UID for points-to sets, stable over copying from inlining.  */
   unsigned int pt_uid;
diff --git a/gcc/tree.c b/gcc/tree.c
index a58f9aa..66287ae 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -8303,6 +8303,7 @@ build_range_type_1 (tree type, tree lowval, tree highval, bool shared)
   TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
   SET_TYPE_ALIGN (itype, TYPE_ALIGN (type));
   TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (type);
+  SET_TYPE_WARN_IF_NOT_ALIGN (itype, TYPE_WARN_IF_NOT_ALIGN (type));
 
   if (!shared)
     return itype;
diff --git a/gcc/tree.h b/gcc/tree.h
index 7de1a77..3faf1af 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1922,6 +1922,16 @@ extern machine_mode element_mode (const_tree t);
 /* The alignment for NODE, in bytes.  */
 #define TYPE_ALIGN_UNIT(NODE) (TYPE_ALIGN (NODE) / BITS_PER_UNIT)
 
+/* The minimum alignment necessary for objects of this type without
+   warning.  The value is an int, measured in bits.  */
+#define TYPE_WARN_IF_NOT_ALIGN(NODE) \
+    (TYPE_CHECK (NODE)->type_common.warn_if_not_align \
+     ? ((unsigned)1) << ((NODE)->type_common.warn_if_not_align - 1) : 0)
+
+/* Specify that TYPE_WARN_IF_NOT_ALIGN(NODE) is X.  */
+#define SET_TYPE_WARN_IF_NOT_ALIGN(NODE, X) \
+    (TYPE_CHECK (NODE)->type_common.warn_if_not_align = ffs_hwi (X))
+
 /* If your language allows you to declare types, and you want debug info
    for them, then you need to generate corresponding TYPE_DECL nodes.
    These "stub" TYPE_DECL nodes have no name, and simply point at the
@@ -2377,6 +2387,16 @@ extern machine_mode element_mode (const_tree t);
 #define SET_DECL_ALIGN(NODE, X) \
     (DECL_COMMON_CHECK (NODE)->decl_common.align = ffs_hwi (X))
 
+/* The minimum alignment necessary for the datum, in bits, without
+   warning.  */
+#define DECL_WARN_IF_NOT_ALIGN(NODE) \
+    (DECL_COMMON_CHECK (NODE)->decl_common.warn_if_not_align \
+     ? ((unsigned)1) << ((NODE)->decl_common.warn_if_not_align - 1) : 0)
+
+/* Specify that DECL_WARN_IF_NOT_ALIGN(NODE) is X.  */
+#define SET_DECL_WARN_IF_NOT_ALIGN(NODE, X) \
+    (DECL_COMMON_CHECK (NODE)->decl_common.warn_if_not_align = ffs_hwi (X))
+
 /* The alignment of NODE, in bytes.  */
 #define DECL_ALIGN_UNIT(NODE) (DECL_ALIGN (NODE) / BITS_PER_UNIT)
 /* Set if the alignment of this DECL has been set by the user, for
-- 
2.9.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]