diff mbox

69780 - [4.9/5/6 Regression] ICE on __builtin_alloca_with_align, with small alignment

Message ID 56C4DC9A.5070900@gmail.com
State New
Headers show

Commit Message

Martin Sebor Feb. 17, 2016, 8:48 p.m. UTC
On 02/17/2016 12:39 AM, Jakub Jelinek wrote:
> On Tue, Feb 16, 2016 at 06:04:48PM -0700, Martin Sebor wrote:
>>> Formatting.  = needs to be on the next line.
>>
>> There are literally dozens of examples of this style in this file
>> alone.  In one of the two instances of this style in this patch,
>> moving the equals sign to the next line would force me to split
>> the initializer expression over the next two lines to avoid
>> exceeding the 80 character per line limit and make the code
>> harder to read.  I also don't see the style you suggest mentioned
>> in the GNU coding standard or in the GCC coding conventions.
>> I would prefer to leave this detail to the discretion of the
>> author.
>
> Please change this, consistency is very much desirable.  Yes, there are
> various formatting inconsistencies (which some people fix them up as they touch
> the code), but that doesn't mean new inconsistencies should be introduced.

Please see my note in the PS.

>> +#undef MAX_STACK_ALIGNMENT
>> +#define MAX_STACK_ALIGNMENT __UINT32_MAX__
>> +
>
> This is wrong for 2 reasons:

Doh! Sorry about that! This was leftover from an experiment I did
at one point and forgot to take out. (You do not need to explain
why it would be wrong to commit, it's obvious.)

>>     switch (DECL_FUNCTION_CODE (fndecl))
>>       {
>> +    case BUILT_IN_ALLOCA_WITH_ALIGN:
>> +      {
>> +	/* Get the requested alignment (in bits) if it's a constant
>> +	   integer expression.  */
>> +	unsigned HOST_WIDE_INT align =
>> +	  TREE_CODE (args[1]) == INTEGER_CST ? tree_to_uhwi (args[1]) : 0;
>
> Besides formatting, not all INTEGER_CSTs fit into uhwi.
> So, you should use instead
> 	unsigned HOST_WIDE_INT align
> 	  = tree_fits_uhwi_p (args[1]) : tree_to_uhwi (args[1]) : 0;

Thanks. I haven't been able to cause the original code to misbehave
but I vaguely recall running into a problem (ICE?) with one of my
previous changes where I didn't check tree_fits_uhwi_p() in a compiler
built for a 32-bit host.  If that's possible it would be nice if this
trap could somehow be pointed out at compile time via a warning.

>
>> +	/* Determine if the requested alignment is a power of 2 greater
>> +	   than CHAR_BIT.  */
>> +	if ((align & (align - 1)) == 0)
>> +	  align >>= LOG2_BITS_PER_UNIT;
>> +	else
>> +	  align = 0;
>
> Ugh, why the shifting?  The alignment is in bits, and the alignment in bits
> must be a power of two, and the alignment in bits must fit into host
> unsigned int.

I shifted the alignment so that it could be compared against
MAX_STACK_ALIGNMENT.  But after some searching it seems as though
MAX_STACK_ALIGNMENT is in bits, rather than bytes as I had assumed,
so I've removed the shift.

(It would be helpful if the unit of MAX_STACK_ALIGNMENT was mentioned
in a comment in defaults.h where the macro is defined.)

With that cleared up, you seem to be suggesting that the alignment
argument shouldn't be checked against the macro.  I see
MAX_STACK_ALIGNMENT being used as the upper bound on stack alignment
in check_cxx_fundamental_alignment_constraints.   I also see that both
the C and C++ front ends reject stack-based variable declarations
aligned on a stricter boundary, such as:

   void foo (void) {
     _Alignas (1 << 29) int i;    // alignas in C++
   }

(Although the check for _Alignas and C++ alignas uses
(HOST_BITS_PER_INT - BITS_PER_UNIT_LOG)).

Is there a specific reason why you're advising against using
MAX_STACK_ALIGNMENT here?

> Thus, instead of the above do just
> 	if ((align & (align - 1)) != 0)
> 	  align = 0;
>
> 	/* Reject invalid alignments.  */
> 	if (align < BITS_PER_UNIT || (unsigned int) align != align)
> or better
> 	/* Reject invalid alignments.  */
> 	if ((align & (align - 1)) != 0
> 	    || align < BITS_PER_UNIT
> 	    || (unsigned int) align != align)

It's not obvious to me that this is guaranteed to be correct.
IMO, even if it happens to be, I find it much clearer to check
against MAX_STACK_ALIGNMENT (or whatever macro describes the
limit if not this one).

> and then
> 	  {
> 	    error_at (EXPR_LOC_OR_LOC (args[1], input_location),
> 		      "second argument to function %qE must be a constant "
> 		      "integer power of 2 between %qi and %qu",
> 		      fndecl, BITS_PER_UNIT, ~0U);
> Or if you don't like ~0U, you can use INTTYPE_MAXIMUM (unsigned int),
> but for unsigned type it will do the same thing.

That would be incorrect because ~0U isn't neither a power of 2, nor
the enforced stack alignment.  Again, using the actual limit encoded
in MAX_STACK_ALIGNMENT seems correct and IMO results in much clearer
code.

>> --- gcc/doc/extend.texi	(revision 233476)
>> +++ gcc/doc/extend.texi	(working copy)
>> @@ -10144,6 +10144,8 @@ in the Cilk Plus language manual which c
>>   @node Other Builtins
>>   @section Other Built-in Functions Provided by GCC
>>   @cindex built-in functions
>> +@findex __builtin_alloca
>> +@findex __builtin_alloca_with_align
>
> I'd prefer not to mix the documentation patch with the bugfix, otherwise
> the documentation might defer review of the bugfix or vice versa.

I don't mind waiting a bit for the documentation review, but I do
feel it's important to update the documentation at the same time
as making the change to the interface of the builtin.  The GCC
Coding Conventions even requires it:

   Any change to documented behavior (for example, the behavior of
   a command-line option or a GNU language extension) must include
   the necessary changes to the manual.

Attached is an updated patch.

Martin

PS I also feel that consistency is important, and I usually find
working with a consistently formatted code base far more enjoyable
(unless of course it comes at the expense of readability).

But since people have different personal preferences, unless the
preferred style is documented in the GCC style conventions or in
the or GNU coding standard (and ideally checked by an automated
tool like the check_GNU_style.sh script), some divergence is
unavoidable.

FWIW, since I haven't noticed a clear preference for either of
these two styles in the code base I decided to count the number
of occurrences of each to see if one is prevalent.  Although
the results are mildly in favor of the style you suggest, they
clearly indicate the lack of consensus:

$ find ~/scm/fsf/gcc-git/gcc ! -path "*/testsuite/*" \( -name "*.c" -o 
-name "*.h" \) | xargs grep "^[[:space:]][[:space:]]*=[^-+/*&!=]" | wc -l
5451

$ find ~/scm/fsf/gcc-git/gcc ! -path "*/testsuite/*" \( -name "*.c" -o 
-name "*.h" \) | xargs grep "[^-+/*&!=]=[[:space:]]*$" | wc -l
2000

In light of this, I see no point in spending time on trying to
adjust my changes or debating whether the equals looks better
on one line or the other.  There are far more important problems
to solve.

If I may make a suggestion: you would like to see the style
you prefer used consistently, bring it on the list to make
sure everyone knows about and agrees with it and then add it
to the GCC coding conventions and update check_GNU_style.sh
script to help enforce it.  Otherwise, trying to enforce it
in ad hoc code reviews is obviously ineffective and a waste
of everyone's time.  Not to mention that it's frustrating
to those of us who have made an effort to comply with the
documented style conventions and who try to follow the style
already in use to have our changes seemingly arbitrarily
picked on by different reviewers with each having their own
standard for the enforcement of the ideal formatting style.

Comments

Jakub Jelinek Feb. 17, 2016, 10:50 p.m. UTC | #1
On Wed, Feb 17, 2016 at 01:48:26PM -0700, Martin Sebor wrote:
> I shifted the alignment so that it could be compared against
> MAX_STACK_ALIGNMENT.  But after some searching it seems as though
> MAX_STACK_ALIGNMENT is in bits, rather than bytes as I had assumed,
> so I've removed the shift.

The reason why MAX_STACK_ALIGNMENT is wrong is that on most targets
it is terribly small number (a couple of bytes usually), only i?86/x86_64 is
an exception, because it is the only target that supports dynamic stack
realignment.
All other targets do support more aligned variables than that, but because
they don't support dynamic stack realignment, they handle those more aligned
automatic variables by doing alloca instead.  Which is exactly why we need
__builtin_alloca_with_align to support those larger alignments.
There is no inherent reason why __builtin_alloca_with_align can't support
arbitrary (power of 2 > BITS_PER_UNITS of course) alignments, as long as
it fits into address space and the alignment doesn't run into other memory,
but that is the general problem of alloca, it is up to the user to ensure
he doesn't run out of the stack, and the alignment is no different.

> It's not obvious to me that this is guaranteed to be correct.
> IMO, even if it happens to be, I find it much clearer to check
> against MAX_STACK_ALIGNMENT (or whatever macro describes the
> limit if not this one).

See above, there is no macro describing such limit, it is solely about
doing pretty much __builtin_alloca (size + alignment - 1);
and realign the pointer.

> That would be incorrect because ~0U isn't neither a power of 2, nor
> the enforced stack alignment.  Again, using the actual limit encoded
> in MAX_STACK_ALIGNMENT seems correct and IMO results in much clearer
> code.

No, see above.  And, if you want the exact largest possible power of 2
smaller than ~0U, you can use (unsigned int) INTTYPE_MINIMUM (int).

> I don't mind waiting a bit for the documentation review, but I do
> feel it's important to update the documentation at the same time
> as making the change to the interface of the builtin.  The GCC
> Coding Conventions even requires it:
> 
>   Any change to documented behavior (for example, the behavior of
>   a command-line option or a GNU language extension) must include
>   the necessary changes to the manual.

But the builtin (which IMHO really was never meant to be user accessible,
but has been added before we had internal functions) is not documented yet.
So, the documentation can be added before or after that IMHO.

> FWIW, since I haven't noticed a clear preference for either of
> these two styles in the code base I decided to count the number
> of occurrences of each to see if one is prevalent.  Although
> the results are mildly in favor of the style you suggest, they
> clearly indicate the lack of consensus:

First of all, you are also counting the static (typically aggregate)
initializers, which are indeed often written as
static ... var =
{
....
};
But even then the greps I've done were like 2440 vs. 819, and that also
included the file scope initializers.

	Jakub
diff mbox

Patch

PR middle-end/69780 - [4.9/5/6 Regression] ICE on __builtin_alloca_with_align
	with small alignment
PR c/69759 - __builtin_alloca and __builtin_alloca_with_align undocumented

gcc/c-family/ChangeLog:
2016-02-17  Martin Sebor  <msebor@redhat.com>

	PR middle-end/69780
	* c-common.c (check_builtin_function_arguments): Validate and reject
	invalid arguments to __builtin_alloca_with_align.

gcc/ChangeLog:
2016-02-17  Martin Sebor  <msebor@redhat.com>

	PR c/69759
	* doc/extend.texi (Other Builtins): Document __builtin_alloca and
	__builtin_alloca_with_align.

gcc/testsuite/ChangeLog:
2016-02-17  Martin Sebor  <msebor@redhat.com>

	PR middle-end/69780
	* g++.dg/ext/builtin_alloca.C: New test.
	* gcc.dg/builtins-68.c: New test.

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 233476)
+++ gcc/c-family/c-common.c	(working copy)
@@ -9818,6 +9818,31 @@  check_builtin_function_arguments (tree f
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
+    case BUILT_IN_ALLOCA_WITH_ALIGN:
+      {
+	/* Get the requested alignment (in bits) if it's a constant
+	   integer expression.  */
+	unsigned HOST_WIDE_INT align = TREE_CODE (args[1]) == INTEGER_CST
+	  && tree_fits_uhwi_p (args[1]) ? tree_to_uhwi (args[1]) : 0;
+
+	/* Determine if the requested alignment is a power of 2.  */
+	if ((align & (align - 1)))
+	  align = 0;
+
+	/* Reject invalid alignments.  */
+	if (align < BITS_PER_UNIT || MAX_STACK_ALIGNMENT < align)
+	  {
+	    /* The maximum stack alignment is in bits.  */
+	    error_at (EXPR_LOC_OR_LOC (args[1], input_location),
+		      "second argument to function %qE must be a constant "
+		      "integer power of 2 between %qi and %qwu bits",
+		      fndecl, BITS_PER_UNIT,
+		      (unsigned HOST_WIDE_INT)MAX_STACK_ALIGNMENT);
+	    return false;
+	  }
+      return true;
+      }
+
     case BUILT_IN_CONSTANT_P:
       return builtin_function_validate_nargs (fndecl, nargs, 1);
 
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 233476)
+++ gcc/doc/extend.texi	(working copy)
@@ -10144,6 +10144,8 @@  in the Cilk Plus language manual which c
 @node Other Builtins
 @section Other Built-in Functions Provided by GCC
 @cindex built-in functions
+@findex __builtin_alloca
+@findex __builtin_alloca_with_align
 @findex __builtin_call_with_static_chain
 @findex __builtin_fpclassify
 @findex __builtin_isfinite
@@ -10690,6 +10692,89 @@  In the same fashion, GCC provides @code{
 @code{__builtin_} prefixed.  The @code{isinf} and @code{isnan}
 built-in functions appear both with and without the @code{__builtin_} prefix.
 
+@deftypefn {Built-in Function} void* __builtin_alloca (size_t size)
+The @code{__builtin_alloca} function must be called at block scope.
+The function allocates an object @var{size} bytes large on the stack
+of the calling function.  The object is aligned at the default stack
+alignment boundary for the target determined by the
+@code{__BIGGEST_ALIGNMENT__} macro.  @code{__builtin_alloca} returns
+a pointer to the first byte of the allocated object.  The lifetime of
+the allocated object ends just before the calling function returns to
+its caller.   This is so even when @code{__builtin_alloca_with_align}
+is called within a nested block.
+
+For example, the following function allocates eight objects of @code{n}
+bytes each on the stack, storing a pointer to each in consecutive elements
+of the array @code{a}.  It then passes the array to function @code{g()}
+which can safely use the storage pointed to by each of the array elements.
+
+@smallexample
+void f (unsigned n)
+@{
+  void *a [8];
+  for (int i = 0; i != 8; ++i)
+    a [i] = __builtin_alloca (n);
+
+  g (a, n);   // safe
+@}
+@end smallexample
+
+Since the @code{__builtin_alloca} function doesn't validate its arguments
+it is the responsibility of its caller to make sure the argument doesn't
+cause it doesn't exceed the stack size limit.
+The @code{__builtin_alloca} function is provided to make it possible to
+allocate arrays with a runtime bound on the stack.  Since C99 variable
+length arrays offer similar functionality under a portable, more convenient,
+and safer interface they are recommended instead, in both C99 and C++
+programs where GCC provides them as an extension.
+
+@end deftypefn
+
+@deftypefn {Built-in Function} void* __builtin_alloca_with_align (size_t size, size_t align)
+The @code{__builtin_alloca_with_align} function must be called at block
+scope.  The function allocates an object @var{align} bytes large on
+the stack of the calling function.  The allocated object is aligned on
+the boundary specified by the argument @var{align} whose unit is given
+in bits (not bytes).  @var{size} must be positive and not exceed the stack
+size limit.  @var{align} must be a constant integer expression that
+evaluates to a power of 2 greater than or equal to @code{__CHAR_BIT__}.
+Invocations with other values are rejected with an error.  The function
+returns a pointer to the first byte of the allocated object.  The lifetime
+of the allocated object ends at the end of the block in which the function
+was called.  The allocated storage is released no later than just before
+the calling function returns to its called, but may be released at the end
+of the block in which the function was called.
+
+For example, in the following function the call to @code{g()} is unsafe
+because when @code{overalign} is non-zero, the space allocated by
+@code{__builtin_alloca_with_align} may have been released at the end
+of the @code{if} statement in which it was called.
+
+@smallexample
+void f (unsigned n, bool overalign)
+@{
+  void *p;
+  if (overalign)
+    p = __builtin_alloca_with_align (n, 64);
+  else
+    p = __builtin_alloc (n);
+
+  g (p, n);   // unsafe
+@}
+@end smallexample
+
+Since the @code{__builtin_alloca_with_align} function doesn't validate its
+arguments it is the responsibility of its caller to make sure the argument
+doesn't cause it to exceed the stack size limit.
+The @code{__builtin_alloca_with_align} function is provided to make
+it possible to allocate overaligned arrays with a runtime bound on
+the stack.  Since C99 variable length arrays offer the same functionality
+under a portable, more convenient, and safer interface they are recommended
+instead, in both C99 and C++ programs where GCC provides them as
+an extension.
+
+@end deftypefn
+
 @deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
 
 You can use the built-in function @code{__builtin_types_compatible_p} to
Index: gcc/testsuite/gcc.dg/builtins-68.c
===================================================================
--- gcc/testsuite/gcc.dg/builtins-68.c	(revision 0)
+++ gcc/testsuite/gcc.dg/builtins-68.c	(working copy)
@@ -0,0 +1,106 @@ 
+/* PR middle-end/69780 - [4.9/5/6 Regression] ICE on
+     __builtin_alloca_with_align with small alignment */
+/* { dg-require-effective-target alloca } */
+/* { dg-do compile } */
+/* { dg-options "-Wno-long-long" } */
+
+#define CHAR_BIT  __CHAR_BIT__
+#define INT_MAX   __INT_MAX__
+#define INT_MIN   (-INT_MAX - 1)
+#define LONG_MAX  __LONG_MAX__
+#define LLONG_MAX __LONG_LONG_MAX__
+
+static void* p;
+
+/* Verify that valid __builtin_alloca_with_align expressions are accepted.  */
+void test_valid (int n)
+{
+  enum {
+    A1   = CHAR_BIT *   1,
+    A2   = CHAR_BIT *   2,
+    A4   = CHAR_BIT *   4,
+    A8   = CHAR_BIT *   8,
+    A16  = CHAR_BIT *  16,
+    A32  = CHAR_BIT *  32
+  };
+
+  /* Valid alignments are power of 2 positive multiples of CHAR_BIT.  */
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  1);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  2);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  4);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  8);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 16);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 32);
+
+  p =  __builtin_alloca_with_align (n, A1);
+  p =  __builtin_alloca_with_align (n, A2);
+  p =  __builtin_alloca_with_align (n, A4);
+  p =  __builtin_alloca_with_align (n, A8);
+  p =  __builtin_alloca_with_align (n, A16);
+  p =  __builtin_alloca_with_align (n, A32);
+}
+
+/* Non-integer alignments must be rejected.  */
+void test_arg2_non_int (int n)
+{
+  /* Verify the full text of the diagnostic just once.  */
+  p =  __builtin_alloca_with_align (n, 0.0);         /* { dg-error "second argument to function .__builtin_alloca_with_align. must be a constant integer power of 2 between .8. and " } */
+
+  /* Disable diagnostic complaining about converting void* to int that
+     preempts the "constant integer expression" error.  */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wint-conversion"
+
+  p =  __builtin_alloca_with_align (n, (void*)0);    /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, "");          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, L"");         /* { dg-error "must be a constant integer" } */
+
+#pragma GCC diagnostic pop
+
+}
+
+/* Integer alignment that's not a constant expression must be rejected.  */
+void test_arg2_non_const (int n, int a1)
+{
+  extern const int a2;
+  static const int a3 = CHAR_BIT;
+  static volatile const int a4 = CHAR_BIT;
+  
+  p =  __builtin_alloca_with_align (n, a1);       /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, a2);       /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, a3);       /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, a4);       /* { dg-error "must be a constant integer" } */
+}
+
+/* Constant integer alignment that's not a power of 2 positive multiple
+   of CHAR_BIT must be rejected.  */
+void test_arg2_non_pow2 (int n)
+{
+  p =  __builtin_alloca_with_align (n, INT_MIN);     /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, -1);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, !1);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, !0);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  0);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  1);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  2);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  3);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  4);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  5);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  6);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  7);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n,  9);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 10);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 11);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 12);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 13);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 14);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 15);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 17);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 31);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 33);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 63);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, 65);          /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, INT_MAX);     /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, ~0U);         /* { dg-error "must be a constant integer" } */
+  p =  __builtin_alloca_with_align (n, LONG_MAX);    /* { dg-error "must be a constant integer" } */
+}
Index: gcc/testsuite/g++.dg/ext/builtin_alloca.C
===================================================================
--- gcc/testsuite/g++.dg/ext/builtin_alloca.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/builtin_alloca.C	(working copy)
@@ -0,0 +1,183 @@ 
+// PR middle-end/69780 - [4.9/5/6 Regression] ICE on
+//     __builtin_alloca_with_align with small alignment
+// { dg-require-effective-target alloca }
+// { dg-do compile }
+
+#define CHAR_BIT  __CHAR_BIT__
+#define INT_MAX   __INT_MAX__
+#define INT_MIN   (-INT_MAX - 1)
+
+static void* p;
+
+// Verify that valid __builtin_alloca_with_align expressions are accepted.
+void test_valid (int n)
+{
+  enum {
+    A1   = CHAR_BIT *   1,
+    A2   = CHAR_BIT *   2,
+    A4   = CHAR_BIT *   4,
+    A8   = CHAR_BIT *   8,
+    A16  = CHAR_BIT *  16,
+    A32  = CHAR_BIT *  32
+  };
+
+  const int a1 = A1;
+  const int a2 = A2;
+  const int a4 = A4;
+  const int a8 = A8;
+  const int a16 = A16;
+  const int a32 = A32;
+
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  1);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  2);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  4);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT *  8);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 16);
+  p =  __builtin_alloca_with_align (n, CHAR_BIT * 32);
+
+  p =  __builtin_alloca_with_align (n, A1);
+  p =  __builtin_alloca_with_align (n, A2);
+  p =  __builtin_alloca_with_align (n, A4);
+  p =  __builtin_alloca_with_align (n, A8);
+  p =  __builtin_alloca_with_align (n, A16);
+  p =  __builtin_alloca_with_align (n, A32);
+
+  p =  __builtin_alloca_with_align (n, a1);
+  p =  __builtin_alloca_with_align (n, a2);
+  p =  __builtin_alloca_with_align (n, a4);
+  p =  __builtin_alloca_with_align (n, a8);
+  p =  __builtin_alloca_with_align (n, a16);
+  p =  __builtin_alloca_with_align (n, a32);
+}
+
+template <int A> struct X { enum { Align = A }; };
+
+template <int A>
+void test_valid_template (int n)
+{
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, A);
+}
+
+template void test_valid_template<CHAR_BIT>(int);
+template void test_valid_template<CHAR_BIT * 2>(int);
+template void test_valid_template<CHAR_BIT * 4>(int);
+template void test_valid_template<CHAR_BIT * 8>(int);
+template void test_valid_template<CHAR_BIT * 16>(int);
+template void test_valid_template<CHAR_BIT * 32>(int);
+
+// Exercise the alignment in a dependent context.
+template <int A>
+void test_valid_template_dep (int n)
+{
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, X<A>::Align);
+}
+
+template void test_valid_template_dep<CHAR_BIT>(int);
+template void test_valid_template_dep<CHAR_BIT * 2>(int);
+template void test_valid_template_dep<CHAR_BIT * 4>(int);
+template void test_valid_template_dep<CHAR_BIT * 8>(int);
+template void test_valid_template_dep<CHAR_BIT * 16>(int);
+template void test_valid_template_dep<CHAR_BIT * 32>(int);
+
+// Invalid size must be rejected (and not cause an ICE).
+void test_arg1_non_int (int n)
+{
+  extern void f ();
+
+  p =  __builtin_alloca_with_align ((void*)0, 32);   // { dg-error "invalid conversion" }
+
+  p =  __builtin_alloca_with_align ("", 32);         // { dg-error "invalid conversion" }
+  p =  __builtin_alloca_with_align (L"", 32);        // { dg-error "invalid conversion" }
+  p =  __builtin_alloca_with_align (f, 32);          // { dg-error "invalid conversion" }
+}
+
+// Non-integer alignment must be rejected.
+void test_arg2_non_int (int n)
+{
+  // Verify the full text of the diagnostic just once.
+  p =  __builtin_alloca_with_align (n, 0.0);         // { dg-error "second argument to function .__builtin_alloca_with_align. must be a constant integer power of 2 between .8. and " }
+
+  p =  __builtin_alloca_with_align (n, (void*)0);    // { dg-error "invalid conversion|must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, "");          // { dg-error "invalid conversion|must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, L"");         // { dg-error "invalid conversion|must be a constant integer" }
+}
+
+// Integer alignment that's not a constant expression must be rejected.
+void test_arg2_non_const (int n, int a1)
+{
+  extern const int a2;
+  static volatile const int a3 = CHAR_BIT;
+  
+  p =  __builtin_alloca_with_align (n, a1);       // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, a2);       // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, a3);       // { dg-error "must be a constant integer" }
+}
+
+// Constant integer alignment that's not a power of 2 positive multiple
+// of CHAR_BIT must be rejected.
+void test_arg2_non_pow2 (int n)
+{
+  p =  __builtin_alloca_with_align (n, INT_MIN);     // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, -1);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, !1);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, !0);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  0);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  1);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  2);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  3);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  4);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  5);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  6);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  7);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n,  9);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 10);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 11);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 12);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 13);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 14);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 15);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 17);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 31);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 33);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 63);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, 65);          // { dg-error "must be a constant integer" }
+  p =  __builtin_alloca_with_align (n, INT_MAX);     // { dg-error "must be a constant integer" }
+}
+
+// Exercise invalid alignment specified by a template argument.
+template <int A>
+void test_invalid_template_1 (int n)
+{
+  // Valid alignments are power of 2 positive multiples of CHAR_BIT.
+  p =  __builtin_alloca_with_align (n, A);           // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_1<1>(int);
+
+template <int A>
+void test_invalid_template_7 (int n)
+{
+  p =  __builtin_alloca_with_align (n, A);           // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_7<7>(int);
+
+template <int A>
+void test_invalid_template_9 (int n)
+{
+  p =  __builtin_alloca_with_align (n, A);           // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_9<9>(int);
+
+// Exercise invalid alignment specified by a template dependent argument.
+template <int A>
+void test_invalid_template_dep_1 (int n)
+{
+  p =  __builtin_alloca_with_align (n, X<A>::Align);     // { dg-error "must be a constant integer" }
+}
+
+template void test_invalid_template_dep_1<1>(int);