diff mbox series

be more permissive about function alignments (PR 88208)

Message ID 19112bc8-83a2-2c35-2841-d95087cd1178@gmail.com
State New
Headers show
Series be more permissive about function alignments (PR 88208) | expand

Commit Message

Martin Sebor Nov. 28, 2018, 4:32 a.m. UTC
The tests for the new __builtin_has_attribute function have been
failing on a number of targets because of a couple of assumptions
that only hold on some.

First, they expect that it's safe to apply attribute aligned with
a smaller alignment than the target provides when GCC rejects such
arguments.  The tests pass on i86 and elsewhere but fail on
strictly aligned targets like aarch64 or sparc.  After some testing
and thinking I don't think this is helpful -- I believe it's better
to instead silently accept attributes that ask for a less restrictive
alignment than the function ultimately ends up with (see * below).
This is what testing shows Clang does on those targets.  The attached
patch implements this change.

Second, the tests assume that the priority forms of the constructor
and destructor attributes are universally supported.  That's also
not the case, even though the manual doesn't mention that.  To
avoid these failures the attached patch moves the priority forms
of the attribute constructor and destructor tests into its own
file that's compiled only for init_priority targets.

Finally, I noticed that attribute aligned accepts zero as
an argument even though it's not a power of two as the manual
documents as a precondition (zero is treated the same as
the attribute without an argument).  A zero argument is likely
to be a mistake, especially when the zero comes from macro
expansion, that users might want to know about.  Clang rejects
a zero with an error but I think a warning is more in line with
established GCC practice, so the patch also implements that.

Besides x86_64-linux, I tested this change with cross-compilers
for aarch64-linux-elf, powerpc64le-linux, and sparc-solaris2.11.
I added tests for the changed aligned attribute for those targets
To make the gcc.dg/builtin-has-attribute.c test pass with
the cross-compilers I changed from a runtime test into a compile
only one.

Martin

PS I'm not happy about duplicating the same test across all those
targets.  It would be much nicer to have a single test somewhere
in dg.exp #include a target-specific header with macros describing
the target-specific parameters.

[*] See the following discussion for some background:
   https://gcc.gnu.org/ml/gcc/2018-11/msg00127.html

Comments

Jeff Law Nov. 29, 2018, 3:48 a.m. UTC | #1
On 11/27/18 9:32 PM, Martin Sebor wrote:
> The tests for the new __builtin_has_attribute function have been
> failing on a number of targets because of a couple of assumptions
> that only hold on some.
> 
> First, they expect that it's safe to apply attribute aligned with
> a smaller alignment than the target provides when GCC rejects such
> arguments.  The tests pass on i86 and elsewhere but fail on
> strictly aligned targets like aarch64 or sparc.  After some testing
> and thinking I don't think this is helpful -- I believe it's better
> to instead silently accept attributes that ask for a less restrictive
> alignment than the function ultimately ends up with (see * below).
> This is what testing shows Clang does on those targets.  The attached
> patch implements this change.
> 
> Second, the tests assume that the priority forms of the constructor
> and destructor attributes are universally supported.  That's also
> not the case, even though the manual doesn't mention that.  To
> avoid these failures the attached patch moves the priority forms
> of the attribute constructor and destructor tests into its own
> file that's compiled only for init_priority targets.
> 
> Finally, I noticed that attribute aligned accepts zero as
> an argument even though it's not a power of two as the manual
> documents as a precondition (zero is treated the same as
> the attribute without an argument).  A zero argument is likely
> to be a mistake, especially when the zero comes from macro
> expansion, that users might want to know about.  Clang rejects
> a zero with an error but I think a warning is more in line with
> established GCC practice, so the patch also implements that.
> 
> Besides x86_64-linux, I tested this change with cross-compilers
> for aarch64-linux-elf, powerpc64le-linux, and sparc-solaris2.11.
> I added tests for the changed aligned attribute for those targets
> To make the gcc.dg/builtin-has-attribute.c test pass with
> the cross-compilers I changed from a runtime test into a compile
> only one.
> 
> Martin
> 
> PS I'm not happy about duplicating the same test across all those
> targets.  It would be much nicer to have a single test somewhere
> in dg.exp #include a target-specific header with macros describing
> the target-specific parameters.
> 
> [*] See the following discussion for some background:
>   https://gcc.gnu.org/ml/gcc/2018-11/msg00127.html
> 
> gcc-88208.diff
> 
> PR testsuite/88208 - new test case c-c++-common/builtin-has-attribute-3.c in r266335 has multiple excess errors
> 
> gcc/ChangeLog:
> 	PR testsuite/88208
> 	* doc/extend.texi (attribute constructor): Clarify.
> 
> gcc/c/ChangeLog:
> 
> 	PR testsuite/88208
> 	* c-decl.c (declspec_add_alignas): Adjust call to check_user_alignment.
> 
> gcc/c-family/ChangeLog:
> 
> 	PR testsuite/88208
> 	* c-attribs.c (common_handle_aligned_attribute): Silently avoid setting
> 	alignments to values less than the target requires.
> 	(has_attribute): For attribute aligned consider both the attribute
> 	and the alignment bits.
> 	* c-common.c (c_init_attributes): Optionally issue a warning for
> 	zero alignment.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR testsuite/88208
> 	* gcc.dg/attr-aligned-2.c: New test.
> 	* gcc.dg/builtin-has-attribute.c: Adjust.
> 	* c-c++-common/builtin-has-attribute-2.c: Same.
> 	* c-c++-common/builtin-has-attribute-3.c: Same.
> 	* c-c++-common/builtin-has-attribute-4.c: Same.
> 	* c-c++-common/builtin-has-attribute-5.c: New test.
> 	* gcc.target/aarch64/attr-aligned.c: Same.
> 	* gcc.target/i386/attr-aligned.c: Same.
> 	* gcc.target/powerpc/attr-aligned.c: Same.
> 	* gcc.target/sparc/attr-aligned.c: Same.
> 
> Index: gcc/c/c-decl.c
> ===================================================================
> --- gcc/c/c-decl.c	(revision 266521)
> +++ gcc/c/c-decl.c	(working copy)
> @@ -11061,12 +11061,15 @@ struct c_declspecs *
>  declspecs_add_alignas (location_t loc,
>  		       struct c_declspecs *specs, tree align)
>  {
> -  int align_log;
>    specs->alignas_p = true;
>    specs->locations[cdw_alignas] = loc;
>    if (align == error_mark_node)
>      return specs;
> -  align_log = check_user_alignment (align, false, true);
> +
> +  /* Only accept the alignment if it's valid and greater than
> +     the current one.  Zere is invalid but by C11 required to be
> +     silently ignored.  */
s/Zere/Zero/

OK with the nit fixed.
jeff
Rainer Orth Dec. 5, 2018, 1:09 p.m. UTC | #2
Hi Martin,

> The tests for the new __builtin_has_attribute function have been
> failing on a number of targets because of a couple of assumptions
> that only hold on some.
>
> First, they expect that it's safe to apply attribute aligned with
> a smaller alignment than the target provides when GCC rejects such
> arguments.  The tests pass on i86 and elsewhere but fail on
> strictly aligned targets like aarch64 or sparc.  After some testing
> and thinking I don't think this is helpful -- I believe it's better
> to instead silently accept attributes that ask for a less restrictive
> alignment than the function ultimately ends up with (see * below).
> This is what testing shows Clang does on those targets.  The attached
> patch implements this change.
>
> Second, the tests assume that the priority forms of the constructor
> and destructor attributes are universally supported.  That's also
> not the case, even though the manual doesn't mention that.  To
> avoid these failures the attached patch moves the priority forms
> of the attribute constructor and destructor tests into its own
> file that's compiled only for init_priority targets.
>
> Finally, I noticed that attribute aligned accepts zero as
> an argument even though it's not a power of two as the manual
> documents as a precondition (zero is treated the same as
> the attribute without an argument).  A zero argument is likely
> to be a mistake, especially when the zero comes from macro
> expansion, that users might want to know about.  Clang rejects
> a zero with an error but I think a warning is more in line with
> established GCC practice, so the patch also implements that.
>
> Besides x86_64-linux, I tested this change with cross-compilers
> for aarch64-linux-elf, powerpc64le-linux, and sparc-solaris2.11.
> I added tests for the changed aligned attribute for those targets
> To make the gcc.dg/builtin-has-attribute.c test pass with
> the cross-compilers I changed from a runtime test into a compile
> only one.
>
> Martin
>
> PS I'm not happy about duplicating the same test across all those
> targets.  It would be much nicer to have a single test somewhere
> in dg.exp #include a target-specific header with macros describing
> the target-specific parameters.

why so complicated?  Just have a single attr-aligned.c test, restricted
to the target cpus it supports via dg directives and with
MINALIGN/MAXALIGN definitions controlled by appropriate target macros?

Besides, the new gcc.target/sparc/attr-aligned.c test currently FAILs on
64-bit sparc:

FAIL: gcc.target/sparc/attr-aligned.c (test for excess errors)

Excess errors:
/vol/gcc/src/hg/trunk/local/gcc/testsuite/gcc.target/sparc/attr-aligned.c:29:1: error: static assertion failed: "alignof (f_) == MAXALIGN"

alignof (f_) is 16 for sparcv9.  The following patch fixes this, tested
on sparc-sun-solaris2.11 with -m32 and -m64.

Ok for mainline?

	Rainer
Jeff Law Dec. 5, 2018, 1:50 p.m. UTC | #3
On 12/5/18 6:09 AM, Rainer Orth wrote:
> Hi Martin,
> 
>> The tests for the new __builtin_has_attribute function have been
>> failing on a number of targets because of a couple of assumptions
>> that only hold on some.
>>
>> First, they expect that it's safe to apply attribute aligned with
>> a smaller alignment than the target provides when GCC rejects such
>> arguments.  The tests pass on i86 and elsewhere but fail on
>> strictly aligned targets like aarch64 or sparc.  After some testing
>> and thinking I don't think this is helpful -- I believe it's better
>> to instead silently accept attributes that ask for a less restrictive
>> alignment than the function ultimately ends up with (see * below).
>> This is what testing shows Clang does on those targets.  The attached
>> patch implements this change.
>>
>> Second, the tests assume that the priority forms of the constructor
>> and destructor attributes are universally supported.  That's also
>> not the case, even though the manual doesn't mention that.  To
>> avoid these failures the attached patch moves the priority forms
>> of the attribute constructor and destructor tests into its own
>> file that's compiled only for init_priority targets.
>>
>> Finally, I noticed that attribute aligned accepts zero as
>> an argument even though it's not a power of two as the manual
>> documents as a precondition (zero is treated the same as
>> the attribute without an argument).  A zero argument is likely
>> to be a mistake, especially when the zero comes from macro
>> expansion, that users might want to know about.  Clang rejects
>> a zero with an error but I think a warning is more in line with
>> established GCC practice, so the patch also implements that.
>>
>> Besides x86_64-linux, I tested this change with cross-compilers
>> for aarch64-linux-elf, powerpc64le-linux, and sparc-solaris2.11.
>> I added tests for the changed aligned attribute for those targets
>> To make the gcc.dg/builtin-has-attribute.c test pass with
>> the cross-compilers I changed from a runtime test into a compile
>> only one.
>>
>> Martin
>>
>> PS I'm not happy about duplicating the same test across all those
>> targets.  It would be much nicer to have a single test somewhere
>> in dg.exp #include a target-specific header with macros describing
>> the target-specific parameters.
> 
> why so complicated?  Just have a single attr-aligned.c test, restricted
> to the target cpus it supports via dg directives and with
> MINALIGN/MAXALIGN definitions controlled by appropriate target macros?
> 
> Besides, the new gcc.target/sparc/attr-aligned.c test currently FAILs on
> 64-bit sparc:
> 
> FAIL: gcc.target/sparc/attr-aligned.c (test for excess errors)
> 
> Excess errors:
> /vol/gcc/src/hg/trunk/local/gcc/testsuite/gcc.target/sparc/attr-aligned.c:29:1: error: static assertion failed: "alignof (f_) == MAXALIGN"
> 
> alignof (f_) is 16 for sparcv9.  The following patch fixes this, tested
> on sparc-sun-solaris2.11 with -m32 and -m64.
> 
> Ok for mainline?
OK
jeff
Martin Sebor Dec. 5, 2018, 4:05 p.m. UTC | #4
On 12/5/18 6:09 AM, Rainer Orth wrote:
> Hi Martin,
> 
>> The tests for the new __builtin_has_attribute function have been
>> failing on a number of targets because of a couple of assumptions
>> that only hold on some.
>>
>> First, they expect that it's safe to apply attribute aligned with
>> a smaller alignment than the target provides when GCC rejects such
>> arguments.  The tests pass on i86 and elsewhere but fail on
>> strictly aligned targets like aarch64 or sparc.  After some testing
>> and thinking I don't think this is helpful -- I believe it's better
>> to instead silently accept attributes that ask for a less restrictive
>> alignment than the function ultimately ends up with (see * below).
>> This is what testing shows Clang does on those targets.  The attached
>> patch implements this change.
>>
>> Second, the tests assume that the priority forms of the constructor
>> and destructor attributes are universally supported.  That's also
>> not the case, even though the manual doesn't mention that.  To
>> avoid these failures the attached patch moves the priority forms
>> of the attribute constructor and destructor tests into its own
>> file that's compiled only for init_priority targets.
>>
>> Finally, I noticed that attribute aligned accepts zero as
>> an argument even though it's not a power of two as the manual
>> documents as a precondition (zero is treated the same as
>> the attribute without an argument).  A zero argument is likely
>> to be a mistake, especially when the zero comes from macro
>> expansion, that users might want to know about.  Clang rejects
>> a zero with an error but I think a warning is more in line with
>> established GCC practice, so the patch also implements that.
>>
>> Besides x86_64-linux, I tested this change with cross-compilers
>> for aarch64-linux-elf, powerpc64le-linux, and sparc-solaris2.11.
>> I added tests for the changed aligned attribute for those targets
>> To make the gcc.dg/builtin-has-attribute.c test pass with
>> the cross-compilers I changed from a runtime test into a compile
>> only one.
>>
>> Martin
>>
>> PS I'm not happy about duplicating the same test across all those
>> targets.  It would be much nicer to have a single test somewhere
>> in dg.exp #include a target-specific header with macros describing
>> the target-specific parameters.
> 
> why so complicated?  Just have a single attr-aligned.c test, restricted
> to the target cpus it supports via dg directives and with
> MINALIGN/MAXALIGN definitions controlled by appropriate target macros?

I have done that in the past(*) but hardcoding target-specific
assumptions into a general test didn't feel right either given
the design of the test suite (separate target tests).

[*] see the tangle of #ifdefs in gcc/testsuite/gcc.dg/attr-aligned.c

> 
> Besides, the new gcc.target/sparc/attr-aligned.c test currently FAILs on
> 64-bit sparc:
> 
> FAIL: gcc.target/sparc/attr-aligned.c (test for excess errors)
> 
> Excess errors:
> /vol/gcc/src/hg/trunk/local/gcc/testsuite/gcc.target/sparc/attr-aligned.c:29:1: error: static assertion failed: "alignof (f_) == MAXALIGN"
> 
> alignof (f_) is 16 for sparcv9.  The following patch fixes this, tested
> on sparc-sun-solaris2.11 with -m32 and -m64.
> 
> Ok for mainline?

Thanks!
Martin
Rainer Orth Dec. 5, 2018, 4:12 p.m. UTC | #5
Hi Martin,

>>> PS I'm not happy about duplicating the same test across all those
>>> targets.  It would be much nicer to have a single test somewhere
>>> in dg.exp #include a target-specific header with macros describing
>>> the target-specific parameters.
>>
>> why so complicated?  Just have a single attr-aligned.c test, restricted
>> to the target cpus it supports via dg directives and with
>> MINALIGN/MAXALIGN definitions controlled by appropriate target macros?
>
> I have done that in the past(*) but hardcoding target-specific
> assumptions into a general test didn't feel right either given
> the design of the test suite (separate target tests).
>
> [*] see the tangle of #ifdefs in gcc/testsuite/gcc.dg/attr-aligned.c

however, gcc.target, g++.target are only meant for tests that only make
sense on a particular target and cannot work elsewhere.  The current
amount of duplication between the various gcc.target/*/attr-aligned.c
tests (where the only variation I could see are the MINALIGN/MAXALIGN
definitions) seems way worse.  For someone adapting the test to his
target, it's way easier to skim through the variations (hopefully with
appropriate comments where non-obvious) in a single file rather than
looking at many almost identical files in gcc.target.

	Rainer
diff mbox series

Patch

PR testsuite/88208 - new test case c-c++-common/builtin-has-attribute-3.c in r266335 has multiple excess errors

gcc/ChangeLog:
	PR testsuite/88208
	* doc/extend.texi (attribute constructor): Clarify.

gcc/c/ChangeLog:

	PR testsuite/88208
	* c-decl.c (declspec_add_alignas): Adjust call to check_user_alignment.

gcc/c-family/ChangeLog:

	PR testsuite/88208
	* c-attribs.c (common_handle_aligned_attribute): Silently avoid setting
	alignments to values less than the target requires.
	(has_attribute): For attribute aligned consider both the attribute
	and the alignment bits.
	* c-common.c (c_init_attributes): Optionally issue a warning for
	zero alignment.

gcc/testsuite/ChangeLog:

	PR testsuite/88208
	* gcc.dg/attr-aligned-2.c: New test.
	* gcc.dg/builtin-has-attribute.c: Adjust.
	* c-c++-common/builtin-has-attribute-2.c: Same.
	* c-c++-common/builtin-has-attribute-3.c: Same.
	* c-c++-common/builtin-has-attribute-4.c: Same.
	* c-c++-common/builtin-has-attribute-5.c: New test.
	* gcc.target/aarch64/attr-aligned.c: Same.
	* gcc.target/i386/attr-aligned.c: Same.
	* gcc.target/powerpc/attr-aligned.c: Same.
	* gcc.target/sparc/attr-aligned.c: Same.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 266521)
+++ gcc/doc/extend.texi	(working copy)
@@ -2552,8 +2552,9 @@  called.  Functions with these attributes are usefu
 initializing data that is used implicitly during the execution of
 the program.
 
-You may provide an optional integer priority to control the order in
-which constructor and destructor functions are run.  A constructor
+On some targets the attributes also accept an integer argument to
+specify a priority to control the order in which constructor and
+destructor functions are run.  A constructor
 with a smaller priority number runs before a constructor with a larger
 priority number; the opposite relationship holds for destructors.  So,
 if you have a constructor that allocates a resource and a destructor
@@ -2566,6 +2567,10 @@  decorated with attribute @code{constructor} are in
 In mixed declarations, attribute @code{init_priority} can be used to
 impose a specific ordering.
 
+Using the argument forms of the @code{constructor} and @code{destructor}
+attributes on targets where the feature is not supported is rejected with
+an error.
+
 @item copy
 @itemx copy (@var{function})
 @cindex @code{copy} function attribute
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 266521)
+++ gcc/c/c-decl.c	(working copy)
@@ -11061,12 +11061,15 @@  struct c_declspecs *
 declspecs_add_alignas (location_t loc,
 		       struct c_declspecs *specs, tree align)
 {
-  int align_log;
   specs->alignas_p = true;
   specs->locations[cdw_alignas] = loc;
   if (align == error_mark_node)
     return specs;
-  align_log = check_user_alignment (align, false, true);
+
+  /* Only accept the alignment if it's valid and greater than
+     the current one.  Zere is invalid but by C11 required to be
+     silently ignored.  */
+  int align_log = check_user_alignment (align, false, /* warn_zero = */false);
   if (align_log > specs->align_log)
     specs->align_log = align_log;
   return specs;
Index: gcc/c-family/c-attribs.c
===================================================================
--- gcc/c-family/c-attribs.c	(revision 266521)
+++ gcc/c-family/c-attribs.c	(working copy)
@@ -2003,7 +2003,8 @@  common_handle_aligned_attribute (tree *node, tree
   bool objfile = (TREE_CODE (*node) == FUNCTION_DECL
 		  || (VAR_P (*node) && TREE_STATIC (*node)));
   /* Log2 of specified alignment.  */
-  int pow2align = check_user_alignment (align_expr, objfile, true);
+  int pow2align = check_user_alignment (align_expr, objfile,
+					/* warn_zero = */ true);
   if (pow2align == -1
       || !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags))
     {
@@ -2019,6 +2020,9 @@  common_handle_aligned_attribute (tree *node, tree
   unsigned curalign = 0;
   unsigned lastalign = 0;
 
+  /* True when SET_DECL_ALIGN() should be called for the decl when
+     *NO_ADD_ATTRS is false.  */
+  bool set_align = true;
   if (is_type)
     {
       if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
@@ -2067,23 +2071,35 @@  common_handle_aligned_attribute (tree *node, tree
 	curalign = lastalign;
 
       curalign /= BITS_PER_UNIT;
-      bitalign /= BITS_PER_UNIT;
+      unsigned newalign = bitalign / BITS_PER_UNIT;
 
-      bool diagd = true;
       auto_diagnostic_group d;
-      if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl))
-	diagd = warning (OPT_Wattributes,
-			  "ignoring attribute %<%E (%u)%> because it conflicts "
-			  "with attribute %<%E (%u)%>",
-			  name, bitalign, name, curalign);
+      if ((DECL_USER_ALIGN (decl)
+	   || DECL_USER_ALIGN (last_decl)))
+	{
+	  if (warning (OPT_Wattributes,
+		       "ignoring attribute %<%E (%u)%> because it conflicts "
+		       "with attribute %<%E (%u)%>",
+		       name, newalign, name, curalign)
+	      && note)
+	    inform (DECL_SOURCE_LOCATION (last_decl),
+		    "previous declaration here");
+	  /* Only reject attempts to relax/override an alignment
+	     explicitly specified previously and accept declarations
+	     that appear to relax the implicit function alignment for
+	     the target.  Both increasing and increasing the alignment
+	     set by -falign-functions setting is permitted.  */
+	  *no_add_attrs = true;
+	}
       else if (!warn_if_not_aligned_p)
-	/* Do not error out for attribute warn_if_not_aligned.  */
-	error ("alignment for %q+D must be at least %d", decl, curalign);
-
-      if (diagd && note)
-	inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here");
-
-      *no_add_attrs = true;
+	{
+	  /* Do not fail for attribute warn_if_not_aligned.  Otherwise,
+	     silently avoid applying the alignment to the declaration
+	     because it's implicitly satisfied by the target.  Apply
+	     the attribute nevertheless so it can be retrieved by
+	     __builtin_has_attribute.  */
+	  set_align = false;
+	}
     }
   else if (DECL_USER_ALIGN (decl)
 	   && DECL_ALIGN (decl) > bitalign)
@@ -2100,33 +2116,29 @@  common_handle_aligned_attribute (tree *node, tree
 	   && TREE_CODE (decl) == FUNCTION_DECL
 	   && DECL_ALIGN (decl) > bitalign)
     {
-      /* Don't warn function alignment here if warn_if_not_aligned_p is
-	 true.  It will be warned later.  */
+      /* Don't warn for function alignment here if warn_if_not_aligned_p
+	 is true.  It will be warned about later.  */
       if (DECL_USER_ALIGN (decl))
-	error ("alignment for %q+D was previously specified as %d "
-	       "and may not be decreased", decl,
-	       DECL_ALIGN (decl) / BITS_PER_UNIT);
-      else
-	error ("alignment for %q+D must be at least %d", decl,
-	       DECL_ALIGN (decl) / BITS_PER_UNIT);
-      *no_add_attrs = true;
-    }
-  else
-    {
-      if (warn_if_not_aligned_p)
 	{
-	  if (TREE_CODE (decl) == FIELD_DECL && !DECL_C_BIT_FIELD (decl))
-	    {
-	      SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign);
-	      warn_if_not_aligned_p = false;
-	    }
+	  /* Only reject attempts to relax/override an alignment
+	     explicitly specified previously and accept declarations
+	     that appear to relax the implicit function alignment for
+	     the target.  Both increasing and increasing the alignment
+	     set by -falign-functions setting is permitted.  */
+	  error ("alignment for %q+D was previously specified as %d "
+		 "and may not be decreased", decl,
+		 DECL_ALIGN (decl) / BITS_PER_UNIT);
+	  *no_add_attrs = true;
 	}
-      else
-	{
-	  SET_DECL_ALIGN (decl, bitalign);
-	  DECL_USER_ALIGN (decl) = 1;
-	}
     }
+  else if (warn_if_not_aligned_p
+	   && TREE_CODE (decl) == FIELD_DECL
+	   && !DECL_C_BIT_FIELD (decl))
+    {
+      SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign);
+      warn_if_not_aligned_p = false;
+      set_align = false;
+    }
 
   if (warn_if_not_aligned_p)
     {
@@ -2134,6 +2146,11 @@  common_handle_aligned_attribute (tree *node, tree
 	     decl);
       *no_add_attrs = true;
     }
+  else if (!is_type && !*no_add_attrs && set_align)
+    {
+      SET_DECL_ALIGN (decl, bitalign);
+      DECL_USER_ALIGN (decl) = 1;
+    }
 
   return NULL_TREE;
 }
@@ -4086,11 +4103,6 @@  has_attribute (location_t atloc, tree t, tree attr
 	 with the sought attributes) has been found on the attribute chain.  */
       bool found_attr = false;
 
-      /* For attribute aligned ignore the attribute list and consider
-	 the tree node itself instead.  */
-      if (type && !strcmp ("aligned", namestr))
-	atlist = NULL_TREE;
-
       /* When clear, the first mismatched attribute argument results
 	 in failure.  Otherwise, the first matched attribute argument
 	 results in success.  */
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 266521)
+++ gcc/c-family/c-common.c	(working copy)
@@ -5143,11 +5143,11 @@  c_init_attributes (void)
    then reject alignments greater than MAX_OFILE_ALIGNMENT when
    converted to bits.  Otherwise, consider valid only alignments
    that are less than HOST_BITS_PER_INT - LOG2_BITS_PER_UNIT.
-   If ALLOW_ZERO then 0 is valid and should result in
-   a return of -1 with no error.  */
+   Zero is not considered a valid argument (and results in -1 on
+   return) but it only triggers a warning when WARN_ZERO is set.  */
 
 int
-check_user_alignment (const_tree align, bool objfile, bool allow_zero)
+check_user_alignment (const_tree align, bool objfile, bool warn_zero)
 {
   if (error_operand_p (align))
     return -1;
@@ -5159,8 +5159,14 @@  int
       return -1;
     }
 
-  if (allow_zero && integer_zerop (align))
-    return -1;
+  if (integer_zerop (align))
+    {
+      if (warn_zero)
+	warning (OPT_Wattributes,
+		 "requested alignment %qE is not a positive power of 2",
+		 align);
+      return -1;
+    }
 
   int log2bitalign;
   if (tree_int_cst_sgn (align) == -1
Index: gcc/testsuite/gcc.dg/attr-aligned-2.c
===================================================================
--- gcc/testsuite/gcc.dg/attr-aligned-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/attr-aligned-2.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Verify that valid alignment on functions is accepted for all targets
+   and that alignment of zero is ignored with a warning.
+   { dg-do compile }
+   { dg-options "-Wno-pedantic" }  */
+
+#define ASSERT(expr)   _Static_assert (expr, #expr)
+#define ALIGN(n)       __attribute__ ((aligned (n)))
+#define alignof(expr)  __alignof__ (expr)
+
+ALIGN (0) void f0 (void) { }    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
+ALIGN (1) void f1 (void) { }
+ALIGN (2) void f2 (void) { }
+ALIGN (3) void f3 (void) { }    /* { dg-error "requested alignment '3' is not a positive power of 2" } */
+ALIGN (4) void f4 (void) { }
+
+ASSERT (alignof (f0) > 0);
+ASSERT (alignof (f1) >= 1);
+ASSERT (alignof (f2) >= 2);
+ASSERT (alignof (f3) >= 1);
+ASSERT (alignof (f4) >= 4);
Index: gcc/testsuite/c-c++-common/builtin-has-attribute-2.c
===================================================================
--- gcc/testsuite/c-c++-common/builtin-has-attribute-2.c	(revision 266521)
+++ gcc/testsuite/c-c++-common/builtin-has-attribute-2.c	(working copy)
@@ -42,8 +42,8 @@  void test_type (int n)
 
   A (0, int ATTR (aligned (4)), aligned (2));
   A (0, int ATTR (aligned (2)), aligned (4));
-  /* GCC retains both attributes in the */
-  A (0, int ATTR (aligned (2), aligned (4)), aligned (2));
+  /* GCC retains both attributes when the type is defined in the builtin.  */
+  A (1, int ATTR (aligned (2), aligned (4)), aligned (2));
   A (1, int ATTR (aligned (2), aligned (4)), aligned (4));
   /* The following fails due to bug 87524.
      A (1, int ATTR (aligned (4), aligned (2))), aligned (4)); */
@@ -132,7 +132,7 @@  void test_typedef (int n)
   A (1, MAI, may_alias);
 
   typedef ATTR (aligned (4), may_alias) char A4MAC;
-  A (0, A4MAC, aligned (0));
+  A (0, A4MAC, aligned (0));    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, A4MAC, aligned (1));
   A (0, A4MAC, aligned (2));
   A (1, A4MAC, aligned (4));
@@ -141,7 +141,7 @@  void test_typedef (int n)
 
   typedef ATTR (may_alias, aligned (8)) char A8MAC;
   A (1, A8MAC, aligned);
-  A (0, A8MAC, aligned (0));
+  A (0, A8MAC, aligned (0));    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, A8MAC, aligned (1));
   A (0, A8MAC, aligned (2));
   A (0, A8MAC, aligned (4));
Index: gcc/testsuite/c-c++-common/builtin-has-attribute-3.c
===================================================================
--- gcc/testsuite/c-c++-common/builtin-has-attribute-3.c	(revision 266521)
+++ gcc/testsuite/c-c++-common/builtin-has-attribute-3.c	(working copy)
@@ -35,7 +35,7 @@  ATTR (alias ("fnoreturn")) void falias (void);
 void test_aligned (void)
 {
   A (0, fnone, aligned);
-  A (0, fnone, aligned (0));
+  A (0, fnone, aligned (0));            /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, fnone, aligned (1));
   A (0, fnone, aligned (2));
   A (0, fnone, aligned (4));
@@ -43,18 +43,18 @@  void test_aligned (void)
   A (0, fnone, aligned (16));
 
   A (1, faligned, aligned);
-  A (0, faligned, aligned (0));
+  A (0, faligned, aligned (0));         /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, faligned, aligned (1));
   A (0, faligned, aligned (2));
 
   A (1, faligned_1, aligned);
-  A (0, faligned_1, aligned (0));
+  A (0, faligned_1, aligned (0));       /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (1, faligned_1, aligned (1));
   A (0, faligned_1, aligned (2));
   A (0, faligned_1, aligned (4));
 
   A (1, faligned_2, aligned);
-  A (0, faligned_2, aligned (0));
+  A (0, faligned_2, aligned (0));       /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, faligned_2, aligned (1));
   A (1, faligned_2, aligned (2));
   A (0, faligned_2, aligned (4));
@@ -193,18 +193,6 @@  void test_ctor_dtor (void)
 
   A (1, fctor_dtor, constructor);
   A (1, fctor_dtor, destructor);
-
-  extern ATTR (constructor (123)) void fctor_123 (void);
-  A (1, fctor_123, constructor);
-  A (0, fctor_123, destructor);
-  A (1, fctor_123, constructor (123));
-  A (0, fctor_123, constructor (124));
-
-  extern ATTR (destructor (234)) void fctor_123 (void);
-  A (1, fctor_123, constructor (123));
-  A (1, fctor_123, destructor);
-  A (1, fctor_123, destructor (234));
-  A (0, fctor_123, destructor (235));
 }
 
 
Index: gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
===================================================================
--- gcc/testsuite/c-c++-common/builtin-has-attribute-4.c	(revision 266521)
+++ gcc/testsuite/c-c++-common/builtin-has-attribute-4.c	(working copy)
@@ -19,7 +19,7 @@  ATTR (aligned (8)) char valigned_8;
 void test_aligned (void)
 {
   A (0, vnone, aligned);
-  A (0, vnone, aligned (0));
+  A (0, vnone, aligned (0));      /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, vnone, aligned (1));
   A (0, vnone, aligned (2));
   A (0, vnone, aligned (4));
@@ -27,18 +27,18 @@  void test_aligned (void)
   A (0, vnone, aligned (16));
 
   A (1, valigned, aligned);
-  A (0, valigned, aligned (0));
+  A (0, valigned, aligned (0));   /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, valigned, aligned (1));
   A (0, valigned, aligned (2));
 
   A (1, valigned_1, aligned);
-  A (0, valigned_1, aligned (0));
+  A (0, valigned_1, aligned (0)); /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (1, valigned_1, aligned (1));
   A (0, valigned_1, aligned (2));
   A (0, valigned_1, aligned (4));
 
   A (1, valigned_2, aligned);
-  A (0, valigned_2, aligned (0));
+  A (0, valigned_2, aligned (0)); /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
   A (0, valigned_2, aligned (1));
   A (1, valigned_2, aligned (2));
   A (0, valigned_2, aligned (4));
Index: gcc/testsuite/c-c++-common/builtin-has-attribute-5.c
===================================================================
--- gcc/testsuite/c-c++-common/builtin-has-attribute-5.c	(nonexistent)
+++ gcc/testsuite/c-c++-common/builtin-has-attribute-5.c	(working copy)
@@ -0,0 +1,48 @@ 
+/* Verify __builtin_has_attribute return value for attributes constructor
+   and destructor with explicit priorities.
+   { dg-do compile { target init_priority } }
+   { dg-options "-Wall -ftrack-macro-expansion=0" }
+   { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } }  */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+#define A(expect, sym, attr)						\
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+void fnone (void);
+
+void test_ctor_dtor_prio (void)
+{
+  extern ATTR (constructor) void fctor (void);
+  extern ATTR (destructor) void fdtor (void);
+  extern ATTR (constructor, destructor) void fctor_dtor (void);
+
+  A (0, fnone, constructor);
+  A (0, fnone, constructor (123));
+  A (0, fnone, destructor);
+  A (0, fnone, constructor (234));
+
+  A (1, fctor, constructor);
+  A (0, fctor, constructor (123));
+  A (1, fdtor, destructor);
+  A (0, fdtor, destructor (234));
+
+  extern ATTR (constructor) void fctor_dtor (void);
+  extern ATTR (destructor) void fctor_dtor (void);
+  extern ATTR (constructor, destructor) void fctor_dtor (void);
+
+  A (1, fctor_dtor, constructor);
+  A (1, fctor_dtor, destructor);
+
+  extern ATTR (constructor (123)) void fctor_123 (void);
+  A (1, fctor_123, constructor);
+  A (0, fctor_123, destructor);
+  A (1, fctor_123, constructor (123));
+  A (0, fctor_123, constructor (124));
+
+  extern ATTR (destructor (234)) void fctor_123 (void);
+  A (1, fctor_123, constructor (123));
+  A (1, fctor_123, destructor);
+  A (1, fctor_123, destructor (234));
+  A (0, fctor_123, destructor (235));
+}
Index: gcc/testsuite/gcc.dg/builtin-has-attribute.c
===================================================================
--- gcc/testsuite/gcc.dg/builtin-has-attribute.c	(revision 266521)
+++ gcc/testsuite/gcc.dg/builtin-has-attribute.c	(working copy)
@@ -3,8 +3,8 @@ 
    Also verify that the expression in __builtin_has_attribute is
    not evaluated.
 
-  { dg-do run }
-  { dg-options "-O2 -Wall -Wc++-compat" }  */
+  { dg-do compile }
+  { dg-options "-O2 -Wall -Wc++-compat -fdump-tree-optimized -ftrack-macro-expansion=0" }  */
 
 #define ATTR(list) __attribute__ (list)
 
@@ -11,8 +11,6 @@ 
 #define A(expect, sym, attr)						\
   typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
 
-int nfails;
-
 #define assert(expr)						\
   ((expr)							\
    ? (void)0							\
@@ -24,22 +22,27 @@  A (0, struct A { int i; }, aligned);   /* { dg-war
 A (1, struct ATTR ((aligned)) B { int i; }, aligned);   /* { dg-warning "expression is invalid in C\\\+\\\+" } */
 
 
-int f (void)
+static int f (void)
 {
   __builtin_abort ();
 }
 
-int n = 1;
-
 int main (void)
 {
+  int n = 0, nfails = 0;
+
   assert (0 == __builtin_has_attribute (int[n++], aligned));
   assert (1 == __builtin_has_attribute (ATTR ((aligned)) int[n++], aligned));
   assert (1 == __builtin_has_attribute (ATTR ((aligned)) int[f ()], aligned));
   assert (1 == 1);
 
+  if (n)
+    __builtin_abort ();
+
   if (nfails)
     __builtin_abort ();
 
   return 0;
 }
+
+/* { dg-final { scan-tree-dump-times "abort" 0 "optimized" } } */
Index: gcc/testsuite/gcc.target/aarch64/attr-aligned.c
===================================================================
--- gcc/testsuite/gcc.target/aarch64/attr-aligned.c	(nonexistent)
+++ gcc/testsuite/gcc.target/aarch64/attr-aligned.c	(working copy)
@@ -0,0 +1,65 @@ 
+/* Verify that valid alignment on functions is accepted and results
+   in the alignment expected for the target and that alignment of
+   zero is ignored with a warning.
+   { dg-do compile }
+   { dg-options "-Wno-pedantic -ftrack-macro-expansion=0" }  */
+
+#define ASSERT(expr)     _Static_assert (expr, #expr)
+#define ALIGN(n)         __attribute__ ((aligned (n)))
+#define alignof(expr)    __alignof__ (expr)
+#define HAS_ALIGN(f, n)  __builtin_has_attribute (f, __aligned__ (n))
+
+#define MINALIGN(N)   ((N) < 4 ? 4 : (N))
+#define MAXALIGN      16
+
+/* No alignment specified.  */
+void f (void) { }
+
+/* Empty alignment means maximum.  */
+ALIGN () void f_ (void) { }
+
+ALIGN (0) void f0 (void) { }    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
+ALIGN (1) void f1 (void) { }
+ALIGN (2) void f2 (void) { }
+ALIGN (4) void f4 (void) { }
+ALIGN (8) void f8 (void) { }
+ALIGN (16) void f16 (void) { }
+ALIGN (32) void f32 (void) { }
+
+ASSERT (alignof (f_) == MAXALIGN);
+ASSERT (alignof (f0) == alignof (f));
+ASSERT (alignof (f1) == MINALIGN (1));
+ASSERT (alignof (f2) == MINALIGN (2));
+ASSERT (alignof (f4) == MINALIGN (4));
+ASSERT (alignof (f8) == MINALIGN (8));
+ASSERT (alignof (f16) == MINALIGN (16));
+ASSERT (alignof (f32) == MINALIGN (32));
+
+ASSERT (!__builtin_has_attribute (f, aligned));
+ASSERT (__builtin_has_attribute (f_, aligned));
+ASSERT (!__builtin_has_attribute (f0, aligned));
+
+ASSERT (!HAS_ALIGN (f_, MAXALIGN));
+
+ASSERT (HAS_ALIGN (f1, 1));
+ASSERT (!HAS_ALIGN (f1, 2));
+
+ASSERT (!HAS_ALIGN (f2, 1));
+ASSERT (HAS_ALIGN (f2, 2));
+ASSERT (!HAS_ALIGN (f2, 4));
+
+ASSERT (!HAS_ALIGN (f4, 2));
+ASSERT (HAS_ALIGN (f4, 4));
+ASSERT (!HAS_ALIGN (f4, 8));
+
+ASSERT (!HAS_ALIGN (f8, 4));
+ASSERT (HAS_ALIGN (f8, 8));
+ASSERT (!HAS_ALIGN (f8, 16));
+
+ASSERT (!HAS_ALIGN (f16, 8));
+ASSERT (HAS_ALIGN (f16, 16));
+ASSERT (!HAS_ALIGN (f16, 32));
+
+ASSERT (!HAS_ALIGN (f32, 16));
+ASSERT (HAS_ALIGN (f32, 32));
+ASSERT (!HAS_ALIGN (f32, 64));
Index: gcc/testsuite/gcc.target/i386/attr-aligned.c
===================================================================
--- gcc/testsuite/gcc.target/i386/attr-aligned.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/attr-aligned.c	(working copy)
@@ -0,0 +1,65 @@ 
+/* Verify that valid alignment on functions is accepted and results
+   in the alignment expected for the target and that alignment of
+   zero is ignored with a warning.
+   { dg-do compile }
+   { dg-options "-Wno-pedantic -ftrack-macro-expansion=0" }  */
+
+#define ASSERT(expr)     _Static_assert (expr, #expr)
+#define ALIGN(n)         __attribute__ ((aligned (n)))
+#define alignof(expr)    __alignof__ (expr)
+#define HAS_ALIGN(f, n)  __builtin_has_attribute (f, __aligned__ (n))
+
+#define MINALIGN(N)   N
+#define MAXALIGN      16
+
+/* No alignment specified.  */
+void f (void) { }
+
+/* Empty alignment means maximum.  */
+ALIGN () void f_ (void) { }
+
+ALIGN (0) void f0 (void) { }    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
+ALIGN (1) void f1 (void) { }
+ALIGN (2) void f2 (void) { }
+ALIGN (4) void f4 (void) { }
+ALIGN (8) void f8 (void) { }
+ALIGN (16) void f16 (void) { }
+ALIGN (32) void f32 (void) { }
+
+ASSERT (alignof (f_) == MAXALIGN);
+ASSERT (alignof (f0) == alignof (f));
+ASSERT (alignof (f1) == MINALIGN (1));
+ASSERT (alignof (f2) == MINALIGN (2));
+ASSERT (alignof (f4) == MINALIGN (4));
+ASSERT (alignof (f8) == MINALIGN (8));
+ASSERT (alignof (f16) == MINALIGN (16));
+ASSERT (alignof (f32) == MINALIGN (32));
+
+ASSERT (!__builtin_has_attribute (f, aligned));
+ASSERT (__builtin_has_attribute (f_, aligned));
+ASSERT (!__builtin_has_attribute (f0, aligned));
+
+ASSERT (!HAS_ALIGN (f_, MAXALIGN));
+
+ASSERT (HAS_ALIGN (f1, 1));
+ASSERT (!HAS_ALIGN (f1, 2));
+
+ASSERT (!HAS_ALIGN (f2, 1));
+ASSERT (HAS_ALIGN (f2, 2));
+ASSERT (!HAS_ALIGN (f2, 4));
+
+ASSERT (!HAS_ALIGN (f4, 2));
+ASSERT (HAS_ALIGN (f4, 4));
+ASSERT (!HAS_ALIGN (f4, 8));
+
+ASSERT (!HAS_ALIGN (f8, 4));
+ASSERT (HAS_ALIGN (f8, 8));
+ASSERT (!HAS_ALIGN (f8, 16));
+
+ASSERT (!HAS_ALIGN (f16, 8));
+ASSERT (HAS_ALIGN (f16, 16));
+ASSERT (!HAS_ALIGN (f16, 32));
+
+ASSERT (!HAS_ALIGN (f32, 16));
+ASSERT (HAS_ALIGN (f32, 32));
+ASSERT (!HAS_ALIGN (f32, 64));
Index: gcc/testsuite/gcc.target/powerpc/attr-aligned.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/attr-aligned.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/attr-aligned.c	(working copy)
@@ -0,0 +1,65 @@ 
+/* Verify that valid alignment on functions is accepted and results
+   in the alignment expected for the target and that alignment of
+   zero is ignored with a warning.
+   { dg-do compile }
+   { dg-options "-Wno-pedantic -ftrack-macro-expansion=0" }  */
+
+#define ASSERT(expr)     _Static_assert (expr, #expr)
+#define ALIGN(n)         __attribute__ ((aligned (n)))
+#define alignof(expr)    __alignof__ (expr)
+#define HAS_ALIGN(f, n)  __builtin_has_attribute (f, __aligned__ (n))
+
+#define MINALIGN(N)   (N < 4 ? 4 : N)
+#define MAXALIGN      16
+
+/* No alignment specified.  */
+void f (void) { }
+
+/* Empty alignment means maximum.  */
+ALIGN () void f_ (void) { }
+
+ALIGN (0) void f0 (void) { }    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
+ALIGN (1) void f1 (void) { }
+ALIGN (2) void f2 (void) { }
+ALIGN (4) void f4 (void) { }
+ALIGN (8) void f8 (void) { }
+ALIGN (16) void f16 (void) { }
+ALIGN (32) void f32 (void) { }
+
+ASSERT (alignof (f_) == MAXALIGN);
+ASSERT (alignof (f0) == alignof (f));
+ASSERT (alignof (f1) == MINALIGN (1));
+ASSERT (alignof (f2) == MINALIGN (2));
+ASSERT (alignof (f4) == MINALIGN (4));
+ASSERT (alignof (f8) == MINALIGN (8));
+ASSERT (alignof (f16) == MINALIGN (16));
+ASSERT (alignof (f32) == MINALIGN (32));
+
+ASSERT (!__builtin_has_attribute (f, aligned));
+ASSERT (__builtin_has_attribute (f_, aligned));
+ASSERT (!__builtin_has_attribute (f0, aligned));
+
+ASSERT (!HAS_ALIGN (f_, MAXALIGN));
+
+ASSERT (HAS_ALIGN (f1, 1));
+ASSERT (!HAS_ALIGN (f1, 2));
+
+ASSERT (!HAS_ALIGN (f2, 1));
+ASSERT (HAS_ALIGN (f2, 2));
+ASSERT (!HAS_ALIGN (f2, 4));
+
+ASSERT (!HAS_ALIGN (f4, 2));
+ASSERT (HAS_ALIGN (f4, 4));
+ASSERT (!HAS_ALIGN (f4, 8));
+
+ASSERT (!HAS_ALIGN (f8, 4));
+ASSERT (HAS_ALIGN (f8, 8));
+ASSERT (!HAS_ALIGN (f8, 16));
+
+ASSERT (!HAS_ALIGN (f16, 8));
+ASSERT (HAS_ALIGN (f16, 16));
+ASSERT (!HAS_ALIGN (f16, 32));
+
+ASSERT (!HAS_ALIGN (f32, 16));
+ASSERT (HAS_ALIGN (f32, 32));
+ASSERT (!HAS_ALIGN (f32, 64));
Index: gcc/testsuite/gcc.target/sparc/attr-aligned.c
===================================================================
--- gcc/testsuite/gcc.target/sparc/attr-aligned.c	(nonexistent)
+++ gcc/testsuite/gcc.target/sparc/attr-aligned.c	(working copy)
@@ -0,0 +1,65 @@ 
+/* Verify that valid alignment on functions is accepted and results
+   in the alignment expected for the target and that alignment of
+   zero is ignored with a warning.
+   { dg-do compile }
+   { dg-options "-Wno-pedantic -ftrack-macro-expansion=0" }  */
+
+#define ASSERT(expr)     _Static_assert (expr, #expr)
+#define ALIGN(n)         __attribute__ ((aligned (n)))
+#define alignof(expr)    __alignof__ (expr)
+#define HAS_ALIGN(f, n)  __builtin_has_attribute (f, __aligned__ (n))
+
+#define MINALIGN(N)   ((N) < 4 ? 4 : (N))
+#define MAXALIGN      8
+
+/* No alignment specified.  */
+void f (void) { }
+
+/* Empty alignment means maximum.  */
+ALIGN () void f_ (void) { }
+
+ALIGN (0) void f0 (void) { }    /* { dg-warning "requested alignment .0. is not a positive power of 2" } */
+ALIGN (1) void f1 (void) { }
+ALIGN (2) void f2 (void) { }
+ALIGN (4) void f4 (void) { }
+ALIGN (8) void f8 (void) { }
+ALIGN (16) void f16 (void) { }
+ALIGN (32) void f32 (void) { }
+
+ASSERT (alignof (f_) == MAXALIGN);
+ASSERT (alignof (f0) == alignof (f));
+ASSERT (alignof (f1) == MINALIGN (1));
+ASSERT (alignof (f2) == MINALIGN (2));
+ASSERT (alignof (f4) == MINALIGN (4));
+ASSERT (alignof (f8) == MINALIGN (8));
+ASSERT (alignof (f16) == MINALIGN (16));
+ASSERT (alignof (f32) == MINALIGN (32));
+
+ASSERT (!__builtin_has_attribute (f, aligned));
+ASSERT (__builtin_has_attribute (f_, aligned));
+ASSERT (!__builtin_has_attribute (f0, aligned));
+
+ASSERT (!HAS_ALIGN (f_, MAXALIGN));
+
+ASSERT (HAS_ALIGN (f1, 1));
+ASSERT (!HAS_ALIGN (f1, 2));
+
+ASSERT (!HAS_ALIGN (f2, 1));
+ASSERT (HAS_ALIGN (f2, 2));
+ASSERT (!HAS_ALIGN (f2, 4));
+
+ASSERT (!HAS_ALIGN (f4, 2));
+ASSERT (HAS_ALIGN (f4, 4));
+ASSERT (!HAS_ALIGN (f4, 8));
+
+ASSERT (!HAS_ALIGN (f8, 4));
+ASSERT (HAS_ALIGN (f8, 8));
+ASSERT (!HAS_ALIGN (f8, 16));
+
+ASSERT (!HAS_ALIGN (f16, 8));
+ASSERT (HAS_ALIGN (f16, 16));
+ASSERT (!HAS_ALIGN (f16, 32));
+
+ASSERT (!HAS_ALIGN (f32, 16));
+ASSERT (HAS_ALIGN (f32, 32));
+ASSERT (!HAS_ALIGN (f32, 64));