On 07/10/2016 06:09 PM, Martin Sebor wrote:
On 07/08/2016 05:48 AM, Aldy Hernandez wrote:
[New thread now that I actually have a tested patch :)].
...
I have overhauled the options and added extensive documentation to
invoke.texi explaining them.  See the included testcases.  I have tried
to add a testcase for everything the pass currently handles.

In the interest of keeping a consistent relationship with -Wvla, we now
have:

-Walloca:    Warn on every use of alloca (not VLAs).
-Walloca=999:    Warn on unbounded uses of alloca, bounded uses with
         no known limit, and bounded uses where the number of
         bytes is greater than 999.
-Wvla:        Behaves as currently (warn on every use of VLAs).
-Wvla=999:    Similar to -Walloca=999, but for -Wvla.

Notice plain -Walloca doesn't have a default, and just warns on every
use of alloca, just like -Wvla does for VLAs.  This way we can be
consistent with -Wvla, and just add the -Wvla=999 variant.

I like it!

This patch depends on range information, which is less than stellar past
the VRP pass.  To get better range information, we'd have to incorporate
this somehow into the VRP pass and use the ASSERT_EXPRs therein.  And
still, VRP gets awfully confused with PHI merge points.  Andrew Macleod
is working on a new fancy range info infrastructure that should
eliminate a lot of the false positives we may get and/or help us
diagnose a wider range of cases.  Hence the reason that I'm not bending
over backwards to incorporate this pass into tree-vrp.c.

FYI, I have a few XFAILed tests in this patch, to make sure we don't
lose track of possible improvements (which in this case should be
handled by better range info).  What's the blessed way of doing this?
Are adding new XFAILed tests acceptable?

I have regstrapped this patch on x86-64 Linux, and have tested the
resulting compiler by building glibc with:

/source/glibc/configure --prefix=/usr CC="/path/bin/gcc -Walloca=5000"
--disable-werror

This of course, pointed out all sorts of interesting things!

Fire away!

I've played with the patch a bit over the weekend and have a few
comments and suggestions (I hope you won't regret encouraging me :)

Not at all.  Your feedback is quite valuable.

I like the consistency between -Walloca and -Wvla! (And despite
the volume of my remaining comments, the rest of the patch too!

Well, after Manuel's comments I decided to split things up as previously discussed:

-Wvla: warn on any VLA uses (as currently on mainline).
-Wvla-larger-than=N: warn on unbounded use of VLAs, etc.
-Walloca: same as -Wvla but for alloca.
-Walloca-larger-than=N: same as -Wvla-larger-than=N but for alloca.


1) Optimization.  Without -O2 GCC prints:

   sorry, unimplemented: -Walloca ignored without -O2

Changed to only sorry() on the -Wvla-larger-than=* and -Walloca-larger-than=* options. The -Wvla and -Walloca warnings work without optimization as you suggest below.


It seems that a warning would be more appropriate here than
a hard error, but the checker could, and I would say should, be
made available (in a limited form) without optimization because
  -Walloca with no argument doesn't rely on it.  I suspect in this
form, -Walloca is probably mainly going to be useful as a mechanism
to enforce a "thou shall not use alloca" policy, though not much
more beyond that.  Some development processes only require that
code build without optimization in order to allow a commit and
do more extensive testing with optimization during continuous
integration, and not enabling it at -O0 would make it difficult
to adopt the warning on projects that use such a process.

Done. -Walloca and -Wvla warn on any use of alloca and VLAs accordingly, with or without optimization. I sorry() on the bounded cases.


2) When passed an argument of a signed type, GCC prints

   warning: cast from signed type in alloca

even though there is no explicit cast in the code.  It may not
be obvious why the conversion is a problem in this context.  I
would suggest to rephrase the warning along the lines of
-Wsign-conversion which prints:

   conversion to ‘long unsigned int’ from ‘int’ may change the sign of
the result

and add why it's a potential problem.  Perhaps something like:

   argument to alloca may be too large due to conversion from
   'int to 'long unsigned int'

Fixed:

void
g2 (short int n)
{
  void *p;
  p = __builtin_alloca (n);
  f (p);
}

b.c:9:5: warning: argument to alloca may be too large due to conversion from 'short int' to 'long unsigned int' [-Walloca-larger-than=]
   p = __builtin_alloca (n);
   ~~^~~~~~~~~~~~~~~~~~~~~~

I wonder whether we could do all this in the front-ends as in -Wsign-conversion, but this is something that can be done as a follow-up if we really want it.


(In addition, assuming one accepts the lack of range checking and
constant propagation, this aspect of -Walloca also doesn't need
optimization.)

I did not do this. It is technically possible, but I did not want to complicate things further. -Walloca works without optimization, and flags everything. -Walloca-larger-than=* works with -O2 and above.


3) I wonder if the warning should also detect alloca calls with
a zero argument and VLAs of zero size.  They are both likely to
be programmer errors.  (Although it seems that that would need
to be done earlier than in the alloca pass.)

Fixed and test added as well.


4) I wasn't able to trigger the -Wvla=N warning with VLAs used
in loops even though VRP provides the range of the value:

   $ cat t.c && /build/gcc-walloca/gcc/xgcc -B /build/gcc-walloca/gcc
-O2 -S -Wall -Wextra -Wpedantic -Wvla=3 -fdump-tree-vrp=/dev/stdout t.c
| grep _2
   void f0 (void*);

   void f1 (void)
   {
     for (int i = 0; i != 32; ++i)
     {
       char a [i];
       f0 (a);
     }
   }

   _2: [0, 31]
     sizetype _2;
     _2 = (sizetype) i_16;
     a.1_8 = __builtin_alloca_with_align (_2, 8);

There is a "documented" reason for this: :)

      // Do not warn on VLAs occurring in a loop, since VLAs are
      // guaranteed to be cleaned up when they go out of scope.
      // That is, there is a corresponding __builtin_stack_restore
      // at the end of the scope in which the VLA occurs.


5) The -Wvla=N logic only seems to take into consideration the number
of elements but not the size of the element type. For example, I wasn't
able to get it to warn on the following with -Wvla=255 or greater:

   void f0 (void*);

   void f1 (unsigned char a)
   {
     int x [a];   // or even char a [n][__INT_MAX__];
     f0 (x);
   }

That was a huge oversight (or should I say over-engineering) on my part. Fixed.


6) The patch seems to assume that __builtin_alloca_with_align implies
a VLA, but that need not be the case.  Based on tree dumps it looks
like there is a way to distinguish a VLA from a call to the built-in.
For accuracy's sake I think it would be worth making that distinction
in the diagnostic.

Good catch.  Fixed:

-Walloca* only applies to alloca(), __builtin_alloca, and __builtin_alloca_with_align() called directly. Whereas, __builtin_alloca_with_align() called through a VLA is warned as such. There is no wording distinction between direct calls to __builtin_alloca and direct calls to __builtin_alloca_with_align though, FYI.


7) The -Walloca=N and -Wvla=N argument is a 32-bit integer and no
checking appears to be done to make sure it doesn't overflow, so
that invoking GCC with an argument of UINT_MAX results in:

   cc1: note: -Wvla=0 disables -Wvla.  Use -Wno-vla instead.

and with larger arguments in imposing a limit that's modulo UINT_MAX.
Although stack size in excess of UINT_MAX bytes is unlikely, it seems
that such exceedingly large arguments should be handled more gracefully
(if they cannot be stored in a size_t argument it would be nice give
a warning).

This seems to be a limitation of the option handling machinery. For example, by the time type I get a hold of the passed value in c_common_handle_option(), we don't even know there was an overflow.

That is, when you pass -Walloca-larger-than=4294967296 (MAX_UINT + 1), c_common_handle_option() just sees value == 0. However, passing MAX_UINT is handled prior to c_common_handle_option in the generic machinery:

./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet -Walloca-larger-than=4294967295 -O2

cc1: error: argument to ‘-Walloca-larger-than=’ should be a non-negative integer

This is a problem with the generic machinery so I would prefer someone file a bugzilla report :), as this affects other options.

For that matter, "type" in c_common_handle_option() seems to be of "signed int", whereas the option was defined in c.opt as UInteger. That should probably be addressed as well.

Good catch, though.


8) Finally, I think it would be helpful to provide information about
the values GCC used to decide to issue the warning, especially when
optimization is involved.  In many cases it will not be immediately
obvious how GCC determined that an alloca argument is too big, or
what the limit even is (for instance, when the -Walloca=N option
is set via a #pragma GCC diagnostic far away from the call).
Mentioning both the argument value or range and the threshold for
the warning will help make it clear.

Ughhh...you're making me write user friendly stuff. The reason I got into compilers was so I wouldn't have to deal with the user :).

  if (n < 2000)
    {
    p = __builtin_alloca (n);
    f (p);
    }

./cc1 a.c -fdump-tree-all-vops-alias-details-graph -quiet -I/tmp -Walloca-larger-than=100 -O2
a.c: In function ‘g2’:
a.c:9:7: warning: argument to alloca may be too large [-Walloca-larger-than=]
     p = __builtin_alloca (n);
     ~~^~~~~~~~~~~~~~~~~~~~~~
a.c:9:7: note: limit is '100' bytes, but argument may be '1999'

Happy? :-)

Of course, the non-obvious cases may get ranges you may not expect. This should get better with improved range info.


Martin

PS I also ran into a couple internal compiler errors with the test
cases below:

   void f0 (void*);

   void f1 (int a, int b)
   {
     int x [a][b];
     f0 (x);
   }

Fixed. There were issues with multi-dimensional VLAs, but mainly it was me being overly smart with VLA inner types.


   0x11def63 tree_to_uhwi(tree_node const*)
   /src/gcc/walloca/gcc/tree.c:7339
   ...

   void f0 (void*);

   void f1 (unsigned char a)
   {
     void *p = __builtin_alloca_with_align (a, 8);
     f0 (p);
   }

Fixed now that the distinction between direct __builtin_alloca_with_align calls and VLAs has been addressed.

Phew.  I think that's it.

Tested on x86-64 Linux.

What do you think?

Aldy
gcc/

        * Makefile.in (OBJS): Add gimple-ssa-warn-walloca.o.
        * passes.def: Add two instances of pass_walloca.
        * tree-pass.h (make_pass_walloca): New.
        * gimple-ssa-warn-walloca.c: New file.
        * opts.c (finish_options): Warn when using -Wvla-larger-than= and
        -Walloca-larger-than= without -O2 or greater.
        * doc/invoke.texi: Document -Walloca, -Walloca-larger-than=, and
        -Wvla-larger-than= options.

gcc/c-family/

        * c.opt (Walloca): New.
        (Walloca-larger-than=): New.
        (Wvla-larger-than=): New.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 776f6d7..2a13b8f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1284,6 +1284,7 @@ OBJS = \
        gimple-ssa-nonnull-compare.o \
        gimple-ssa-split-paths.o \
        gimple-ssa-strength-reduction.o \
+       gimple-ssa-warn-alloca.o \
        gimple-streamer-in.o \
        gimple-streamer-out.o \
        gimple-walk.o \
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index ff6339c..dc2be2d 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -376,6 +376,16 @@ c_common_handle_option (size_t scode, const char *arg, int 
value,
       cpp_opts->warn_num_sign_change = value;
       break;
 
+    case OPT_Walloca_larger_than_:
+      if (!value)
+       inform (loc, "-Walloca-larger-than=0 is meaningless");
+      break;
+
+    case OPT_Wvla_larger_than_:
+      if (!value)
+       inform (loc, "-Wvla-larger-than=0 is meaningless");
+      break;
+
     case OPT_Wunknown_pragmas:
       /* Set to greater than 1, so that even unknown pragmas in
         system headers will be warned about.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 83fd84c..a8e9532 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -275,6 +275,15 @@ Wall
 C ObjC C++ ObjC++ Warning
 Enable most warning messages.
 
+Walloca
+C ObjC C++ ObjC++ Var(warn_alloca) Warning
+
+Walloca-larger-than=
+C ObjC C++ ObjC++ Var(warn_alloca_limit) Warning Joined RejectNegative UInteger
+-Walloca-larger-than=<number> Warn on unbounded uses of
+alloca, and on bounded uses of alloca whose bound can be larger than
+<number> bytes.
+
 Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
@@ -980,6 +989,12 @@ Wvla
 C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
 Warn if a variable length array is used.
 
+Wvla-larger-than=
+C ObjC C++ ObjC++ Var(warn_vla_limit) Warning Joined RejectNegative UInteger
+-Wvla-larger-than=<number> Warn on unbounded uses of variable-length arrays, 
and
+on bounded uses of variable-length arrays whose bound can be
+larger than <number> bytes.
+
 Wvolatile-register-var
 C ObjC C++ ObjC++ Var(warn_volatile_register_var) Warning LangEnabledBy(C ObjC 
C++ ObjC++,Wall)
 Warn when a register variable is declared volatile.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2105351..98a4a5b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -253,6 +253,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
+-Walloca -Walloca-larger-than=@var{n} @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wno-attributes -Wbool-compare -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -309,7 +310,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wunused-const-variable -Wunused-const-variable=@var{n} @gol
 -Wunused-but-set-parameter -Wunused-but-set-variable @gol
 -Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol
--Wvla -Wvolatile-register-var  -Wwrite-strings @gol
+-Wvla -Wvla-larger-than=@var{n} -Wvolatile-register-var  -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant -Whsa}
 
 @item C and Objective-C-only Warning Options
@@ -4618,6 +4619,61 @@ annotations.
 Warn about overriding virtual functions that are not marked with the override
 keyword.
 
+@item -Walloca
+@opindex Wno-alloca
+@opindex Walloca
+This option warns on all uses of @code{alloca} in the source.
+
+@item -Walloca-larger-than=@var{n}
+This option warns on calls to @code{alloca} that are not bounded by a
+controlling predicate limiting its size to @var{n} bytes, or calls to
+@code{alloca} where the bound is unknown.
+
+For example, a bounded case of @code{alloca} could be:
+
+@smallexample
+unsigned int n;
+...
+if (n <= 1000)
+  alloca (n);
+@end smallexample
+
+In the above example, passing @code{-Walloca=1000} would not issue a
+warning because the call to @code{alloca} is known to be at most 1000
+bytes.  However, if @code{-Walloca=500} was passed, the compiler would
+have emitted a warning.
+
+Unbounded uses, on the other hand, are uses of @code{alloca} with no
+controlling predicate verifying its size.  For example:
+
+@smallexample
+stuff ();
+alloca (n);
+@end smallexample
+
+If @code{-Walloca=500} was passed, the above would trigger a warning,
+but this time because of the lack of bounds checking.
+
+Note, that even seemingly correct code involving signed integers could
+cause a warning:
+
+@smallexample
+signed int n;
+...
+if (n < 500)
+  alloca (n);
+@end smallexample
+
+In the above example, @var{n} could be negative, causing a larger than
+expected argument to be implicitly casted into the @code{alloca} call.
+
+This option also warns when @code{alloca} is used in a loop.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Wvla-larger-than=@var{n}}.
+
 @item -Warray-bounds
 @itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
@@ -5782,9 +5838,21 @@ moving from a moved-from object, this warning can be 
disabled.
 @item -Wvla
 @opindex Wvla
 @opindex Wno-vla
-Warn if variable length array is used in the code.
+Warn if a variable-length array is used in the code.
 @option{-Wno-vla} prevents the @option{-Wpedantic} warning of
-the variable length array.
+the variable-length array.
+
+@item -Wvla-larger-than=@var{n}
+If this option is used, the compiler will warn on uses of
+variable-length arrays where the size is either unbounded, or bounded
+by an argument that can be larger than @var{n} bytes.  This is similar
+to how @option{-Walloca-larger-than=@var{n}} works, but with
+variable-length arrays.
+
+This warning is not enabled by @option{-Wall}, and is only active when
+@option{-ftree-vrp} is active (default for @option{-O2} and above).
+
+See also @option{-Walloca-larger-than=@var{n}}.
 
 @item -Wvolatile-register-var
 @opindex Wvolatile-register-var
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
new file mode 100644
index 0000000..cbd6535
--- /dev/null
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -0,0 +1,486 @@
+/* Warn on problematic uses of alloca and variable length arrays.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <al...@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa.h"
+#include "params.h"
+#include "tree-cfg.h"
+#include "calls.h"
+#include "cfgloop.h"
+
+const pass_data pass_data_walloca = {
+  GIMPLE_PASS,
+  "walloca",
+  OPTGROUP_NONE,
+  TV_NONE,
+  PROP_cfg, // properties_required
+  0,       // properties_provided
+  0,       // properties_destroyed
+  0,       // properties_start
+  0,       // properties_finish
+};
+
+class pass_walloca : public gimple_opt_pass
+{
+public:
+  pass_walloca (gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_walloca, ctxt), first_time_p (false)
+  {}
+  opt_pass *clone () { return new pass_walloca (m_ctxt); }
+  void set_pass_param (unsigned int n, bool param)
+    {
+      gcc_assert (n == 0);
+      first_time_p = param;
+    }
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *);
+
+ private:
+  // Set to TRUE the first time we run this pass on a function.
+  bool first_time_p;
+};
+
+bool
+pass_walloca::gate (function *fun ATTRIBUTE_UNUSED)
+{
+  // The first time this pass is called, it is called before
+  // optimizations have been run and range information is unavailable,
+  // so we can only perform strict alloca checking.
+  if (first_time_p)
+    return warn_alloca != 0;
+
+  return warn_alloca_limit > 0 || warn_vla_limit > 0;
+}
+
+// Possible problematic uses of alloca.
+enum alloca_type {
+  // Alloca argument is within known bounds that are appropriate.
+  ALLOCA_OK,
+
+  // Alloca argument is KNOWN to have a value that is too large.
+  ALLOCA_BOUND_DEFINITELY_LARGE,
+
+  // Alloca argument may be too large.
+  ALLOCA_BOUND_MAYBE_LARGE,
+
+  // Alloca argument is bounded but of an indeterminate size.
+  ALLOCA_BOUND_UNKNOWN,
+
+  // Alloca argument was casted from a signed integer.
+  ALLOCA_CAST_FROM_SIGNED,
+
+  // Alloca appears in a loop.
+  ALLOCA_IN_LOOP,
+
+  // Alloca argument is 0.
+  ALLOCA_ARG_IS_ZERO,
+
+  // Alloca call is unbounded.  That is, there is no controlling
+  // predicate for its argument.
+  ALLOCA_UNBOUNDED
+};
+
+// We have a few heuristics up our sleeve to determine if a call to
+// alloca() is within bounds.  Try them out and return the type of
+// alloca call this is based on its argument.
+//
+// Given a known argument (ARG) to alloca() and an EDGE (E)
+// calculating said argument, verify that the last statement in the BB
+// in E->SRC is a gate comparing ARG to an acceptable bound for
+// alloca().  See examples below.
+//
+// MAX_SIZE is WARN_ALLOCA= adjusted for VLAs.  It is the maximum size
+// in bytes we allow for arg.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// Returns the alloca type.
+
+static enum alloca_type
+alloca_call_type_by_arg (tree arg, edge e, unsigned max_size,
+                        wide_int *assumed_limit)
+{
+  // All the tests bellow depend on the jump being on the TRUE path.
+  if (!(e->flags & EDGE_TRUE_VALUE))
+    return ALLOCA_UNBOUNDED;
+
+  basic_block bb = e->src;
+  gimple_stmt_iterator gsi = gsi_last_bb (bb);
+  gimple *last = gsi_stmt (gsi);
+  if (!last || gimple_code (last) != GIMPLE_COND)
+    return ALLOCA_UNBOUNDED;
+
+  /* Check for:
+     if (ARG <= N)
+       goto <bb 3>;
+      else
+        goto <bb 4>;
+      <bb 3>:
+      alloca(ARG);
+  */
+  if (gimple_cond_code (last) == LE_EXPR
+      && gimple_cond_lhs (last) == arg)
+    {
+      if (TREE_CODE (gimple_cond_rhs (last)) == INTEGER_CST)
+       {
+         tree rhs = gimple_cond_rhs (last);
+         if (tree_to_uhwi (rhs) > max_size)
+           {
+             *assumed_limit = rhs;
+             return ALLOCA_BOUND_MAYBE_LARGE;
+           }
+         return ALLOCA_OK;
+       }
+      else
+       return ALLOCA_BOUND_UNKNOWN;
+    }
+
+  /* Check for:
+     if (arg .cond. LIMIT) -or- if (LIMIT .cond. arg)
+       alloca(arg);
+
+     Where LIMIT has a bound of unknown range.  */
+  tree limit = NULL;
+  if (gimple_cond_lhs (last) == arg)
+    limit = gimple_cond_rhs (last);
+  else if (gimple_cond_rhs (last) == arg)
+    limit = gimple_cond_lhs (last);
+  if (limit && TREE_CODE (limit) == SSA_NAME)
+    {
+      wide_int min, max;
+      value_range_type range_type = get_range_info (limit, &min, &max);
+      if (range_type == VR_UNDEFINED || range_type == VR_VARYING)
+       return ALLOCA_BOUND_UNKNOWN;
+      // FIXME: We could try harder here and handle a possible range
+      // or anti-range.  Hopefully the upcoming changes to range info
+      // will give us finer grained info, and we can avoid somersaults
+      // here.
+    }
+
+  return ALLOCA_UNBOUNDED;
+}
+
+// Return TRUE if SSA's definition is a cast from a signed type.
+// If so, set *INVALID_CASTED_TYPE to the signed type.
+
+static bool
+cast_from_signed_p (tree ssa, tree *invalid_casted_type)
+{
+  gimple *def = SSA_NAME_DEF_STMT (ssa);
+  if (def
+      && !gimple_nop_p (def)
+      && gimple_assign_cast_p (def)
+      && !TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (def))))
+    {
+      *invalid_casted_type = TREE_TYPE (gimple_assign_rhs1 (def));
+      return true;
+    }
+  return false;
+}
+
+// Return TURE if X has a maximum range of MAX, basically covering the
+// entire domain, in which case it's no range at all.
+
+static bool
+is_max (tree x, wide_int max)
+{
+  return wi::max_value (TREE_TYPE (x)) == max;
+}
+
+// Analyze the alloca call in STMT and return an `enum alloca_type'
+// explaining what type of alloca it is.  IS_VLA is set if the alloca
+// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+//
+// If the alloca bound is determined to be too large, ASSUMED_LIMIT is
+// set to the bound used to determine this.  ASSUMED_LIMIT is only set
+// for ALLOCA_BOUND_MAYBE_LARGE and ALLOCA_BOUND_DEFINITELY_LARGE.
+//
+// If the alloca call may be too large because of a cast from a signed
+// type to an unsigned type, set *INVALID_CASTED_TYPE to the
+// problematic signed type.
+
+static enum alloca_type
+alloca_call_type (gimple *stmt, bool is_vla, wide_int *assumed_limit,
+                 tree *invalid_casted_type)
+{
+  gcc_assert (gimple_alloca_call_p (stmt));
+  tree len = gimple_call_arg (stmt, 0);
+  enum alloca_type w = ALLOCA_UNBOUNDED;
+  wide_int min, max;
+
+  if (is_vla)
+    gcc_assert (warn_vla_limit > 0);
+  if (!is_vla)
+    gcc_assert (warn_alloca_limit > 0);
+
+  // Check if we're in a loop.
+  basic_block bb = gimple_bb (stmt);
+  if (bb->loop_father
+      // ?? Functions with no loops get a loop_father?  I
+      // don't get it.  The following conditional seems to do
+      // the trick to exclude such nonsense.
+      && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+    {
+      // Do not warn on VLAs occurring in a loop, since VLAs are
+      // guaranteed to be cleaned up when they go out of scope.
+      // That is, there is a corresponding __builtin_stack_restore
+      // at the end of the scope in which the VLA occurs.
+      tree fndecl = gimple_call_fn (stmt);
+      while (TREE_CODE (fndecl) == ADDR_EXPR)
+       fndecl = TREE_OPERAND (fndecl, 0);
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+         && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
+       return ALLOCA_OK;
+
+      return ALLOCA_IN_LOOP;
+    }
+
+  // Adjust warn_alloca_max_size for VLAs, by taking the underlying
+  // type into account.
+  unsigned HOST_WIDE_INT max_size;
+  if (is_vla)
+    max_size = (unsigned HOST_WIDE_INT) warn_vla_limit;
+  else
+    max_size = (unsigned HOST_WIDE_INT) warn_alloca_limit;
+
+  // Check for the obviously bounded case.
+  if (TREE_CODE (len) == INTEGER_CST)
+    {
+      if (tree_to_uhwi (len) > max_size)
+       {
+         *assumed_limit = len;
+         return ALLOCA_BOUND_DEFINITELY_LARGE;
+       }
+      if (integer_zerop (len))
+       return ALLOCA_ARG_IS_ZERO;
+      w = ALLOCA_OK;
+    }
+  else if (TREE_CODE (len) != SSA_NAME)
+    return ALLOCA_UNBOUNDED;
+  // Check the range info if available.
+  else
+    {
+      if (value_range_type range_type = get_range_info (len, &min, &max))
+       {
+         if (range_type == VR_RANGE)
+           {
+             if (wi::leu_p (max, max_size))
+               w = ALLOCA_OK;
+             else if (is_max (len, max))
+               {
+                 // A cast may have created a range we don't care
+                 // about.  For instance, a cast from 16-bit to
+                 // 32-bit creates a range of 0..65535, even if there
+                 // is not really a determinable range in the
+                 // underlying code.  In this case, look through the
+                 // cast at the original argument, and fall through
+                 // to look at other alternatives.
+                 gimple *def = SSA_NAME_DEF_STMT (len);
+                 if (gimple_assign_cast_p (def))
+                   len = gimple_assign_rhs1 (def);
+               }
+             else
+               {
+                 /* If `len' is merely a cast that is being
+                    calculated right before the call to alloca, look
+                    at the range for the original value.
+
+                    This avoids the cast creating a range where the
+                    original expression did not have a range:
+
+                    # RANGE [0, 18446744073709551615] NONZERO 4294967295
+                    _2 = (long unsigned int) n_7(D);
+                    p_9 = __builtin_alloca (_2);
+
+                    The correct thing would've been for the user to
+                    use size_t, which in the case above would've been
+                    'long unsigned int', and everything would've
+                    worked.  But we have to catch cases where the
+                    user is using some other compatible type for the
+                    call argument to alloca (say unsigned short).  */
+                 gimple *def = SSA_NAME_DEF_STMT (len);
+                 if (gimple_assign_cast_p (def))
+                   {
+                     len = gimple_assign_rhs1 (def);
+                     range_type = get_range_info (len, &min, &max);
+                   }
+
+                 if (range_type != VR_VARYING && is_max (len, max))
+                   {
+                     // Treat a max of the entire domain as if it had no
+                     // range info, and fall through the try other
+                     // alternatives.
+                   }
+                 else
+                   {
+                     *assumed_limit = max;
+                     return ALLOCA_BOUND_MAYBE_LARGE;
+                   }
+               }
+           }
+         else if (range_type == VR_ANTI_RANGE)
+           {
+             // There may be some wrapping around going on.  Catch it
+             // with this heuristic.  Hopefully, this VR_ANTI_RANGE
+             // nonsense will go away, and we won't have to catch the
+             // sign conversion problems with this crap.
+             if (cast_from_signed_p (len, invalid_casted_type))
+               return ALLOCA_CAST_FROM_SIGNED;
+
+             // Fall thru and try other things.
+           }
+         else if (range_type == VR_VARYING)
+           {
+             // No easily determined range.  Try other things.
+           }
+       }
+    }
+
+  // If we couldn't find anything, try a few heuristics for things we
+  // can easily determine.  Check these misc cases but only accept
+  // them if all predecessors have a known bound.
+  if (w == ALLOCA_UNBOUNDED)
+    {
+      w = ALLOCA_OK;
+      for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
+       {
+         enum alloca_type w
+           = alloca_call_type_by_arg (len, EDGE_PRED (bb, ix), max_size,
+                                      assumed_limit);
+         if (w != ALLOCA_OK)
+           return w;
+       }
+    }
+
+  return w;
+}
+
+unsigned int
+pass_walloca::execute (function *fun)
+{
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fun)
+    {
+      for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
+          gsi_next (&si))
+       {
+         gimple *stmt = gsi_stmt (si);
+         location_t loc = gimple_location (stmt);
+
+         if (!gimple_alloca_call_p (stmt))
+           continue;
+         gcc_assert (gimple_call_num_args (stmt) >= 1);
+
+         bool is_vla = gimple_alloca_call_p (stmt)
+           && gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
+
+         // Strict mode whining for VLAs is handled by the front-end,
+         // so we can safely ignore this case.  Also, ignore VLAs if
+         // the user doesn't care about them.
+         if (is_vla
+             && (warn_vla > 0 || !warn_vla_limit))
+           continue;
+
+         if (!is_vla && (warn_alloca || !warn_alloca_limit))
+           {
+             if (warn_alloca)
+               warning_at (loc, OPT_Walloca, "use of alloca");
+             continue;
+           }
+
+         wide_int assumed_limit
+           = wi::to_wide (integer_zero_node,
+                          TYPE_PRECISION (size_type_node));
+         tree invalid_casted_type = NULL;
+         enum alloca_type w = alloca_call_type (stmt, is_vla, &assumed_limit,
+                                                &invalid_casted_type);
+         enum opt_code wcode
+           = is_vla ? OPT_Wvla_larger_than_ : OPT_Walloca_larger_than_;
+         const char *alloca_str
+           = is_vla ? "variable-length array" : "alloca";
+         char buff[WIDE_INT_MAX_PRECISION / 4 + 4];
+         switch (w)
+           {
+           case ALLOCA_OK:
+             break;
+           case ALLOCA_BOUND_MAYBE_LARGE:
+             gcc_assert (assumed_limit != 0);
+             if (warning_at (loc, wcode,
+                             "argument to %s may be too large", alloca_str))
+               {
+                 print_decu (assumed_limit, buff);
+                 inform (loc, "limit is '%u' bytes, but argument may be '%s'",
+                         is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+               }
+             break;
+           case ALLOCA_BOUND_DEFINITELY_LARGE:
+             gcc_assert (assumed_limit != 0);
+             if (warning_at (loc, wcode,
+                             "argument to %s is too large", alloca_str))
+               {
+                 print_decu (assumed_limit, buff);
+                 inform (loc, "limit is %u' bytes, but argument is '%s'",
+                         is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+               }
+             break;
+           case ALLOCA_BOUND_UNKNOWN:
+             warning_at (loc, wcode, "%s bound is unknown", alloca_str);
+             break;
+           case ALLOCA_UNBOUNDED:
+             warning_at (loc, wcode, "unbounded use of %s", alloca_str);
+             break;
+           case ALLOCA_IN_LOOP:
+             warning_at (loc, wcode, "use of %s within a loop", alloca_str);
+             break;
+           case ALLOCA_CAST_FROM_SIGNED:
+             gcc_assert (invalid_casted_type != NULL_TREE);
+             warning_at (loc, wcode, "argument to %s may be too large due to "
+                         "conversion from '%T' to '%T'",
+                         alloca_str, invalid_casted_type, size_type_node);
+             break;
+           case ALLOCA_ARG_IS_ZERO:
+             warning_at (loc, wcode, "argument to %s is zero", alloca_str);
+             break;
+           default:
+             gcc_unreachable ();
+           }
+       }
+    }
+  return 0;
+}
+
+gimple_opt_pass *
+make_pass_walloca (gcc::context *ctxt)
+{
+  return new pass_walloca (ctxt);
+}
diff --git a/gcc/opts.c b/gcc/opts.c
index e80331f..8a84901 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -743,6 +743,20 @@ finish_options (struct gcc_options *opts, struct 
gcc_options *opts_set,
   if (opts->x_flag_tm && opts->x_flag_non_call_exceptions)
     sorry ("transactional memory is not supported with non-call exceptions");
 
+  // -Walloca-larger-than=N needs range info which is only available at -O2.
+  if (opts->x_warn_alloca_limit > 0 && opts->x_optimize < 2)
+    {
+      sorry ("-Walloca-larger-than=N ignored without -O2");
+      opts->x_warn_alloca_limit = 0;
+    }
+
+  // -Wvla-larger-than= needs range info which is only available at -O2.
+  if (opts->x_warn_vla_limit > 0 && opts->x_optimize < 2)
+    {
+      sorry ("-Wvla-larger-than= ignored without -O2");
+      opts->x_warn_vla_limit = 0;
+    }
+
   /* Unless the user has asked for section anchors, we disable toplevel
      reordering at -O0 to disable transformations that might be surprising
      to end users and to get -fno-toplevel-reorder tested.  */
diff --git a/gcc/passes.def b/gcc/passes.def
index 3647e90..591add2 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_expand_omp);
   NEXT_PASS (pass_build_cgraph_edges);
+  NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
   TERMINATE_PASS_LIST (all_lowering_passes)
 
   /* Interprocedural optimization passes.  */
@@ -303,6 +304,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_simduid_cleanup);
       NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_cse_reciprocals);
+      NEXT_PASS (pass_walloca, /*strict_mode_p=*/false);
       NEXT_PASS (pass_reassoc, false /* insert_powi_p */);
       NEXT_PASS (pass_strength_reduction);
       NEXT_PASS (pass_split_paths);
diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c
new file mode 100644
index 0000000..3cde6de
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-1.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+#define alloca __builtin_alloca
+
+typedef __SIZE_TYPE__ size_t;
+extern size_t strlen(const char *);
+
+extern void useit (char *);
+
+int num;
+
+void foo1 (size_t len, size_t len2, size_t len3)
+{
+  int i;
+
+  for (i=0; i < 123; ++i)
+    {
+      char *s = alloca (566);  /* { dg-warning "alloca within a loop" } */
+      useit (s);
+    }
+
+  char *s = alloca (123);
+  useit (s);                   // OK, constant argument to alloca
+
+  s = alloca (num);            // { dg-warning "large due to conversion" }
+  useit (s);
+
+  s = alloca(90000);           /* { dg-warning "is too large" } */
+  useit (s);
+
+  if (len < 2000)
+    {
+      s = alloca(len);         // OK, bounded
+      useit (s);
+    }
+
+  if (len + len2 < 2000)       // OK, bounded
+    {
+      s = alloca(len + len2);
+      useit (s);
+    }
+
+  if (len3 <= 2001)
+    {
+      s = alloca(len3);                /* { dg-warning "may be too large" } */
+      useit(s);
+    }
+}
+
+void foo2 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not confused
+  // with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8); // { dg-warning "unbounded 
use of alloca" }
+  useit (p);
+}
+
+void foo3 (unsigned char a)
+{
+  if (a == 0)
+    useit (__builtin_alloca (a)); // { dg-warning "argument to alloca is zero" 
}
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-2.c b/gcc/testsuite/gcc.dg/Walloca-2.c
new file mode 100644
index 0000000..548e0ed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-2.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+void
+g1 (int n)
+{
+  void *p;
+  if (n > 0 && n < 2000)
+    p = __builtin_alloca (n);
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g2 (int n)
+{
+  void *p;
+  if (n < 2000)
+    p = __builtin_alloca (n); // { dg-warning "large due to conversion" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+void
+g3 (int n)
+{
+  void *p;
+  if (n > 0 && n < 3000)
+    {
+      p = __builtin_alloca (n); // { dg-warning "alloca may be too large" }
+      // { dg-message "note:.*argument may be '2999'" "note" { target *-*-* } 
34 }
+    }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-3.c b/gcc/testsuite/gcc.dg/Walloca-3.c
new file mode 100644
index 0000000..28df13c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=2000 -O2" } */
+
+void f (void *);
+
+__SIZE_TYPE__ LIMIT;
+
+// Warn when there is an alloca bound, but it is an unknown bound.
+
+void
+g1 (__SIZE_TYPE__ n)
+{
+  void *p;
+  if (n < LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "alloca bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
+
+// Similar to the above, but do not get confused by the upcast.
+
+unsigned short SHORT_LIMIT;
+void
+g2 (unsigned short n)
+{
+  void *p;
+  if (n < SHORT_LIMIT)
+    p = __builtin_alloca (n); // { dg-warning "alloca bound is unknown" }
+  else
+    p = __builtin_malloc (n);
+  f (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-4.c b/gcc/testsuite/gcc.dg/Walloca-4.c
new file mode 100644
index 0000000..d96cc4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=5000 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* 
} } */
+
+// Should be another variant of Walloca-7.c.
+// This should not warn, as we have a known bound within limits.
+
+ char *
+ _i18n_number_rewrite (char *w, char *rear_ptr)
+{
+
+  char *src;
+ _Bool 
+      use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
+ if (use_alloca)
+    src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
+  else
+    src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
+  return src;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-5.c b/gcc/testsuite/gcc.dg/Walloca-5.c
new file mode 100644
index 0000000..5ed1171
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=123 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* 
} } */
+
+/* The argument to alloca ends up having a range of 0..MAXINT(32bits),
+   so we think we have a range because of the upcast.  Consequently,
+   we warn with "alloca may be too large", but we should technically
+   warn with "unbounded use of alloca".
+
+   We currently drill through casts to figure this stuff out, but we
+   get confused because it's not just a cast.  It's a cast, plus a
+   multiply.
+
+   <bb 2>:
+  # RANGE [0, 4294967295] NONZERO 4294967295
+  _1 = (long unsigned int) something_4(D);
+  # RANGE [0, 34359738360] NONZERO 34359738360
+  _2 = _1 * 8;
+  _3 = __builtin_alloca (_2);
+
+  I don't know whether it's even worth such fine-grained warnings.
+  Perhaps we should generically warn everywhere with "alloca may be
+  too large".
+
+  I'm hoping that this particular case will be easier to diagnose with
+  Andrew's work.  */
+
+void useit(void *);
+void foobar(unsigned int something)
+{
+  useit(__builtin_alloca (something * sizeof (const char *))); // { dg-warning 
"unbounded use of alloca" "" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-6.c b/gcc/testsuite/gcc.dg/Walloca-6.c
new file mode 100644
index 0000000..b4d8d41
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca-larger-than=256 -O2" } */
+/* { dg-xfail-if "Currently broken but Andrew's work should fix this" { *-*-* 
} } */
+
+void f (void*);
+void g (__SIZE_TYPE__ n)
+{
+  // No warning on this case.  Range is easily determinable.
+  if (n > 0 && n < 256)
+    f (__builtin_alloca (n));
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-7.c b/gcc/testsuite/gcc.dg/Walloca-7.c
new file mode 100644
index 0000000..8476aab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O0" } */
+
+extern void f(void *);
+
+void foo(void)
+{
+  // Test that strict -Walloca works even without optimization.
+  f (__builtin_alloca(500)); // { dg-warning "use of alloca" }
+}
+
+void bar(void)
+{
+  // Test that we warn on alloca() calls, not just __builtin_alloca calls.
+  extern void *alloca(__SIZE_TYPE__);
+  f (alloca (123)); // { dg-warning "use of alloca" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-1.c b/gcc/testsuite/gcc.dg/Wvla-1.c
new file mode 100644
index 0000000..384c930
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-Wvla-larger-than=100 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void useit (char *);
+
+int num;
+
+void test_vlas (size_t num)
+{
+  char str2[num];              /* { dg-warning "unbounded use" } */
+  useit(str2);
+
+  num = 98;
+  for (int i=0; i < 1234; ++i) {
+    char str[num];             // OK, VLA in a loop, but it is a
+                               // known size *AND* the compiler takes
+                               // care of cleaning up between
+                               // iterations with
+                               // __builtin_stack_restore.
+    useit(str);
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-2.c b/gcc/testsuite/gcc.dg/Wvla-2.c
new file mode 100644
index 0000000..1124f21
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-2.c
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-O2 -Wvla-larger-than=40" } */
+
+#include <stdint.h>
+
+void f0 (void *);
+void
+f1 (__SIZE_TYPE__ a)
+{
+  if (a <= 10)
+    {
+      // 10 * 4 bytes = 40: OK!
+      uint32_t x[a];
+      f0 (x);
+    }
+}
+
+void
+f2 (__SIZE_TYPE__ a)
+{
+  if (a <= 11)
+    {
+      // 11 * 4 bytes = 44: Not OK.
+      uint32_t x[a]; // { dg-warning "array may be too large" }
+      // { dg-message "note:.*argument may be '44'" "note" { target *-*-* } 25 
}
+      f0 (x);
+    }
+}
+
+void
+f3 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 3)
+    {
+      // 5 * 3 * 4 bytes = 60: Not OK.
+      uint32_t x[a][b]; // { dg-warning "array may be too large" }
+      f0 (x);
+    }
+}
+
+void
+f4 (__SIZE_TYPE__ a, __SIZE_TYPE__ b)
+{
+  if (a <= 5 && b <= 2)
+    {
+      // 5 * 2 * 4 bytes = 40 bytes: OK!
+      uint32_t x[a][b];
+      f0 (x);
+    }
+}
+
+void
+f5 (__SIZE_TYPE__ len)
+{
+  // Test that a direct call to __builtin_alloca_with_align is not
+  // confused with a VLA.
+  void *p = __builtin_alloca_with_align (len, 8);
+  f0 (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Wvla-3.c b/gcc/testsuite/gcc.dg/Wvla-3.c
new file mode 100644
index 0000000..5124476
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wvla-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Walloca -O2" } */
+
+// Make sure we don't warn on VLA with -Walloca.
+
+void f (void*);
+
+void h1 (unsigned n)
+{
+  int a [n];
+  f (a);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 36299a6..57b61f4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -469,6 +469,7 @@ extern simple_ipa_opt_pass *make_pass_ipa_oacc 
(gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_oacc_kernels (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_gen_hsail (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_warn_nonnull_compare (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_walloca (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);

Reply via email to