public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: [PATCH] Add warn_if_not_aligned attribute
@ 2017-06-04 15:52 H.J. Lu
  2017-06-05 15:11 ` Joseph Myers
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-04 15:52 UTC (permalink / raw)
  To: gcc-patches

__attribute__((warn_if_not_aligned(N))) issues 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

The same warning is also issued without the warn_if_not_aligned attribute
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

gcc/

	PR c/53037
	* c-decl.c (finish_enum): Also copy TYPE_WARN_IF_NOT_ALIGN.
	* print-tree.c (print_node): Support TYPE_WARN_IF_NOT_ALIGN.
	* stor-layout.c (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.c (build_range_type_1): Likewise.
	* tree-core.h (tree_type_common): Add warn_if_not_align.  Set
	spare to 18.
	* tree.h (TYPE_WARN_IF_NOT_ALIGN): New.
	(SET_TYPE_WARN_IF_NOT_ALIGN): Likewise.
	* c-family/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/c-decl.c (finish_enum): Copy TYPE_WARN_IF_NOT_ALIGN.

gcc/testsuite/

	PR c/53037
	* gcc.dg/pr53037-1.c: New test.
---
 gcc/c-family/c-attribs.c         | 55 +++++++++++++++++++++++++++++++++----
 gcc/c/c-decl.c                   |  2 ++
 gcc/print-tree.c                 |  6 ++--
 gcc/stor-layout.c                | 45 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr53037-1.c | 59 ++++++++++++++++++++++++++++++++++++++++
 gcc/tree-core.h                  |  3 +-
 gcc/tree.c                       |  1 +
 gcc/tree.h                       | 10 +++++++
 8 files changed, 172 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-1.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 695c58c..a76f9f7 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)
 {
   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)
+	{
+	  SET_TYPE_WARN_IF_NOT_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+	  warn_if_not_aligned = 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)
@@ -1650,9 +1664,38 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       DECL_USER_ALIGN (decl) = 1;
     }
 
+  if (warn_if_not_aligned)
+    {
+      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/c-decl.c b/gcc/c/c-decl.c
index f2b8096..f27356b 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -8363,6 +8363,8 @@ finish_enum (tree enumtype, tree values, tree attributes)
       TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
       SET_TYPE_ALIGN (tem, TYPE_ALIGN (enumtype));
       TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype);
+      SET_TYPE_WARN_IF_NOT_ALIGN (tem,
+				  TYPE_WARN_IF_NOT_ALIGN (enumtype));
       TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype);
       TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype);
     }
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index ea26a0b..7b53c49 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -603,8 +603,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..28249bc 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1074,6 +1074,38 @@ 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 = TYPE_WARN_IF_NOT_ALIGN (type);
+
+  if (!warn_if_not_align && 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 +1116,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 +1202,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 +1324,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 +1365,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 +1517,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 +2128,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 +2366,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/gcc.dg/pr53037-1.c b/gcc/testsuite/gcc.dg/pr53037-1.c
new file mode 100644
index 0000000..1ab1f86
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-1.c
@@ -0,0 +1,59 @@
+/* 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)));
+
+union bar1
+{
+  int i1;
+  int i3;
+  __u64 x;
+}; /* { dg-warning "alignment 4 of 'union bar1' is less than 8" } */
+
+union bar2
+{
+  int i1;
+  int i3;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+struct __attribute__ ((aligned (8))) S8 { char a[8]; };
+struct __attribute__ ((packed)) S0 {
+  struct S8 s8;
+}; /* { dg-warning "alignment 1 of 'struct S0' is less than 8" } */
+
+struct __attribute__ ((packed)) S1 {
+   long long ll;
+};
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index ea73477..0882bdc 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;
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 c6e883c..7d9572e 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
-- 
2.9.4

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-04 15:52 RFC: [PATCH] Add warn_if_not_aligned attribute H.J. Lu
@ 2017-06-05 15:11 ` Joseph Myers
  2017-06-05 17:45   ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Joseph Myers @ 2017-06-05 15:11 UTC (permalink / raw)
  To: H.J. Lu; +Cc: gcc-patches

The new attribute needs documentation.  Should the test be in c-c++-common 
or does this feature not support C++?

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-05 15:11 ` Joseph Myers
@ 2017-06-05 17:45   ` H.J. Lu
  2017-06-06 16:07     ` Martin Sebor
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-05 17:45 UTC (permalink / raw)
  To: Joseph Myers; +Cc: GCC Patches

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

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

-- 
H.J.

[-- Attachment #2: 0001-Add-warn_if_not_aligned-attribute.patch --]
[-- Type: text/x-patch, Size: 19487 bytes --]

From b427b82bf9e7e510a1c1d5a91aa8198dd8036232 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

__attribute__((warn_if_not_aligned(N))) issues 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

The same warning is also issued without the warn_if_not_aligned attribute
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

gcc/

	PR c/53037
	* c-decl.c (finish_enum): Also copy TYPE_WARN_IF_NOT_ALIGN.
	* print-tree.c (print_node): Support TYPE_WARN_IF_NOT_ALIGN.
	* stor-layout.c (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.c (build_range_type_1): Likewise.
	* tree-core.h (tree_type_common): Add warn_if_not_align.  Set
	spare to 18.
	* tree.h (TYPE_WARN_IF_NOT_ALIGN): New.
	(SET_TYPE_WARN_IF_NOT_ALIGN): Likewise.
	* c-family/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/c-decl.c (finish_enum): Copy TYPE_WARN_IF_NOT_ALIGN.
	* doc/extend.texi: Document warn_if_not_aligned attribute.

gcc/testsuite/

	PR c/53037
	* g++.dg/pr53037-1.C: New test.
	* gcc.dg/pr53037-1.c: Likewise.
---
 gcc/c-family/c-attribs.c         | 55 +++++++++++++++++++++++---
 gcc/c/c-decl.c                   |  2 +
 gcc/doc/extend.texi              | 50 ++++++++++++++++++++++++
 gcc/print-tree.c                 |  6 ++-
 gcc/stor-layout.c                | 45 +++++++++++++++++++++
 gcc/testsuite/g++.dg/pr53037-1.C | 84 ++++++++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr53037-1.c | 84 ++++++++++++++++++++++++++++++++++++++++
 gcc/tree-core.h                  |  3 +-
 gcc/tree.c                       |  1 +
 gcc/tree.h                       | 10 +++++
 10 files changed, 331 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr53037-1.C
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-1.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 695c58c..a76f9f7 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)
 {
   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)
+	{
+	  SET_TYPE_WARN_IF_NOT_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+	  warn_if_not_aligned = 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)
@@ -1650,9 +1664,38 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       DECL_USER_ALIGN (decl) = 1;
     }
 
+  if (warn_if_not_aligned)
+    {
+      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/c-decl.c b/gcc/c/c-decl.c
index f2b8096..f27356b 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -8363,6 +8363,8 @@ finish_enum (tree enumtype, tree values, tree attributes)
       TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
       SET_TYPE_ALIGN (tem, TYPE_ALIGN (enumtype));
       TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype);
+      SET_TYPE_WARN_IF_NOT_ALIGN (tem,
+				  TYPE_WARN_IF_NOT_ALIGN (enumtype));
       TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype);
       TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype);
     }
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 60a1a3f..0063df2 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5677,6 +5677,56 @@ 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
+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
+
 @item cleanup (@var{cleanup_function})
 @cindex @code{cleanup} variable attribute
 The @code{cleanup} attribute runs a function when the variable goes
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index ea26a0b..7b53c49 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -603,8 +603,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..28249bc 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1074,6 +1074,38 @@ 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 = TYPE_WARN_IF_NOT_ALIGN (type);
+
+  if (!warn_if_not_align && 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 +1116,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 +1202,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 +1324,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 +1365,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 +1517,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 +2128,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 +2366,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/g++.dg/pr53037-1.C b/gcc/testsuite/g++.dg/pr53037-1.C
new file mode 100644
index 0000000..d05fe72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-1.C
@@ -0,0 +1,84 @@
+/* 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)));
+
+union bar1 /* { dg-warning "alignment 4 of 'bar1' is less than 8" } */
+{
+  int i1;
+  int i3;
+  __u64 x;
+};
+
+union bar2
+{
+  int i1;
+  int i3;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+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..a205579
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-1.c
@@ -0,0 +1,84 @@
+/* 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)));
+
+union bar1
+{
+  int i1;
+  int i3;
+  __u64 x;
+}; /* { dg-warning "alignment 4 of 'union bar1' is less than 8" } */
+
+union bar2
+{
+  int i1;
+  int i3;
+  __u64 x;
+} __attribute__((aligned(8)));
+
+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..0882bdc 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;
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 c6e883c..7d9572e 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
-- 
2.9.4


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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-05 17:45   ` H.J. Lu
@ 2017-06-06 16:07     ` Martin Sebor
  2017-06-06 16:11       ` Martin Sebor
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Sebor @ 2017-06-06 16:07 UTC (permalink / raw)
  To: H.J. Lu, Joseph Myers; +Cc: GCC Patches

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.

Martin

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-06 16:07     ` Martin Sebor
@ 2017-06-06 16:11       ` Martin Sebor
  2017-06-06 16:59         ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Sebor @ 2017-06-06 16:11 UTC (permalink / raw)
  To: H.J. Lu, Joseph Myers; +Cc: GCC Patches

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

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-06 16:11       ` Martin Sebor
@ 2017-06-06 16:59         ` H.J. Lu
  2017-06-06 17:35           ` Martin Sebor
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-06 16:59 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Joseph Myers, GCC Patches

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?

-- 
H.J.

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-06 16:59         ` H.J. Lu
@ 2017-06-06 17:35           ` Martin Sebor
  2017-06-06 22:57             ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Sebor @ 2017-06-06 17:35 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph Myers, GCC Patches

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.

Martin

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-06 17:35           ` Martin Sebor
@ 2017-06-06 22:57             ` H.J. Lu
  2017-06-07  0:11               ` Martin Sebor
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-06 22:57 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Joseph Myers, GCC Patches

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?


-- 
H.J.

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-06 22:57             ` H.J. Lu
@ 2017-06-07  0:11               ` Martin Sebor
  2017-06-07 13:30                 ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Sebor @ 2017-06-07  0:11 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph Myers, GCC Patches

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.

Martin

PS [*] On a related note, in the Clang discussion of
-Waddress-of-packed-member they briefly considered reusing
-Wcast-align for the same purpose, but decided against it
because it apparently involves an explicit cast.  That
doesn't seem to me like a string enough argument not to
change -Wcast-align to trigger on implicit conversions that
increase alignment.  (The option is essentially useless on
most targets so this extension would make it generally
useful.)

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-07  0:11               ` Martin Sebor
@ 2017-06-07 13:30                 ` H.J. Lu
  2017-06-08 17:00                   ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-07 13:30 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Joseph Myers, GCC Patches

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.


-- 
H.J.

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-07 13:30                 ` H.J. Lu
@ 2017-06-08 17:00                   ` H.J. Lu
  2017-06-08 19:13                     ` Martin Sebor
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-08 17:00 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Joseph Myers, GCC Patches

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

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.

[-- Attachment #2: 0001-Add-warn_if_not_aligned-attribute.patch --]
[-- Type: text/x-patch, Size: 34969 bytes --]

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


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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-08 17:00                   ` H.J. Lu
@ 2017-06-08 19:13                     ` Martin Sebor
  2017-06-09 13:31                       ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Sebor @ 2017-06-08 19:13 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph Myers, GCC Patches

On 06/08/2017 11:00 AM, H.J. Lu wrote:
> 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.

Okay.  I can't approve the patch but thank you for enhancing your
patch to handle the additional case I brought up!

Martin

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

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-08 19:13                     ` Martin Sebor
@ 2017-06-09 13:31                       ` H.J. Lu
  2017-06-15 15:38                         ` Martin Sebor
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-09 13:31 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Joseph Myers, GCC Patches

On Thu, Jun 8, 2017 at 12:13 PM, Martin Sebor <msebor@gmail.com> wrote:
> On 06/08/2017 11:00 AM, H.J. Lu wrote:
>>
>> 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.
>
>
> Okay.  I can't approve the patch but thank you for enhancing your
> patch to handle the additional case I brought up!
>
> Martin

Where do we go from here?

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

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-09 13:31                       ` H.J. Lu
@ 2017-06-15 15:38                         ` Martin Sebor
  2017-06-15 15:47                           ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Martin Sebor @ 2017-06-15 15:38 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph Myers, GCC Patches

On 06/09/2017 07:31 AM, H.J. Lu wrote:
> On Thu, Jun 8, 2017 at 12:13 PM, Martin Sebor <msebor@gmail.com> wrote:
>> On 06/08/2017 11:00 AM, H.J. Lu wrote:
>>>
>>> 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.
>>
>>
>> Okay.  I can't approve the patch but thank you for enhancing your
>> patch to handle the additional case I brought up!
>>
>> Martin
>
> Where do we go from here?

Other than the C and C++ maintainers needing to approve the patch
I can't think of anything else.

If you think it's worthwhile to merge the two options into one
(or perhaps even incorporate them into -Wpacked) that can be done
afterwards.

Martin

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

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-15 15:38                         ` Martin Sebor
@ 2017-06-15 15:47                           ` H.J. Lu
  2017-06-15 17:31                             ` Joseph Myers
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-15 15:47 UTC (permalink / raw)
  To: Martin Sebor, Jason Merrill; +Cc: Joseph Myers, GCC Patches

On Thu, Jun 15, 2017 at 8:38 AM, Martin Sebor <msebor@gmail.com> wrote:
>>
>> Where do we go from here?
>
>
> Other than the C and C++ maintainers needing to approve the patch
> I can't think of anything else.

Hi Joseph, Jason,

The complete patch is at

https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00541.html

Is this OK for trunk?

> If you think it's worthwhile to merge the two options into one
> (or perhaps even incorporate them into -Wpacked) that can be done
> afterwards.

I can take a look after my patch is accepted.

Thanks.


H.J.

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-15 15:47                           ` H.J. Lu
@ 2017-06-15 17:31                             ` Joseph Myers
  2017-06-16 11:55                               ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Joseph Myers @ 2017-06-15 17:31 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Martin Sebor, Jason Merrill, GCC Patches

On Thu, 15 Jun 2017, H.J. Lu wrote:

> On Thu, Jun 15, 2017 at 8:38 AM, Martin Sebor <msebor@gmail.com> wrote:
> >>
> >> Where do we go from here?
> >
> >
> > Other than the C and C++ maintainers needing to approve the patch
> > I can't think of anything else.
> 
> Hi Joseph, Jason,
> 
> The complete patch is at
> 
> https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00541.html
> 
> Is this OK for trunk?

I'd expect the warning calls to include OPT_Wif_not_aligned or 
OPT_Wpacked_not_aligned (as appropriate, depending on what triggered the 
warning / would disable it), so the warning output includes an option 
name.

As the attribute is specific to fields I'd expect testcases that use of it 
on non-fields is diagnosed.  And I think the diagnostic for that should 
include quotes, %<warn_if_not_aligned%>.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-15 17:31                             ` Joseph Myers
@ 2017-06-16 11:55                               ` H.J. Lu
  2017-07-06 15:45                                 ` Joseph Myers
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-06-16 11:55 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Martin Sebor, Jason Merrill, GCC Patches

On Thu, Jun 15, 2017 at 05:31:34PM +0000, Joseph Myers wrote:
> On Thu, 15 Jun 2017, H.J. Lu wrote:
> 
> > On Thu, Jun 15, 2017 at 8:38 AM, Martin Sebor <msebor@gmail.com> wrote:
> > >>
> > >> Where do we go from here?
> > >
> > >
> > > Other than the C and C++ maintainers needing to approve the patch
> > > I can't think of anything else.
> > 
> > Hi Joseph, Jason,
> > 
> > The complete patch is at
> > 
> > https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00541.html
> > 
> > Is this OK for trunk?
> 
> I'd expect the warning calls to include OPT_Wif_not_aligned or 
> OPT_Wpacked_not_aligned (as appropriate, depending on what triggered the 
> warning / would disable it), so the warning output includes an option 
> name.
> 

Done.

> As the attribute is specific to fields I'd expect testcases that use of it 

Done.

> on non-fields is diagnosed.  And I think the diagnostic for that should 
> include quotes, %<warn_if_not_aligned%>.
> 

Done.

Here is the updated patch.  OK for trunk?

Thanks.


H.J.
---
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): Copy TYPE_WARN_IF_NOT_ALIGN.
	* 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 DECL_WARN_IF_NOT_ALIGN.

gcc/cp/

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

gcc/testsuite/

	PR c/53037
	* c-c++-common/pr53037-5.c: New test.
	* g++.dg/pr53037-1.C: Likewise.
	* g++.dg/pr53037-2.C: Likewise.
	* g++.dg/pr53037-3.C: Likewise.
	* g++.dg/pr53037-4.C: Likewise.
	* gcc.dg/pr53037-1.c: Likewise.
	* gcc.dg/pr53037-2.c: Likewise.
	* gcc.dg/pr53037-3.c: Likewise.
	* gcc.dg/pr53037-4.c: Likewise.
---
 gcc/c-family/c-attribs.c               | 68 ++++++++++++++++++++++----
 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                      | 63 ++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.C       | 11 +++++
 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/testsuite/gcc.dg/pr53037-4.c       | 11 +++++
 gcc/tree-core.h                        |  9 +++-
 gcc/tree.c                             |  1 +
 gcc/tree.h                             | 20 ++++++++
 20 files changed, 701 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.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
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-4.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 2b6845f..d01f623 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -88,6 +88,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 *);
@@ -211,6 +213,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,
@@ -1640,12 +1645,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;
@@ -1694,8 +1700,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)
@@ -1728,13 +1742,51 @@ 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 && TREE_CODE (decl) == FIELD_DECL)
+	{
+	  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 317d5cd..144174e 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2384,6 +2384,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 3711476..ab22f98 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2527,6 +2527,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 1de17b4..d5abe35 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5707,6 +5707,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
@@ -6560,6 +6595,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 653bc07..5bf2a2d 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..ae6f981 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,54 @@ 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;
+
+  int opt_w = 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)
+	opt_w = OPT_Wif_not_aligned;
+    }
+
+  if (!warn_if_not_align
+      && warn_packed_not_aligned
+      && TYPE_USER_ALIGN (type))
+    {
+      warn_if_not_align = TYPE_ALIGN (type);
+      opt_w = OPT_Wpacked_not_aligned;
+    }
+
+  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 (opt_w, "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 (opt_w, "%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 +1134,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 +1220,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 +1342,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 +1383,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 +1535,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 +2146,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 +2384,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-5.c b/gcc/testsuite/c-c++-common/pr53037-5.c
new file mode 100644
index 0000000..97d54b1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.C b/gcc/testsuite/g++.dg/pr53037-4.C
new file mode 100644
index 0000000..525483d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-4.C
@@ -0,0 +1,11 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int foo __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo'" } */
+
+__attribute__((warn_if_not_aligned(8)))
+void
+bar (void) /* { dg-error "'warn_if_not_aligned' may not be specified for 'void bar\\(\\)'" } */
+{
+}
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/testsuite/gcc.dg/pr53037-4.c b/gcc/testsuite/gcc.dg/pr53037-4.c
new file mode 100644
index 0000000..665f828
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-4.c
@@ -0,0 +1,11 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int foo __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo'" } */
+
+__attribute__((warn_if_not_aligned(8)))
+void
+bar (void) /* { dg-error "'warn_if_not_aligned' may not be specified for 'bar'" } */
+{
+}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 34e5c17..a31d4e6 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1519,8 +1519,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;
@@ -1627,7 +1628,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 2602803..e4b5892 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 bfe83f7..bb8d927 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

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-06-16 11:55                               ` H.J. Lu
@ 2017-07-06 15:45                                 ` Joseph Myers
  2017-07-08 13:45                                   ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Joseph Myers @ 2017-07-06 15:45 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Martin Sebor, Jason Merrill, GCC Patches

On Fri, 16 Jun 2017, H.J. Lu wrote:

> +@code{warning: alignment 8 of 'struct foo' is less than 16}.

I think @samp is better than @code for warnings, throughout, since they 
aren't pieces of program code.

> +This warning can be disabled by @option{-Wno-if-not-aligned}.
> +The @code{warn_if_not_aligned } attribute can also be used for types

Stray space before }.

> +static void
> +handle_warn_if_not_align (tree field, unsigned int record_align)

Missing comment above this function explaining its semantics and those of 
its arguments.

> +  if ((record_align % warn_if_not_align) != 0)
> +    warning (opt_w, "alignment %d of %qT is less than %d",
> +	     record_align, context, warn_if_not_align);

I'd expect %u for unsigned int alignments, instead of %d.

> +  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 (opt_w, "%q+D offset %d in %qT isn't aligned to %d",
> +	     field, off, context, warn_if_not_align);

And you can have struct offsets that don't fit in unsigned int (i.e. 
structures over 4 GB), so should be using unsigned HOST_WIDE_INT to store 
the offset and %wu to print it.  (Whereas various places in GCC restrict 
alignments to unsigned int.)

What happens if you specify the attribute on a bit-field, or on a type 
used to declare a bit-field?  I don't think either of those particularly 
makes sense, but I don't see tests for it either.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-07-06 15:45                                 ` Joseph Myers
@ 2017-07-08 13:45                                   ` H.J. Lu
  2017-08-17 14:19                                     ` Joseph Myers
  0 siblings, 1 reply; 24+ messages in thread
From: H.J. Lu @ 2017-07-08 13:45 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Martin Sebor, Jason Merrill, GCC Patches

On Thu, Jul 06, 2017 at 03:44:57PM +0000, Joseph Myers wrote:
> On Fri, 16 Jun 2017, H.J. Lu wrote:
> 
> > +@code{warning: alignment 8 of 'struct foo' is less than 16}.
> 
> I think @samp is better than @code for warnings, throughout, since they 
> aren't pieces of program code.

Done.

> 
> > +This warning can be disabled by @option{-Wno-if-not-aligned}.
> > +The @code{warn_if_not_aligned } attribute can also be used for types
> 
> Stray space before }.

Done.

> 
> > +static void
> > +handle_warn_if_not_align (tree field, unsigned int record_align)
> 
> Missing comment above this function explaining its semantics and those of 
> its arguments.
> 

Done.

> > +  if ((record_align % warn_if_not_align) != 0)
> > +    warning (opt_w, "alignment %d of %qT is less than %d",
> > +	     record_align, context, warn_if_not_align);
> 
> I'd expect %u for unsigned int alignments, instead of %d.

Done.

> 
> > +  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 (opt_w, "%q+D offset %d in %qT isn't aligned to %d",
> > +	     field, off, context, warn_if_not_align);
> 
> And you can have struct offsets that don't fit in unsigned int (i.e. 
> structures over 4 GB), so should be using unsigned HOST_WIDE_INT to store 
> the offset and %wu to print it.  (Whereas various places in GCC restrict 
> alignments to unsigned int.)

Done.

> 
> What happens if you specify the attribute on a bit-field, or on a type 
> used to declare a bit-field?  I don't think either of those particularly 
> makes sense, but I don't see tests for it either.
> 

I fixed it and added some testcases.

Here is the updated patch.  OK for master?

Thanks.


H.J.
----
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): Copy TYPE_WARN_IF_NOT_ALIGN.
	* 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 DECL_WARN_IF_NOT_ALIGN.
	(grokfield): Don't allow bit-field with warn_if_not_aligned type.

gcc/cp/

	PR c/53037
	* decl.c (duplicate_decls): Also merge DECL_WARN_IF_NOT_ALIGN.
	* decl2.c (grokbitfield): Don't allow bit-field with
	warn_if_not_aligned type.

gcc/testsuite/

	PR c/53037
	* c-c++-common/pr53037-5.c: New test.
	* g++.dg/pr53037-1.C: Likewise.
	* g++.dg/pr53037-2.C: Likewise.
	* g++.dg/pr53037-3.C: Likewise.
	* g++.dg/pr53037-4.C: Likewise.
	* gcc.dg/pr53037-1.c: Likewise.
	* gcc.dg/pr53037-2.c: Likewise.
	* gcc.dg/pr53037-3.c: Likewise.
	* gcc.dg/pr53037-4.c: Likewise.
---
 gcc/c-family/c-attribs.c               | 71 +++++++++++++++++++++++----
 gcc/c-family/c.opt                     |  8 ++++
 gcc/c/c-decl.c                         | 11 +++++
 gcc/cp/decl.c                          |  4 ++
 gcc/cp/decl2.c                         |  7 +++
 gcc/doc/extend.texi                    | 87 ++++++++++++++++++++++++++++++++++
 gcc/doc/invoke.texi                    | 29 +++++++++++-
 gcc/print-tree.c                       |  9 ++--
 gcc/stor-layout.c                      | 66 ++++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.C       | 24 ++++++++++
 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/testsuite/gcc.dg/pr53037-4.c       | 24 ++++++++++
 gcc/tree-core.h                        |  9 +++-
 gcc/tree.c                             |  1 +
 gcc/tree.h                             | 20 ++++++++
 21 files changed, 747 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.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
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-4.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 626ffa1..200e8ae 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -88,6 +88,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 *);
@@ -211,6 +213,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,
@@ -1640,12 +1645,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;
@@ -1694,8 +1700,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)
@@ -1728,13 +1742,54 @@ 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)
+	{
+	  if (TREE_CODE (decl) == FIELD_DECL && !DECL_INITIAL (decl))
+	    {
+	      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 05766c4..1dc380e 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) IntegerRange(0, 2)
 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.
@@ -710,6 +714,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 317d5cd..45d561d 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2384,6 +2384,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.  */
@@ -7588,6 +7592,13 @@ grokfield (location_t loc,
   finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE);
   DECL_INITIAL (value) = width;
 
+  if (width && TYPE_WARN_IF_NOT_ALIGN (TREE_TYPE (value)))
+    {
+      error_at (loc, "cannot declare bit-field %q+D with %<warn_if_not_aligned%> type",
+		value);
+      TREE_TYPE (value) = error_mark_node;
+    }
+
   if (warn_cxx_compat && DECL_NAME (value) != NULL_TREE)
     {
       /* If we currently have a binding for this field, set the
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 43a94d9..0c34b1b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2510,6 +2510,10 @@ next_arg:;
       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/cp/decl2.c b/gcc/cp/decl2.c
index 877745c..21bc917 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1008,6 +1008,13 @@ grokbitfield (const cp_declarator *declarator,
       return NULL_TREE;
     }
 
+  if (width && TYPE_WARN_IF_NOT_ALIGN (TREE_TYPE (value)))
+    {
+      error ("cannot declare bit-field %qD with %<warn_if_not_aligned%> type",
+	     DECL_NAME (value));
+      return NULL_TREE;
+    }
+
   if (DECL_IN_AGGR_P (value))
     {
       error ("%qD is already defined in the class %qT", value,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index d0abd7f..df141ca 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5707,6 +5707,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
+@samp{warning: alignment 8 of 'struct foo' is less than 16}.
+The compiler also issues a warning, like @samp{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
@@ -6560,6 +6595,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
+@samp{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
+@samp{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 aa848bb..23046ff 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -284,6 +284,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
@@ -298,7 +299,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
@@ -4427,6 +4428,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
@@ -6520,6 +6528,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 6a237cc..8bb6230 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..54edb5c 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,57 @@ update_alignment_for_field (record_layout_info rli, tree field,
   return desired_align;
 }
 
+/* Issue a warning if the record alignment, RECORD_ALIGN, is less than
+   the field alignment of FIELD or FIELD isn't aligned. */
+
+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;
+
+  int opt_w = 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)
+	opt_w = OPT_Wif_not_aligned;
+    }
+
+  if (!warn_if_not_align
+      && warn_packed_not_aligned
+      && TYPE_USER_ALIGN (type))
+    {
+      warn_if_not_align = TYPE_ALIGN (type);
+      opt_w = OPT_Wpacked_not_aligned;
+    }
+
+  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 (opt_w, "alignment %u of %qT is less than %u",
+	     record_align, context, warn_if_not_align);
+
+  unsigned HOST_WIDE_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 (opt_w, "%q+D offset %wu in %qT isn't aligned to %u",
+	     field, off, context, warn_if_not_align);
+}
+
 /* Called from place_field to handle unions.  */
 
 static void
@@ -1084,6 +1137,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 +1223,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 +1345,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 +1386,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 +1538,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 +2149,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 +2387,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-5.c b/gcc/testsuite/c-c++-common/pr53037-5.c
new file mode 100644
index 0000000..97d54b1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.C b/gcc/testsuite/g++.dg/pr53037-4.C
new file mode 100644
index 0000000..553dd9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-4.C
@@ -0,0 +1,24 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int foo1 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo1'" } */
+
+__attribute__((warn_if_not_aligned(8)))
+void
+foo2 (void) /* { dg-error "'warn_if_not_aligned' may not be specified for 'void foo2\\(\\)'" } */
+{
+}
+
+struct foo3
+{
+  int i : 2 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'i'" } */
+};
+
+typedef unsigned int __u32
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo4
+{
+  __u32 i : 2; /* { dg-error "cannot declare bit-field 'i' with 'warn_if_not_aligned' type" } */
+};
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/testsuite/gcc.dg/pr53037-4.c b/gcc/testsuite/gcc.dg/pr53037-4.c
new file mode 100644
index 0000000..feb3afa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-4.c
@@ -0,0 +1,24 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int foo1 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo1'" } */
+
+__attribute__((warn_if_not_aligned(8)))
+void
+foo2 (void) /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo2'" } */
+{
+}
+
+struct foo3
+{
+  int i : 2 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'i'" } */
+};
+
+typedef unsigned int __u32
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo4
+{
+  __u32 i : 2; /* { dg-error "cannot declare bit-field 'i' with 'warn_if_not_aligned' type" } */
+};
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 278d0c9..a58b673 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1523,8 +1523,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;
@@ -1631,7 +1632,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 ca28afa..87f6504 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -8305,6 +8305,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 91cf253..55f3ebf 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

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-07-08 13:45                                   ` H.J. Lu
@ 2017-08-17 14:19                                     ` Joseph Myers
  2017-08-17 16:23                                       ` H.J. Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Joseph Myers @ 2017-08-17 14:19 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Martin Sebor, Jason Merrill, GCC Patches

On Sat, 8 Jul 2017, H.J. Lu wrote:

> +@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:

Use @samp for warnings quoted in the manual, as previously discussed.

OK with that change, in the absence of C++ maintainer objections within 48 
hours.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-08-17 14:19                                     ` Joseph Myers
@ 2017-08-17 16:23                                       ` H.J. Lu
  2017-08-18  1:40                                         ` Jason Merrill
  2017-08-21 12:02                                         ` Szabolcs Nagy
  0 siblings, 2 replies; 24+ messages in thread
From: H.J. Lu @ 2017-08-17 16:23 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Martin Sebor, Jason Merrill, GCC Patches

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

On Thu, Aug 17, 2017 at 6:52 AM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Sat, 8 Jul 2017, H.J. Lu wrote:
>
>> +@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:
>
> Use @samp for warnings quoted in the manual, as previously discussed.
>
> OK with that change, in the absence of C++ maintainer objections within 48
> hours.
>

Here is the updated patch.  I moved c++ changes to merge_decls, where
alignment is merged,  and check_bitfield_type_and_width, where bit-fields
are checked.

Tested on x86-64 and i686.


-- 
H.J.

[-- Attachment #2: 0001-Add-warn_if_not_aligned-attribute.patch --]
[-- Type: text/x-patch, Size: 38687 bytes --]

From 441bd3479a83093ad46fbaa67d270d69808c05b2 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

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): Copy TYPE_WARN_IF_NOT_ALIGN.
	* 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 DECL_WARN_IF_NOT_ALIGN.
	(check_bitfield_type_and_width): Don't allow bit-field with
	warn_if_not_aligned type.

gcc/cp/

	PR c/53037
	* decl.c (duplicate_decls): Also merge DECL_WARN_IF_NOT_ALIGN.
	* decl2.c (grokbitfield): Don't allow bit-field with
	warn_if_not_aligned type.

gcc/testsuite/

	PR c/53037
	* c-c++-common/pr53037-5.c: New test.
	* g++.dg/pr53037-1.C: Likewise.
	* g++.dg/pr53037-2.C: Likewise.
	* g++.dg/pr53037-3.C: Likewise.
	* g++.dg/pr53037-4.C: Likewise.
	* gcc.dg/pr53037-1.c: Likewise.
	* gcc.dg/pr53037-2.c: Likewise.
	* gcc.dg/pr53037-3.c: Likewise.
	* gcc.dg/pr53037-4.c: Likewise.
---
 gcc/c-family/c-attribs.c               | 71 +++++++++++++++++++++++----
 gcc/c-family/c.opt                     |  8 ++++
 gcc/c/c-decl.c                         | 11 +++++
 gcc/cp/decl.c                          |  4 ++
 gcc/cp/decl2.c                         |  7 +++
 gcc/doc/extend.texi                    | 87 ++++++++++++++++++++++++++++++++++
 gcc/doc/invoke.texi                    | 29 +++++++++++-
 gcc/print-tree.c                       |  9 ++--
 gcc/stor-layout.c                      | 66 ++++++++++++++++++++++++++
 gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.C       | 24 ++++++++++
 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/testsuite/gcc.dg/pr53037-4.c       | 24 ++++++++++
 gcc/tree-core.h                        |  9 +++-
 gcc/tree.c                             |  1 +
 gcc/tree.h                             | 20 ++++++++
 21 files changed, 747 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr53037-5.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/g++.dg/pr53037-4.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
 create mode 100644 gcc/testsuite/gcc.dg/pr53037-4.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 626ffa1cde7..200e8ae4eed 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -88,6 +88,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 *);
@@ -211,6 +213,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,
@@ -1640,12 +1645,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;
@@ -1694,8 +1700,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)
@@ -1728,13 +1742,54 @@ 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)
+	{
+	  if (TREE_CODE (decl) == FIELD_DECL && !DECL_INITIAL (decl))
+	    {
+	      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 05766c47856..1dc380eea35 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) IntegerRange(0, 2)
 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.
@@ -710,6 +714,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 317d5cdd099..8b49ab9a0e2 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2384,6 +2384,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.  */
@@ -5390,6 +5394,13 @@ check_bitfield_type_and_width (location_t loc, tree *type, tree *width,
       *type = unsigned_type_node;
     }
 
+  if (TYPE_WARN_IF_NOT_ALIGN (*type))
+    {
+      error_at (loc, "cannot declare bit-field %qs with %<warn_if_not_aligned%> type",
+		name);
+      *type = unsigned_type_node;
+    }
+
   type_mv = TYPE_MAIN_VARIANT (*type);
   if (!in_system_header_at (input_location)
       && type_mv != integer_type_node
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 43a94d9f6eb..0c34b1baa09 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2510,6 +2510,10 @@ next_arg:;
       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/cp/decl2.c b/gcc/cp/decl2.c
index 877745c546b..21bc917e3e1 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1008,6 +1008,13 @@ grokbitfield (const cp_declarator *declarator,
       return NULL_TREE;
     }
 
+  if (width && TYPE_WARN_IF_NOT_ALIGN (TREE_TYPE (value)))
+    {
+      error ("cannot declare bit-field %qD with %<warn_if_not_aligned%> type",
+	     DECL_NAME (value));
+      return NULL_TREE;
+    }
+
   if (DECL_IN_AGGR_P (value))
     {
       error ("%qD is already defined in the class %qT", value,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index d0abd7faadf..df141caca7d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5707,6 +5707,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
+@samp{warning: alignment 8 of 'struct foo' is less than 16}.
+The compiler also issues a warning, like @samp{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
@@ -6560,6 +6595,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
+@samp{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
+@samp{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 aa848bb2348..23046ff81b7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -284,6 +284,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
@@ -298,7 +299,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
@@ -4427,6 +4428,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
@@ -6520,6 +6528,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 6a237cc1253..8bb62308775 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 1574e4383e8..54edb5c9ef4 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,57 @@ update_alignment_for_field (record_layout_info rli, tree field,
   return desired_align;
 }
 
+/* Issue a warning if the record alignment, RECORD_ALIGN, is less than
+   the field alignment of FIELD or FIELD isn't aligned. */
+
+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;
+
+  int opt_w = 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)
+	opt_w = OPT_Wif_not_aligned;
+    }
+
+  if (!warn_if_not_align
+      && warn_packed_not_aligned
+      && TYPE_USER_ALIGN (type))
+    {
+      warn_if_not_align = TYPE_ALIGN (type);
+      opt_w = OPT_Wpacked_not_aligned;
+    }
+
+  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 (opt_w, "alignment %u of %qT is less than %u",
+	     record_align, context, warn_if_not_align);
+
+  unsigned HOST_WIDE_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 (opt_w, "%q+D offset %wu in %qT isn't aligned to %u",
+	     field, off, context, warn_if_not_align);
+}
+
 /* Called from place_field to handle unions.  */
 
 static void
@@ -1084,6 +1137,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 +1223,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 +1345,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 +1386,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 +1538,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 +2149,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 +2387,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-5.c b/gcc/testsuite/c-c++-common/pr53037-5.c
new file mode 100644
index 00000000000..97d54b19acf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr53037-5.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 00000000000..a3d8f99b54e
--- /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 00000000000..e617f9051f0
--- /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 00000000000..1ed6354f677
--- /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/g++.dg/pr53037-4.C b/gcc/testsuite/g++.dg/pr53037-4.C
new file mode 100644
index 00000000000..553dd9a6c45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr53037-4.C
@@ -0,0 +1,24 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int foo1 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo1'" } */
+
+__attribute__((warn_if_not_aligned(8)))
+void
+foo2 (void) /* { dg-error "'warn_if_not_aligned' may not be specified for 'void foo2\\(\\)'" } */
+{
+}
+
+struct foo3
+{
+  int i : 2 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'i'" } */
+};
+
+typedef unsigned int __u32
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo4
+{
+  __u32 i : 2; /* { dg-error "cannot declare bit-field 'i' with 'warn_if_not_aligned' type" } */
+};
diff --git a/gcc/testsuite/gcc.dg/pr53037-1.c b/gcc/testsuite/gcc.dg/pr53037-1.c
new file mode 100644
index 00000000000..93af0a50cd4
--- /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 00000000000..f9934a63e17
--- /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 00000000000..fc69ae8e52e
--- /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/testsuite/gcc.dg/pr53037-4.c b/gcc/testsuite/gcc.dg/pr53037-4.c
new file mode 100644
index 00000000000..feb3afad2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr53037-4.c
@@ -0,0 +1,24 @@
+/* PR c/53037.  */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int foo1 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo1'" } */
+
+__attribute__((warn_if_not_aligned(8)))
+void
+foo2 (void) /* { dg-error "'warn_if_not_aligned' may not be specified for 'foo2'" } */
+{
+}
+
+struct foo3
+{
+  int i : 2 __attribute__((warn_if_not_aligned(8))); /* { dg-error "'warn_if_not_aligned' may not be specified for 'i'" } */
+};
+
+typedef unsigned int __u32
+  __attribute__((aligned(4),warn_if_not_aligned(8)));
+
+struct foo4
+{
+  __u32 i : 2; /* { dg-error "cannot declare bit-field 'i' with 'warn_if_not_aligned' type" } */
+};
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 278d0c9b8f8..a58b673eb10 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1523,8 +1523,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;
@@ -1631,7 +1632,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 ca28afad0f2..87f6504998e 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -8305,6 +8305,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 91cf253dee5..55f3ebfa231 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.13.5


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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-08-17 16:23                                       ` H.J. Lu
@ 2017-08-18  1:40                                         ` Jason Merrill
  2017-08-21 12:02                                         ` Szabolcs Nagy
  1 sibling, 0 replies; 24+ messages in thread
From: Jason Merrill @ 2017-08-18  1:40 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Joseph Myers, Martin Sebor, GCC Patches

On Thu, Aug 17, 2017 at 7:56 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Thu, Aug 17, 2017 at 6:52 AM, Joseph Myers <joseph@codesourcery.com> wrote:
>> On Sat, 8 Jul 2017, H.J. Lu wrote:
>>
>>> +@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:
>>
>> Use @samp for warnings quoted in the manual, as previously discussed.
>>
>> OK with that change, in the absence of C++ maintainer objections within 48
>> hours.
>>
>
> Here is the updated patch.  I moved c++ changes to merge_decls, where
> alignment is merged,  and check_bitfield_type_and_width, where bit-fields
> are checked.

OK.

Jason

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-08-17 16:23                                       ` H.J. Lu
  2017-08-18  1:40                                         ` Jason Merrill
@ 2017-08-21 12:02                                         ` Szabolcs Nagy
  2017-08-21 12:57                                           ` H.J. Lu
  1 sibling, 1 reply; 24+ messages in thread
From: Szabolcs Nagy @ 2017-08-21 12:02 UTC (permalink / raw)
  To: H.J. Lu, Joseph Myers; +Cc: nd, Martin Sebor, Jason Merrill, GCC Patches

On 17/08/17 15:56, H.J. Lu wrote:
> On Thu, Aug 17, 2017 at 6:52 AM, Joseph Myers <joseph@codesourcery.com> wrote:
>> On Sat, 8 Jul 2017, H.J. Lu wrote:
>>
>>> +@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:
>>
>> Use @samp for warnings quoted in the manual, as previously discussed.
>>
>> OK with that change, in the absence of C++ maintainer objections within 48
>> hours.
>>
> 
> Here is the updated patch.  I moved c++ changes to merge_decls, where
> alignment is merged,  and check_bitfield_type_and_width, where bit-fields
> are checked.
> 
> Tested on x86-64 and i686.
> 

i assume packed semantics is same on arm so these
should warn on arm too ?

on arm i see:

FAIL: gcc.dg/pr53037-2.c  (test for warnings, line 8)
FAIL: gcc.dg/pr53037-2.c  (test for warnings, line 16)
FAIL: gcc.dg/pr53037-2.c  (test for warnings, line 32)
FAIL: gcc.dg/pr53037-3.c  (test for warnings, line 8)
FAIL: gcc.dg/pr53037-3.c  (test for warnings, line 16)
FAIL: gcc.dg/pr53037-3.c  (test for warnings, line 32)

FAIL: g++.dg/pr53037-2.C  -std=gnu++98  (test for warnings, line 6)
FAIL: g++.dg/pr53037-2.C  -std=gnu++98  (test for warnings, line 16)
FAIL: g++.dg/pr53037-2.C  -std=gnu++98  (test for warnings, line 29)
FAIL: g++.dg/pr53037-2.C  -std=gnu++11  (test for warnings, line 6)
FAIL: g++.dg/pr53037-2.C  -std=gnu++11  (test for warnings, line 16)
FAIL: g++.dg/pr53037-2.C  -std=gnu++11  (test for warnings, line 29)
FAIL: g++.dg/pr53037-2.C  -std=gnu++14  (test for warnings, line 6)
FAIL: g++.dg/pr53037-2.C  -std=gnu++14  (test for warnings, line 16)
FAIL: g++.dg/pr53037-2.C  -std=gnu++14  (test for warnings, line 29)
FAIL: g++.dg/pr53037-3.C  -std=gnu++98  (test for warnings, line 6)
FAIL: g++.dg/pr53037-3.C  -std=gnu++98  (test for warnings, line 16)
FAIL: g++.dg/pr53037-3.C  -std=gnu++98  (test for warnings, line 29)
FAIL: g++.dg/pr53037-3.C  -std=gnu++11  (test for warnings, line 6)
FAIL: g++.dg/pr53037-3.C  -std=gnu++11  (test for warnings, line 16)
FAIL: g++.dg/pr53037-3.C  -std=gnu++11  (test for warnings, line 29)
FAIL: g++.dg/pr53037-3.C  -std=gnu++14  (test for warnings, line 6)
FAIL: g++.dg/pr53037-3.C  -std=gnu++14  (test for warnings, line 16)
FAIL: g++.dg/pr53037-3.C  -std=gnu++14  (test for warnings, line 29)

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

* Re: RFC: [PATCH] Add warn_if_not_aligned attribute
  2017-08-21 12:02                                         ` Szabolcs Nagy
@ 2017-08-21 12:57                                           ` H.J. Lu
  0 siblings, 0 replies; 24+ messages in thread
From: H.J. Lu @ 2017-08-21 12:57 UTC (permalink / raw)
  To: Szabolcs Nagy; +Cc: Joseph Myers, nd, Martin Sebor, Jason Merrill, GCC Patches

On Mon, Aug 21, 2017 at 3:59 AM, Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
> On 17/08/17 15:56, H.J. Lu wrote:
>> On Thu, Aug 17, 2017 at 6:52 AM, Joseph Myers <joseph@codesourcery.com> wrote:
>>> On Sat, 8 Jul 2017, H.J. Lu wrote:
>>>
>>>> +@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:
>>>
>>> Use @samp for warnings quoted in the manual, as previously discussed.
>>>
>>> OK with that change, in the absence of C++ maintainer objections within 48
>>> hours.
>>>
>>
>> Here is the updated patch.  I moved c++ changes to merge_decls, where
>> alignment is merged,  and check_bitfield_type_and_width, where bit-fields
>> are checked.
>>
>> Tested on x86-64 and i686.
>>
>
> i assume packed semantics is same on arm so these
> should warn on arm too ?
>
> on arm i see:
>
> FAIL: gcc.dg/pr53037-2.c  (test for warnings, line 8)
> FAIL: gcc.dg/pr53037-2.c  (test for warnings, line 16)
> FAIL: gcc.dg/pr53037-2.c  (test for warnings, line 32)
> FAIL: gcc.dg/pr53037-3.c  (test for warnings, line 8)
> FAIL: gcc.dg/pr53037-3.c  (test for warnings, line 16)
> FAIL: gcc.dg/pr53037-3.c  (test for warnings, line 32)
>
> FAIL: g++.dg/pr53037-2.C  -std=gnu++98  (test for warnings, line 6)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++98  (test for warnings, line 16)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++98  (test for warnings, line 29)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++11  (test for warnings, line 6)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++11  (test for warnings, line 16)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++11  (test for warnings, line 29)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++14  (test for warnings, line 6)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++14  (test for warnings, line 16)
> FAIL: g++.dg/pr53037-2.C  -std=gnu++14  (test for warnings, line 29)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++98  (test for warnings, line 6)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++98  (test for warnings, line 16)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++98  (test for warnings, line 29)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++11  (test for warnings, line 6)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++11  (test for warnings, line 16)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++11  (test for warnings, line 29)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++14  (test for warnings, line 6)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++14  (test for warnings, line 16)
> FAIL: g++.dg/pr53037-3.C  -std=gnu++14  (test for warnings, line 29)
>

See:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53037#c29

-- 
H.J.

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

end of thread, other threads:[~2017-08-21 12:38 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-04 15:52 RFC: [PATCH] Add warn_if_not_aligned attribute H.J. Lu
2017-06-05 15:11 ` Joseph Myers
2017-06-05 17:45   ` H.J. Lu
2017-06-06 16:07     ` Martin Sebor
2017-06-06 16:11       ` Martin Sebor
2017-06-06 16:59         ` H.J. Lu
2017-06-06 17:35           ` Martin Sebor
2017-06-06 22:57             ` H.J. Lu
2017-06-07  0:11               ` Martin Sebor
2017-06-07 13:30                 ` H.J. Lu
2017-06-08 17:00                   ` H.J. Lu
2017-06-08 19:13                     ` Martin Sebor
2017-06-09 13:31                       ` H.J. Lu
2017-06-15 15:38                         ` Martin Sebor
2017-06-15 15:47                           ` H.J. Lu
2017-06-15 17:31                             ` Joseph Myers
2017-06-16 11:55                               ` H.J. Lu
2017-07-06 15:45                                 ` Joseph Myers
2017-07-08 13:45                                   ` H.J. Lu
2017-08-17 14:19                                     ` Joseph Myers
2017-08-17 16:23                                       ` H.J. Lu
2017-08-18  1:40                                         ` Jason Merrill
2017-08-21 12:02                                         ` Szabolcs Nagy
2017-08-21 12:57                                           ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).