diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index cd1af6f8a9153b05ad0d11e3b005261ca2e794ec..60d2fb29868acf3b54a8cf4bc5b8292f27b91093 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+2006-09-06  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/28903
+	* pt.c (tsubst): Use fold_non_dependent_expr to fold array
+	dimensions.
+
+	PR c++/28886
+	* pt.c (unify): Avoid unnecessary calls to fold_build2 for array
+	dimensions.
+
 2006-09-06  Jason Merrill  <jason@redhat.com>
 
 	PR c++/26696
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d278b00448ee07d8d97bcefeaef89bf947f10945..715b9461aba4bf8d4e79e032522cfe833639938d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7216,9 +7216,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       {
 	tree max, omax = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
 
-	/* The array dimension behaves like a non-type template arg,
-	   in that we want to fold it as much as possible.  */
-	max = tsubst_template_arg (omax, args, complain, in_decl);
+	max = tsubst_expr (omax, args, complain, in_decl,
+			   /*integral_constant_expression_p=*/false);
+	max = fold_non_dependent_expr (max);
 	max = fold_decl_constant_value (max);
 
 	if (TREE_CODE (max) != INTEGER_CST 
@@ -10618,21 +10618,56 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	{
 	  tree parm_max;
 	  tree arg_max;
-
-	  parm_max = TYPE_MAX_VALUE (TYPE_DOMAIN (parm));
-	  arg_max = TYPE_MAX_VALUE (TYPE_DOMAIN (arg));
+	  bool parm_cst;
+	  bool arg_cst;
 
 	  /* Our representation of array types uses "N - 1" as the
 	     TYPE_MAX_VALUE for an array with "N" elements, if "N" is
-	     not an integer constant.  */
-	  if (TREE_CODE (parm_max) == MINUS_EXPR)
+	     not an integer constant.  We cannot unify arbitrarily
+	     complex expressions, so we eliminate the MINUS_EXPRs
+	     here.  */
+	  parm_max = TYPE_MAX_VALUE (TYPE_DOMAIN (parm));
+	  parm_cst = TREE_CODE (parm_max) == INTEGER_CST;
+	  if (!parm_cst)
 	    {
-	      arg_max = fold_build2 (PLUS_EXPR,
-				     integer_type_node,
-				     arg_max,
-				     TREE_OPERAND (parm_max, 1));
+	      gcc_assert (TREE_CODE (parm_max) == MINUS_EXPR);
 	      parm_max = TREE_OPERAND (parm_max, 0);
 	    }
+	  arg_max = TYPE_MAX_VALUE (TYPE_DOMAIN (arg));
+	  arg_cst = TREE_CODE (arg_max) == INTEGER_CST;
+	  if (!arg_cst)
+	    {
+	      /* The ARG_MAX may not be a simple MINUS_EXPR, if we are
+		 trying to unify the type of a variable with the type
+		 of a template parameter.  For example:
+
+                   template <unsigned int N>
+		   void f (char (&) [N]);
+		   int g(); 
+		   void h(int i) {
+                     char a[g(i)];
+		     f(a); 
+                   }
+
+                Here, the type of the ARG will be "int [g(i)]", and
+                may be a SAVE_EXPR, etc.  */
+	      if (TREE_CODE (arg_max) != MINUS_EXPR)
+		return 1;
+	      arg_max = TREE_OPERAND (arg_max, 0);
+	    }
+
+	  /* If only one of the bounds used a MINUS_EXPR, compensate
+	     by adding one to the other bound.  */
+	  if (parm_cst && !arg_cst)
+	    parm_max = fold_build2 (PLUS_EXPR,
+				    integer_type_node,
+				    parm_max,
+				    integer_one_node);
+	  else if (arg_cst && !parm_cst)
+	    arg_max = fold_build2 (PLUS_EXPR,
+				   integer_type_node,
+				   arg_max,
+				   integer_one_node);
 
 	  if (unify (tparms, targs, parm_max, arg_max, UNIFY_ALLOW_INTEGER))
 	    return 1;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c15dda40f9c2914dd385f576fe7325bf45b57106..6e7bd99eee7740b554cce97862c6b49c322674d2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2006-09-06  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/28903
+	* g++.dg/ext/vla3.C: New test.
+
+	PR c++/28886
+	* g++.dg/template/array16.C: New test.
+
 2006-09-06  Richard Guenther  <rguenther@suse.de>
 
 	* gcc.dg/pr27226.c: Remove testcase again.
diff --git a/gcc/testsuite/g++.dg/ext/vla3.C b/gcc/testsuite/g++.dg/ext/vla3.C
new file mode 100644
index 0000000000000000000000000000000000000000..329cc7dde00c745a0aecdd0d8eb926076315dfb8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/vla3.C
@@ -0,0 +1,24 @@
+// PR c++/28903
+// { dg-options "" }
+
+template <class>
+struct View 
+{
+  int n;
+};
+template <class ViewA>
+struct ViewDom : View<ViewA>
+{
+  using View<ViewA>::n;
+  ViewDom();
+};
+template <class ViewA>
+ViewDom<ViewA>::ViewDom()
+{
+  char a[n];
+}
+void element( )
+{
+  ViewDom<int> a;
+}
+
diff --git a/gcc/testsuite/g++.dg/template/array16.C b/gcc/testsuite/g++.dg/template/array16.C
new file mode 100644
index 0000000000000000000000000000000000000000..c51441041b45e81c4b23cf9d4f86b7ad0f2d7603
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/array16.C
@@ -0,0 +1,9 @@
+// PR c++/28886
+
+template<typename> struct A;
+
+template<typename T, int N> struct A<T[N]> {};
+
+template<typename T, int N> struct A<const T[N]> {};
+
+A<const int[1]> a;