diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index c9a4f7decd5eca3e2447b9c7ccd1d167cfd38bbc..74228782f576b1d4eb96885dc7ad9cceffafbe55 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,13 @@
+2004-05-25  Roger Sayle  <roger@eyesopen.com>
+
+	PR fortran/13912
+	* matchexp.c: Allow unary operators after arithmetic operators
+	as a GNU extension.
+	(match_ext_mult_operand, match_ext_add_operand): New functions.
+	(match_mult_operand): Tweak to call match_ext_mult_operand.
+	(match_add_operand): Tweak to call match_ext_mult_operand.
+	(match_level_2): Rearrange to call match_ext_add_operand.
+
 2004-05-25  Paul Brook  <paul@codesourcery.com>
 
 	* expr.c (check_inquiry): Remove bogus tests.
diff --git a/gcc/fortran/matchexp.c b/gcc/fortran/matchexp.c
index f0c227f95b8ac779121e5f6d59a959b53486424b..539a91a31c185cdbc3552f03c5fd1cd3f184c8d0 100644
--- a/gcc/fortran/matchexp.c
+++ b/gcc/fortran/matchexp.c
@@ -222,6 +222,38 @@ match_level_1 (gfc_expr ** result)
 }
 
 
+/* As a GNU extension we support an expanded level-2 expression syntax.
+   Via this extension we support (arbitrary) nesting of unary plus and
+   minus operations following unary and binary operators, such as **.
+   The grammar of section 7.1.1.3 is effectively rewitten as:
+
+	R704  mult-operand     is level-1-expr [ power-op ext-mult-operand ]
+	R704' ext-mult-operand is add-op ext-mult-operand
+			       or mult-operand
+	R705  add-operand      is add-operand mult-op ext-mult-operand
+			       or mult-operand
+	R705' ext-add-operand  is add-op ext-add-operand
+			       or add-operand
+	R706  level-2-expr     is [ level-2-expr ] add-op ext-add-operand
+			       or add-operand
+ */
+
+static match match_ext_mult_operand (gfc_expr ** result);
+static match match_ext_add_operand (gfc_expr ** result);
+
+
+static int
+match_add_op (void)
+{
+
+  if (next_operator (INTRINSIC_MINUS))
+    return -1;
+  if (next_operator (INTRINSIC_PLUS))
+    return 1;
+  return 0;
+}
+
+
 static match
 match_mult_operand (gfc_expr ** result)
 {
@@ -241,7 +273,7 @@ match_mult_operand (gfc_expr ** result)
 
   where = *gfc_current_locus ();
 
-  m = match_mult_operand (&exp);
+  m = match_ext_mult_operand (&exp);
   if (m == MATCH_NO)
     gfc_error ("Expected exponent in expression at %C");
   if (m != MATCH_YES)
@@ -265,6 +297,46 @@ match_mult_operand (gfc_expr ** result)
 }
 
 
+static match
+match_ext_mult_operand (gfc_expr ** result)
+{
+  gfc_expr *all, *e;
+  locus where;
+  match m;
+  int i;
+
+  where = *gfc_current_locus ();
+  i = match_add_op ();
+
+  if (i == 0)
+    return match_mult_operand (result);
+
+  if (gfc_notify_std (GFC_STD_GNU, "Extension: Unary operator following"
+		      " arithmetic operator (use parentheses) at %C")
+      == FAILURE)
+    return MATCH_ERROR;
+
+  m = match_ext_mult_operand (&e);
+  if (m != MATCH_YES)
+    return m;
+
+  if (i == -1)
+    all = gfc_uminus (e);
+  else
+    all = gfc_uplus (e);
+
+  if (all == NULL)
+    {
+      gfc_free_expr (e);
+      return MATCH_ERROR;
+    }
+
+  all->where = where;
+  *result = all;
+  return MATCH_YES;
+}
+
+
 static match
 match_add_operand (gfc_expr ** result)
 {
@@ -295,7 +367,7 @@ match_add_operand (gfc_expr ** result)
 
       where = *gfc_current_locus ();
 
-      m = match_mult_operand (&e);
+      m = match_ext_mult_operand (&e);
       if (m == MATCH_NO)
 	{
 	  gfc_set_locus (&old_loc);
@@ -329,15 +401,43 @@ match_add_operand (gfc_expr ** result)
 }
 
 
-static int
-match_add_op (void)
+static match
+match_ext_add_operand (gfc_expr ** result)
 {
+  gfc_expr *all, *e;
+  locus where;
+  match m;
+  int i;
 
-  if (next_operator (INTRINSIC_MINUS))
-    return -1;
-  if (next_operator (INTRINSIC_PLUS))
-    return 1;
-  return 0;
+  where = *gfc_current_locus ();
+  i = match_add_op ();
+
+  if (i == 0)
+    return match_add_operand (result);
+
+  if (gfc_notify_std (GFC_STD_GNU, "Extension: Unary operator following"
+		      " arithmetic operator (use parentheses) at %C")
+      == FAILURE)
+    return MATCH_ERROR;
+
+  m = match_ext_add_operand (&e);
+  if (m != MATCH_YES)
+    return m;
+
+  if (i == -1)
+    all = gfc_uminus (e);
+  else
+    all = gfc_uplus (e);
+
+  if (all == NULL)
+    {
+      gfc_free_expr (e);
+      return MATCH_ERROR;
+    }
+
+  all->where = where;
+  *result = all;
+  return MATCH_YES;
 }
 
 
@@ -354,12 +454,17 @@ match_level_2 (gfc_expr ** result)
   where = *gfc_current_locus ();
   i = match_add_op ();
 
-  m = match_add_operand (&e);
-  if (i != 0 && m == MATCH_NO)
+  if (i != 0)
     {
-      gfc_error (expression_syntax);
-      m = MATCH_ERROR;
+      m = match_ext_add_operand (&e);
+      if (m == MATCH_NO)
+	{
+	  gfc_error (expression_syntax);
+	  m = MATCH_ERROR;
+	}
     }
+  else
+    m = match_add_operand (&e);
 
   if (m != MATCH_YES)
     return m;
@@ -391,7 +496,7 @@ match_level_2 (gfc_expr ** result)
       if (i == 0)
 	break;
 
-      m = match_add_operand (&e);
+      m = match_ext_add_operand (&e);
       if (m == MATCH_NO)
 	gfc_error (expression_syntax);
       if (m != MATCH_YES)