Index: gcc/testsuite/g++.dg/ext/vla5.C
===================================================================
--- gcc/testsuite/g++.dg/ext/vla5.C	(revision 188104)
+++ gcc/testsuite/g++.dg/ext/vla5.C	(working copy)
@@ -6,5 +6,5 @@
 void
 test (int a)
 {
-  new (char[a]);
+  new (char[a]); // { dg-warning "variable array length" }
 }
Index: gcc/testsuite/g++.dg/ext/vla8.C
===================================================================
--- gcc/testsuite/g++.dg/ext/vla8.C	(revision 188104)
+++ gcc/testsuite/g++.dg/ext/vla8.C	(working copy)
@@ -8,7 +8,7 @@
 
   AvlTreeIter()
   {
-    new (void* [Num()]);
+    new (void* [Num()]); // { dg-warning "variable array length" }
   }
 };
 
Index: gcc/testsuite/g++.dg/init/new35.C
===================================================================
--- gcc/testsuite/g++.dg/init/new35.C	(revision 0)
+++ gcc/testsuite/g++.dg/init/new35.C	(revision 0)
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-Wno-vla" }
+
+int
+main (int argc, char **argv)
+{
+  typedef char A[argc];
+  new A;
+  new A[0]; // { dg-error "variably modified" }
+  new A[5]; // { dg-error "variably modified" }
+  new (A[0]); // { dg-error "variably modified" }
+  new (A[5]); // { dg-error "variably modified" }
+}
Index: gcc/testsuite/g++.dg/init/new36.C
===================================================================
--- gcc/testsuite/g++.dg/init/new36.C	(revision 0)
+++ gcc/testsuite/g++.dg/init/new36.C	(revision 0)
@@ -0,0 +1,153 @@
+// Testcase for invocation of constructors/destructors in operator new[].
+// { dg-do run }
+
+#include <stdlib.h>
+
+struct E {
+  virtual ~E() { }
+};
+
+struct S {
+  S();
+  ~S();
+};
+
+static int count;
+static int max;
+static int throwAfter = -1;
+static S *pS;
+
+S::S()
+{
+  if (throwAfter >= 0 && count >= throwAfter)
+    throw E();
+  if (pS)
+    {
+      ++pS;
+      if (this != pS)
+	abort();
+    }
+  else
+    pS = this;
+  ++count;
+  max = count;
+}
+
+S::~S()
+{
+  if (count > 1)
+    {
+      if (this != pS)
+	abort();
+      --pS;
+    }
+  else
+    pS = 0;
+  --count;
+}
+
+void __attribute__((noinline)) doit(int n)
+{
+  {
+    S *s = new S[n];
+    if (count != n)
+      abort();
+    if (pS != s + n - 1)
+      abort();
+    delete [] s;
+    if (count != 0)
+      abort();
+  }
+  throwAfter = 2;
+  max = 0;
+  try
+    {
+      new S[n];
+      abort();
+    }
+  catch (E)
+    {
+      if (max != 2)
+	abort();
+    }
+  throwAfter = -1;
+}
+
+int main()
+{
+  {
+    S s;
+    if (count != 1)
+      abort();
+    if (pS != &s)
+      abort();
+  }
+  if (count != 0)
+    abort();
+  {
+    S *s = new S;
+    if (count != 1)
+      abort();
+    if (pS != s)
+      abort();
+    delete s;
+    if (count != 0)
+      abort();
+  }
+  {
+    S *s = new S[1];
+    if (count != 1)
+      abort();
+    if (pS != s)
+      abort();
+    delete [] s;
+    if (count != 0)
+      abort();
+  }
+  {
+    S *s = new S[5];
+    if (count != 5)
+      abort();
+    if (pS != s + 4)
+      abort();
+    delete [] s;
+    if (count != 0)
+      abort();
+  }
+  typedef S A[5];
+  {
+    S *s = new A;
+    if (count != 5)
+      abort();
+    if (pS != s + 4)
+      abort();
+    delete [] s;
+    if (count != 0)
+      abort();
+  }
+  throwAfter = 2;
+  max = 0;
+  try
+    {
+      new S[5];
+      abort();
+    }
+  catch (E)
+    {
+      if (max != 2)
+	abort();
+    }
+  max = 0;
+  try
+    {
+      new A;
+      abort();
+    }
+  catch (E)
+    {
+      if (max != 2)
+	abort();
+    }
+  throwAfter = -1;
+  doit(5);
+}
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 188104)
+++ gcc/cp/init.c	(working copy)
@@ -2805,6 +2805,34 @@
       make_args_non_dependent (*init);
     }
 
+  /* If the type is variably modified (a GNU extension for C
+     compatibility), we could end up with a variable-times-variable
+     multiplication at run time, complicating overflow checking.  */
+  if (variably_modified_type_p (type, NULL_TREE))
+    {
+      /* Try to transform new (T[n]) to new T[n], and accept the
+	 result if T is not variably modified. */
+      bool good = false;
+      if (nelts == NULL_TREE && TREE_CODE (type) == ARRAY_TYPE)
+	{
+	  tree inner_type = TREE_TYPE (type);
+	  if (!variably_modified_type_p (inner_type, NULL_TREE))
+	    {
+	      pedwarn (input_location, OPT_Wvla,
+		       "ISO C++ forbids variable array length in parenthesized type-id");
+	      nelts = array_type_nelts_top (type);
+	      type = inner_type;
+	      good = true;
+	    }
+	}
+      if (!good)
+	{
+	  if (complain & tf_error)
+	    error ("new cannot be applied to a variably modified type");
+	  return error_mark_node;
+	}
+    }
+
   if (nelts)
     {
       if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false))
