diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f3761581b718..78017c3ba5a0 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,23 @@
+2003-02-03  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/7129
+	* call.c (z_candidate): Add args.
+	(convert_class_to_reference): Set it.
+	(implicit_conversion): Tidy.
+	(add_candidate): Add args parameter.
+	(add_function_candidate): Adjust call to add_candidate.
+	(add_conv_candidate): Likewise.
+	(build_builtin_candidate): Likewise.
+	(build_user_type_conversion_1): Eliminate wasteful tree_cons
+	usage.
+	(build_new_function_call): Likewise.
+	(build_object_call): Likewise.
+	(add_candidates): New function.
+	(build_new_op): Use it.
+	(covert_like_real): Adjust call to build_over_call.
+	(build_over_call): Remove args parameter.
+	* operators.def: Add <?= and >?=.
+
 2003-02-01  Richard Sandiford  <rsandifo@redhat.com>
 
 	* typeck.c (build_indirect_ref): Don't check flag_volatile.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 440d58a0a22e..5a2f8f18a7dc 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -44,7 +44,7 @@ static struct z_candidate * tourney (struct z_candidate *);
 static int equal_functions (tree, tree);
 static int joust (struct z_candidate *, struct z_candidate *, bool);
 static int compare_ics (tree, tree);
-static tree build_over_call (struct z_candidate *, tree, int);
+static tree build_over_call (struct z_candidate *, int);
 static tree build_java_interface_fn_ref (tree, tree);
 #define convert_like(CONV, EXPR) \
   convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0)
@@ -92,7 +92,7 @@ static bool is_subseq (tree, tree);
 static tree maybe_handle_ref_bind (tree *);
 static void maybe_handle_implicit_object (tree *);
 static struct z_candidate *add_candidate 
-        (struct z_candidate *, tree, tree, tree, tree, int);
+        (struct z_candidate *, tree, tree, tree, tree, tree, int);
 static tree source_type (tree);
 static void add_warning (struct z_candidate *, struct z_candidate *);
 static bool reference_related_p (tree, tree);
@@ -104,6 +104,8 @@ static tree conditional_conversion (tree, tree);
 static char *name_as_c_string (tree, tree, bool *);
 static tree call_builtin_trap (void);
 static tree prep_operand (tree);
+static struct z_candidate *add_candidates (tree, tree, tree, tree,
+					   int, struct z_candidate *);
 
 tree
 build_vfield_ref (tree datum, tree type)
@@ -556,6 +558,8 @@ struct z_candidate GTY(()) {
   /* The FUNCTION_DECL that will be called if this candidate is
      selected by overload resolution.  */
   tree fn;
+  /* The arguments to use when calling this function.  */
+  tree args;
   tree convs;
   tree second_conv;
   int viable;
@@ -1034,6 +1038,12 @@ convert_class_to_reference (tree t, tree s, tree expr)
   if (!cand)
     return NULL_TREE;
 
+  /* Now that we know that this is the function we're going to use fix
+     the dummy first argument.  */
+  cand->args = tree_cons (NULL_TREE,
+			  build_this (expr),
+			  TREE_CHAIN (cand->args));
+
   conv = build1 (IDENTITY_CONV, s, expr);
   conv = build_conv (USER_CONV, TREE_TYPE (TREE_TYPE (cand->fn)),
 		     conv);
@@ -1269,11 +1279,12 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
     conv = standard_conversion (to, from, expr);
 
   if (conv)
-    ;
-  else if (expr != NULL_TREE
-	   && (IS_AGGR_TYPE (from)
-	       || IS_AGGR_TYPE (to))
-	   && (flags & LOOKUP_NO_CONVERSION) == 0)
+    return conv;
+
+  if (expr != NULL_TREE
+      && (IS_AGGR_TYPE (from)
+	  || IS_AGGR_TYPE (to))
+      && (flags & LOOKUP_NO_CONVERSION) == 0)
     {
       cand = build_user_type_conversion_1
 	(to, expr, LOOKUP_ONLYCONVERTING);
@@ -1283,9 +1294,10 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
       /* We used to try to bind a reference to a temporary here, but that
 	 is now handled by the recursive call to this function at the end
 	 of reference_binding.  */
+      return conv;
     }
 
-  return conv;
+  return NULL_TREE;
 }
 
 /* Add a new entry to the list of candidates.  Used by the add_*_candidate
@@ -1293,13 +1305,14 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
 
 static struct z_candidate *
 add_candidate (struct z_candidate *candidates, 
-	       tree fn, tree convs, tree access_path, tree
-	       conversion_path, int viable)
+	       tree fn, tree args, tree convs, tree access_path, 
+	       tree conversion_path, int viable)
 {
   struct z_candidate *cand
     = (struct z_candidate *) ggc_alloc_cleared (sizeof (struct z_candidate));
 
   cand->fn = fn;
+  cand->args = args;
   cand->convs = convs;
   cand->access_path = access_path;
   cand->conversion_path = conversion_path;
@@ -1326,6 +1339,7 @@ add_function_candidate (struct z_candidate *candidates,
   int i, len;
   tree convs;
   tree parmnode, argnode;
+  tree orig_arglist;
   int viable = 1;
 
   /* The `this', `in_chrg' and VTT arguments to constructors are not
@@ -1333,8 +1347,11 @@ add_function_candidate (struct z_candidate *candidates,
   if (DECL_CONSTRUCTOR_P (fn))
     {
       parmlist = skip_artificial_parms_for (fn, parmlist);
+      orig_arglist = arglist;
       arglist = skip_artificial_parms_for (fn, arglist);
     }
+  else 
+    orig_arglist = arglist;
 
   len = list_length (arglist);
   convs = make_tree_vec (len);
@@ -1432,7 +1449,7 @@ add_function_candidate (struct z_candidate *candidates,
     }
 
  out:
-  return add_candidate (candidates, fn, convs, access_path,
+  return add_candidate (candidates, fn, orig_arglist, convs, access_path,
 			conversion_path, viable);
 }
 
@@ -1509,7 +1526,7 @@ add_conv_candidate (struct z_candidate *candidates, tree fn, tree obj,
   if (!sufficient_parms_p (parmnode))
     viable = 0;
 
-  return add_candidate (candidates, totype, convs, access_path,
+  return add_candidate (candidates, totype, arglist, convs, access_path,
 			conversion_path, viable);
 }
 
@@ -1556,7 +1573,7 @@ build_builtin_candidate (struct z_candidate *candidates, tree fnname,
 	viable = 0;
     }      
 
-  return add_candidate (candidates, fnname, convs, 
+  return add_candidate (candidates, fnname, /*args=*/NULL_TREE, convs, 
 			/*access_path=*/NULL_TREE,
 			/*conversion_path=*/NULL_TREE,
 			viable);
@@ -2396,7 +2413,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
   tree fromtype = TREE_TYPE (expr);
   tree ctors = NULL_TREE, convs = NULL_TREE, *p;
   tree args = NULL_TREE;
-  tree templates = NULL_TREE;
 
   /* We represent conversion within a hierarchy using RVALUE_CONV and
      BASE_CONV, as specified by [over.best.ics]; these become plain
@@ -2438,16 +2454,13 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	continue;
 
       if (TREE_CODE (ctor) == TEMPLATE_DECL) 
-	{
-	  templates = tree_cons (NULL_TREE, ctor, templates);
-	  candidates = 
-	    add_template_candidate (candidates, ctor, totype,
-				    NULL_TREE, args, NULL_TREE, 
-				    TYPE_BINFO (totype),
-				    TYPE_BINFO (totype),
-				    flags,
-				    DEDUCE_CALL);
-	}
+	candidates = 
+	  add_template_candidate (candidates, ctor, totype,
+				  NULL_TREE, args, NULL_TREE, 
+				  TYPE_BINFO (totype),
+				  TYPE_BINFO (totype),
+				  flags,
+				  DEDUCE_CALL);
       else 
 	candidates = add_function_candidate (candidates, ctor, totype,
 					     args, TYPE_BINFO (totype), 
@@ -2487,15 +2500,12 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	     So we pass fromtype as CTYPE to add_*_candidate.  */
 
 	  if (TREE_CODE (fn) == TEMPLATE_DECL)
-	    {
-	      templates = tree_cons (NULL_TREE, fn, templates);
-	      candidates = 
-		add_template_candidate (candidates, fn, fromtype, NULL_TREE,
-					args, totype, TYPE_BINFO (fromtype), 
-					conversion_path,
-					flags,
-					DEDUCE_CONV);
-	    } 
+	    candidates = 
+	      add_template_candidate (candidates, fn, fromtype, NULL_TREE,
+				      args, totype, TYPE_BINFO (fromtype), 
+				      conversion_path,
+				      flags,
+				      DEDUCE_CONV);
 	  else 
 	    candidates = add_function_candidate (candidates, fn, fromtype,
 						 args,
@@ -2695,7 +2705,6 @@ build_new_function_call (tree fn, tree args)
       || TREE_CODE (fn) == TEMPLATE_DECL)
     {
       tree t1;
-      tree templates = NULL_TREE;
 
       args = resolve_args (args);
 
@@ -2709,14 +2718,11 @@ build_new_function_call (tree fn, tree args)
 	  my_friendly_assert (!DECL_FUNCTION_MEMBER_P (t), 20020913);
 
 	  if (TREE_CODE (t) == TEMPLATE_DECL)
-	    {
-	      templates = tree_cons (NULL_TREE, t, templates);
-	      candidates = add_template_candidate
-		(candidates, t, NULL_TREE, explicit_targs, args, 
-		 NULL_TREE, /*access_path=*/NULL_TREE, 
-		 /*conversion_path=*/NULL_TREE,
-		 LOOKUP_NORMAL, DEDUCE_CALL);  
-	    }
+	    candidates = add_template_candidate
+	      (candidates, t, NULL_TREE, explicit_targs, args, 
+	       NULL_TREE, /*access_path=*/NULL_TREE, 
+	       /*conversion_path=*/NULL_TREE,
+	       LOOKUP_NORMAL, DEDUCE_CALL);  
 	  else if (! template_only)
 	    candidates = add_function_candidate
 	      (candidates, t, NULL_TREE, args, 
@@ -2745,7 +2751,7 @@ build_new_function_call (tree fn, tree args)
 	  return error_mark_node;
 	}
 
-      return build_over_call (cand, args, LOOKUP_NORMAL);
+      return build_over_call (cand, LOOKUP_NORMAL);
     }
 
   /* This is not really overloaded.  */
@@ -2787,14 +2793,12 @@ build_object_call (tree obj, tree args)
 	{
 	  tree fn = OVL_CURRENT (fns);
 	  if (TREE_CODE (fn) == TEMPLATE_DECL)
-	    {
-	      candidates 
-		= add_template_candidate (candidates, fn, base, NULL_TREE,
-					  mem_args, NULL_TREE, 
-					  TYPE_BINFO (type),
-					  TYPE_BINFO (type),
-					  LOOKUP_NORMAL, DEDUCE_CALL);
-	    }
+	    candidates 
+	      = add_template_candidate (candidates, fn, base, NULL_TREE,
+					mem_args, NULL_TREE, 
+					TYPE_BINFO (type),
+					TYPE_BINFO (type),
+					LOOKUP_NORMAL, DEDUCE_CALL);
 	  else
 	    candidates = add_function_candidate
 	      (candidates, fn, base, mem_args, TYPE_BINFO (type),
@@ -2855,7 +2859,7 @@ build_object_call (tree obj, tree args)
      DECL_NAME here.  */
   if (TREE_CODE (cand->fn) == FUNCTION_DECL
       && DECL_OVERLOADED_OPERATOR_P (cand->fn) == CALL_EXPR)
-    return build_over_call (cand, mem_args, LOOKUP_NORMAL);
+    return build_over_call (cand, LOOKUP_NORMAL);
 
   obj = convert_like_with_context
           (TREE_VEC_ELT (cand->convs, 0), obj, cand->fn, -1);
@@ -3317,13 +3321,78 @@ prep_operand (tree operand)
   return operand;
 }
 
+/* Add each of the viable functions in FNS (a FUNCTION_DECL or
+   OVERLOAD) to the CANDIDATES, returning an updated list of
+   CANDIDATES.  The ARGS are the arguments provided to the call,
+   without any implicit object parameter.  CONVERSION_PATH,
+   ACCESS_PATH, and FLAGS are as for add_function_candidate.  */
+
+static struct z_candidate *
+add_candidates (tree fns, tree args,
+		tree conversion_path, tree access_path,
+		int flags,
+		struct z_candidate *candidates)
+{
+  tree ctype;
+  tree non_static_args;
+
+  ctype = conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE;
+  /* Delay creating the implicit this parameter until it is needed.  */
+  non_static_args = NULL_TREE;
+
+  while (fns) 
+    {
+      tree fn;
+      tree fn_args;
+
+      fn = OVL_CURRENT (fns);
+      /* Figure out which set of arguments to use.  */
+      if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+	{
+	  /* If this function is a non-static member, prepend the implicit
+	     object parameter.  */
+	  if (!non_static_args)
+	    non_static_args = tree_cons (NULL_TREE,
+					 build_this (TREE_VALUE (args)),
+					 TREE_CHAIN (args));
+	  fn_args = non_static_args;
+	}
+      else
+	/* Otherwise, just use the list of arguments provided.  */
+	fn_args = args;
+
+      if (TREE_CODE (fn) == TEMPLATE_DECL)
+	candidates = add_template_candidate (candidates, 
+					     fn, 
+					     ctype,
+					     NULL_TREE,
+					     fn_args,
+					     NULL_TREE,
+					     access_path,
+					     conversion_path,
+					     flags,
+					     DEDUCE_CALL);
+      else
+	candidates = add_function_candidate (candidates,
+					     fn,
+					     ctype,
+					     fn_args,
+					     access_path,
+					     conversion_path,
+					     flags);
+      fns = OVL_NEXT (fns);
+    }
+
+  return candidates;
+}
+
 tree
 build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
 {
   struct z_candidate *candidates = 0, *cand;
-  tree fns, mem_arglist = NULL_TREE, arglist, fnname;
+  tree arglist, fnname;
+  tree args[3];
   enum tree_code code2 = NOP_EXPR;
-  tree templates = NULL_TREE;
   tree conv;
   bool viable_candidates;
 
@@ -3385,98 +3454,45 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
     arglist = tree_cons (NULL_TREE, arg2, arglist);
   arglist = tree_cons (NULL_TREE, arg1, arglist);
 
-  fns = lookup_function_nonclass (fnname, arglist);
-
-  if (fns && TREE_CODE (fns) == TREE_LIST)
-    fns = TREE_VALUE (fns);
-  for (; fns; fns = OVL_NEXT (fns))
+  /* Add namespace-scope operators to the list of functions to
+     consider.  */
+  candidates = add_candidates (lookup_function_nonclass (fnname, arglist),
+			       arglist, NULL_TREE, NULL_TREE,
+			       flags, candidates);
+  /* Add class-member operators to the candidate set.  */
+  if (CLASS_TYPE_P (TREE_TYPE (arg1)))
     {
-      tree fn = OVL_CURRENT (fns);
-      if (TREE_CODE (fn) == TEMPLATE_DECL)
-	{
-	  templates = tree_cons (NULL_TREE, fn, templates);
-	  candidates 
-	    = add_template_candidate (candidates, fn, NULL_TREE, NULL_TREE,
-				      arglist, TREE_TYPE (fnname),
-				      /*access_path=*/NULL_TREE,
-				      /*conversion_path=*/NULL_TREE,
-				      flags, DEDUCE_CALL); 
-	}
-      else
-	candidates = add_function_candidate (candidates, fn, NULL_TREE,
-					     arglist,
-					     /*access_path=*/NULL_TREE,
-					     /*conversion_path=*/NULL_TREE,
-					     flags);
-    }
+      tree fns;
 
-  if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
-    {
       fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 1);
       if (fns == error_mark_node)
 	return fns;
+      if (fns)
+	candidates = add_candidates (BASELINK_FUNCTIONS (fns), arglist, 
+				     BASELINK_BINFO (fns),
+				     TYPE_BINFO (TREE_TYPE (arg1)),
+				     flags, candidates);
+    }
+
+  /* Rearrange the arguments for ?: so that add_builtin_candidate only has
+     to know about two args; a builtin candidate will always have a first
+     parameter of type bool.  We'll handle that in
+     build_builtin_candidate.  */
+  if (code == COND_EXPR)
+    {
+      args[0] = arg2;
+      args[1] = arg3;
+      args[2] = arg1;
     }
   else
-    fns = NULL_TREE;
-
-  if (fns)
     {
-      tree conversion_path = BASELINK_BINFO (fns);
-
-      mem_arglist = tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
-      for (fns = BASELINK_FUNCTIONS (fns); fns; fns = OVL_NEXT (fns))
-	{
-	  tree fn = OVL_CURRENT (fns);
-	  tree this_arglist;
-	  tree access_path = TYPE_BINFO (TREE_TYPE (arg1));
-
-	  if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
-	    this_arglist = mem_arglist;
-	  else
-	    this_arglist = arglist;
-
-	  if (TREE_CODE (fn) == TEMPLATE_DECL)
-	    {
-	      /* A member template.  */
-	      templates = tree_cons (NULL_TREE, fn, templates);
-	      candidates 
-		= add_template_candidate (candidates, fn, 
-					  BINFO_TYPE (conversion_path),
-					  NULL_TREE,
-					  this_arglist,  TREE_TYPE (fnname),
-					  access_path, conversion_path,
-					  flags, DEDUCE_CALL); 
-	    }
-	  else
-	    candidates = add_function_candidate
-	      (candidates, fn, BINFO_TYPE (conversion_path), this_arglist, 
-	       access_path, conversion_path, flags);
-	}
+      args[0] = arg1;
+      args[1] = arg2;
+      args[2] = NULL_TREE;
     }
 
-  {
-    tree args[3];
-
-    /* Rearrange the arguments for ?: so that add_builtin_candidate only has
-       to know about two args; a builtin candidate will always have a first
-       parameter of type bool.  We'll handle that in
-       build_builtin_candidate.  */
-    if (code == COND_EXPR)
-      {
-	args[0] = arg2;
-	args[1] = arg3;
-	args[2] = arg1;
-      }
-    else
-      {
-	args[0] = arg1;
-	args[1] = arg2;
-	args[2] = NULL_TREE;
-      }
-
-    candidates = add_builtin_candidates
-      (candidates, code, code2, fnname, args, flags);
-  }
+  candidates = add_builtin_candidates
+    (candidates, code, code2, fnname, args, flags);
 
   switch (code)
     {
@@ -3559,11 +3575,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
 			 : candidates->fn);
 	}
 
-      return build_over_call
-	(cand,
-	 TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
-	 ? mem_arglist : arglist,
-	 LOOKUP_NORMAL);
+      return build_over_call (cand, LOOKUP_NORMAL);
     }
 
   /* Check for comparison of different enum types.  */
@@ -3907,7 +3919,7 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
 	  }
 	else
 	  args = build_this (expr);
-	expr = build_over_call (cand, args, LOOKUP_NORMAL);
+	expr = build_over_call (cand, LOOKUP_NORMAL);
 
 	/* If this is a constructor or a function returning an aggr type,
 	   we need to build up a TARGET_EXPR.  */
@@ -4238,9 +4250,10 @@ convert_for_arg_passing (tree type, tree val)
    bitmask of various LOOKUP_* flags which apply to the call itself.  */
 
 static tree
-build_over_call (struct z_candidate *cand, tree args, int flags)
+build_over_call (struct z_candidate *cand, int flags)
 {
   tree fn = cand->fn;
+  tree args = cand->args;
   tree convs = cand->convs;
   tree converted_args = NULL_TREE;
   tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
@@ -4702,7 +4715,6 @@ build_new_method_call (tree instance, tree fns, tree args,
   tree mem_args = NULL_TREE, instance_ptr;
   tree name;
   tree user_args;
-  tree templates = NULL_TREE;
   tree call;
   tree fn;
   tree class_type;
@@ -4807,7 +4819,6 @@ build_new_method_call (tree instance, tree fns, tree args,
       if (TREE_CODE (t) == TEMPLATE_DECL)
 	{
 	  /* A member template.  */
-	  templates = tree_cons (NULL_TREE, t, templates);
 	  candidates = 
 	    add_template_candidate (candidates, t, 
 				    class_type,
@@ -4888,10 +4899,10 @@ build_new_method_call (tree instance, tree fns, tree args,
     flags |= LOOKUP_NONVIRTUAL;
 
   if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE)
-    call = build_over_call (cand, mem_args, flags);
+    call = build_over_call (cand, flags);
   else
     {
-      call = build_over_call (cand, args, flags);
+      call = build_over_call (cand, flags);
       /* In an expression of the form `a->f()' where `f' turns out to
 	 be a static member function, `a' is none-the-less evaluated.  */
       if (!is_dummy_object (instance_ptr) && TREE_SIDE_EFFECTS (instance))
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d5896ab1856a..98e317409287 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -5,7 +5,7 @@
    non-overloadable operators (like the `?:' ternary operator).  
    Written by Mark Mitchell <mark@codesourcery.com>
 
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA.  */
      assignment operators, the same tree-codes are reused; i.e.,
      `operator +' will also have PLUS_EXPR as its CODE.
 
-   NEW_MANGLING
+   MANGLING
 
      The mangling prefix for the operator, as a C string, and as
      mangled under the new ABI.  For `operator +', for example, this
@@ -127,7 +127,7 @@ DEF_SIMPLE_OPERATOR ("->", COMPONENT_REF, "pt", 2)
 DEF_SIMPLE_OPERATOR ("[]", ARRAY_REF, "ix", 2)
 DEF_SIMPLE_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", 2)
 DEF_SIMPLE_OPERATOR ("--", POSTDECREMENT_EXPR, "mm", 2)
-/* These are extensions.  */
+/* These operators are GNU extensions.  */
 DEF_SIMPLE_OPERATOR ("<?", MIN_EXPR, "v23min", 2)
 DEF_SIMPLE_OPERATOR (">?", MAX_EXPR, "v23max", 2)
 /* This one is needed for mangling.  */
@@ -145,6 +145,9 @@ DEF_ASSN_OPERATOR ("|=", BIT_IOR_EXPR, "oR", 2)
 DEF_ASSN_OPERATOR ("^=", BIT_XOR_EXPR, "eO", 2)
 DEF_ASSN_OPERATOR ("<<=", LSHIFT_EXPR, "lS", 2)
 DEF_ASSN_OPERATOR (">>=", RSHIFT_EXPR, "rS", 2)
+/* These operators are GNU extensions.  */
+DEF_ASSN_OPERATOR ("<?=", MIN_EXPR, "v23miN", 2);
+DEF_ASSN_OPERATOR (">?=", MAX_EXPR, "v23maX", 2);
 
 /* Ternary operators.  */
 DEF_SIMPLE_OPERATOR ("?:", COND_EXPR, "qu", 3)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3287f358a345..6ed5733aa212 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2003-02-03  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/7129
+	* testsuite/g++.dg/ext/max.C: New test.
+
 Mon Feb  3 16:05:11 CET 2003  Jan Hubicka  <jh@suse.cz>
 
 	* gcc.c-torture/execute/20030203-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/ext/max.C b/gcc/testsuite/g++.dg/ext/max.C
new file mode 100644
index 000000000000..bc65f1f70279
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/max.C
@@ -0,0 +1,6 @@
+struct s_t { 
+};
+void foo(void) {
+  s_t s; int i;
+  s<?=i; // { dg-error "" }
+}