[C++ PATCH] overloaded operator fns [6/N]
authorNathan Sidwell <nathan@acm.org>
Wed, 1 Nov 2017 14:03:27 +0000 (14:03 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 1 Nov 2017 14:03:27 +0000 (14:03 +0000)
https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00018.html
* cp-tree.h (IDENTIFIER_CP_INDEX): Define.
(enum ovl_op_flags): Add OVL_OP_FLAG_AMBIARY.
(enum ovl_op_code): New.
(struct ovl_op_info): Add ovl_op_code field.
(ovl_op_info): Size by OVL_OP_MAX.
(ovl_op_mapping, ovl_op_alternate): Declare.
(OVL_OP_INFO): Adjust for mapping array.
(IDENTIFIER_OVL_OP_INFO): New.
* decl.c (ambi_op_p, unary_op_p): Delete.
(grok_op_properties): Use IDENTIFIER_OVL_OP_INFO and
ovl_op_alternate.
* lex.c (ovl_op_info): Adjust and static initialize.
(ovl_op_mappings, ovl_op_alternate): Define.
(init_operators): Iterate over ovl_op_info array and init mappings
& alternate arrays.
* mangle.c (write_unqualified_id): Use IDENTIFIER_OVL_OP_INFO.
* operators.def (DEF_OPERATOR): Remove KIND parm.
(DEF_SIMPLE_OPERATOR): Delete.
(OPERATOR_TRANSITION): Expand if defined.

From-SVN: r254310

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/lex.c
gcc/cp/mangle.c
gcc/cp/operators.def

index 00ac593..8f4cc99 100644 (file)
@@ -1,3 +1,25 @@
+2017-11-01  Nathan Sidwell  <nathan@acm.org>
+
+       * cp-tree.h (IDENTIFIER_CP_INDEX): Define.
+       (enum ovl_op_flags): Add OVL_OP_FLAG_AMBIARY.
+       (enum ovl_op_code): New.
+       (struct ovl_op_info): Add ovl_op_code field.
+       (ovl_op_info): Size by OVL_OP_MAX.
+       (ovl_op_mapping, ovl_op_alternate): Declare.
+       (OVL_OP_INFO): Adjust for mapping array.
+       (IDENTIFIER_OVL_OP_INFO): New.
+       * decl.c (ambi_op_p, unary_op_p): Delete.
+       (grok_op_properties): Use IDENTIFIER_OVL_OP_INFO and
+       ovl_op_alternate.
+       * lex.c (ovl_op_info): Adjust and static initialize.
+       (ovl_op_mappings, ovl_op_alternate): Define.
+       (init_operators): Iterate over ovl_op_info array and init mappings
+       & alternate arrays.
+       * mangle.c (write_unqualified_id): Use IDENTIFIER_OVL_OP_INFO.
+       * operators.def (DEF_OPERATOR): Remove KIND parm.
+       (DEF_SIMPLE_OPERATOR): Delete.
+       (OPERATOR_TRANSITION): Expand if defined.
+
 2017-10-31  David Malcolm  <dmalcolm@redhat.com>
 
        * pt.c (listify): Use %< and %> for description of #include.
index 257c877..76ee854 100644 (file)
@@ -1072,6 +1072,11 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_1 (NODE)              \
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
+/* Access a C++-specific index for identifier NODE.
+   Used to optimize operator mappings etc.  */
+#define IDENTIFIER_CP_INDEX(NODE)              \
+  (IDENTIFIER_NODE_CHECK(NODE)->base.u.bits.address_space)
+
 /* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only.  */
 #define C_TYPE_FIELDS_READONLY(TYPE) \
   (LANG_TYPE_CLASS_CHECK (TYPE)->fields_readonly)
@@ -5477,12 +5482,25 @@ extern void init_reswords (void);
 /* Various flags for the overloaded operator information.  */
 enum ovl_op_flags
   {
-    OVL_OP_FLAG_NONE = 0,
-    OVL_OP_FLAG_UNARY = 1,
-    OVL_OP_FLAG_BINARY = 2,
-    OVL_OP_FLAG_ALLOC = 4,     /* operator new or delete  */
-    OVL_OP_FLAG_DELETE = 1,    /* operator delete  */
-    OVL_OP_FLAG_VEC = 2                /* vector new or delete  */
+    OVL_OP_FLAG_NONE = 0,      /* Don't care.  */
+    OVL_OP_FLAG_UNARY = 1,     /* Is unary.  */
+    OVL_OP_FLAG_BINARY = 2,    /* Is binary.  */
+    OVL_OP_FLAG_AMBIARY = 3,   /* May be unary or binary.  */
+    OVL_OP_FLAG_ALLOC = 4,     /* operator new or delete.  */
+    OVL_OP_FLAG_DELETE = 1,    /* operator delete.  */
+    OVL_OP_FLAG_VEC = 2                /* vector new or delete.  */
+  };
+
+/* Compressed operator codes.  Order is determined by operators.def
+   and does not match that of tree_codes.  */
+enum ovl_op_code
+  {
+    OVL_OP_ERROR_MARK,
+    OVL_OP_NOP_EXPR,
+#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) OVL_OP_##CODE,
+#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) /* NOTHING */
+#include "operators.def"
+    OVL_OP_MAX
   };
 
 struct GTY(()) ovl_op_info_t {
@@ -5492,19 +5510,29 @@ struct GTY(()) ovl_op_info_t {
   const char *name;
   /* The mangled name of the operator.  */
   const char *mangled_name;
-  /* The tree code.  */
+  /* The (regular) tree code.  */
   enum tree_code tree_code : 16;
+  /* The (compressed) operator code.  */
+  enum ovl_op_code ovl_op_code : 8;
   /* The ovl_op_flags of the operator */
   unsigned flags : 8;
 };
 
-/* Overloaded operator info indexed by ass_op_p & tree_code.  */
-extern GTY(()) ovl_op_info_t ovl_op_info[2][MAX_TREE_CODES];
+/* Overloaded operator info indexed by ass_op_p & ovl_op_code.  */
+extern GTY(()) ovl_op_info_t ovl_op_info[2][OVL_OP_MAX];
+/* Mapping from tree_codes to ovl_op_codes.  */
+extern GTY(()) unsigned char ovl_op_mapping[MAX_TREE_CODES];
+/* Mapping for ambi-ary operators from the binary to the unary.  */
+extern GTY(()) unsigned char ovl_op_alternate[OVL_OP_MAX];
 
 /* Given an ass_op_p boolean and a tree code, return a pointer to its
    overloaded operator info.  */
 #define OVL_OP_INFO(IS_ASS_P, TREE_CODE)                       \
-  (&ovl_op_info[(IS_ASS_P) != 0][(TREE_CODE)])
+  (&ovl_op_info[(IS_ASS_P) != 0][ovl_op_mapping[(TREE_CODE)]])
+/* Overloaded operator info for an identifier for which
+   IDENTIFIER_ANY_OP_P is true.  */
+#define IDENTIFIER_OVL_OP_INFO(NODE) \
+  (&ovl_op_info[IDENTIFIER_ASSIGN_OP_P (NODE)][IDENTIFIER_CP_INDEX (NODE)])
 
 /* A type-qualifier, or bitmask therefore, using the TYPE_QUAL
    constants.  */
index d60b8dd..f43c960 100644 (file)
@@ -65,8 +65,6 @@ static const char *redeclaration_error_message (tree, tree);
 
 static int decl_jump_unsafe (tree);
 static void require_complete_types_for_parms (tree);
-static bool ambi_op_p (enum tree_code);
-static bool unary_op_p (enum tree_code);
 static void push_local_name (tree);
 static tree grok_reference_init (tree, tree, tree, int);
 static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
@@ -12874,30 +12872,6 @@ grok_ctor_properties (const_tree ctype, const_tree decl)
   return true;
 }
 
-/* An operator with this code is unary, but can also be binary.  */
-
-static bool
-ambi_op_p (enum tree_code code)
-{
-  return (code == INDIRECT_REF
-         || code == ADDR_EXPR
-         || code == UNARY_PLUS_EXPR
-         || code == NEGATE_EXPR
-         || code == PREINCREMENT_EXPR
-         || code == PREDECREMENT_EXPR);
-}
-
-/* An operator with this name can only be unary.  */
-
-static bool
-unary_op_p (enum tree_code code)
-{
-  return (code == TRUTH_NOT_EXPR
-         || code == BIT_NOT_EXPR
-         || code == COMPONENT_REF
-         || code == TYPE_EXPR);
-}
-
 /* DECL is a declaration for an overloaded or conversion operator.  If
    COMPLAIN is true, errors are issued for invalid declarations.  */
 
@@ -12905,15 +12879,15 @@ bool
 grok_op_properties (tree decl, bool complain)
 {
   tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
-  int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
+  bool methodp = TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE;
   tree name = DECL_NAME (decl);
 
   tree class_type = DECL_CONTEXT (decl);
   if (class_type && !CLASS_TYPE_P (class_type))
     class_type = NULL_TREE;
 
-  tree_code operator_code = ERROR_MARK;
-  unsigned op_flags = OVL_OP_FLAG_NONE;
+  tree_code operator_code;
+  unsigned op_flags;
   if (IDENTIFIER_CONV_OP_P (name))
     {
       /* Conversion operators are TYPE_EXPR for the purposes of this
@@ -12923,21 +12897,11 @@ grok_op_properties (tree decl, bool complain)
     }
   else
     {
-      /* It'd be nice to hang something else of the identifier to
-        find CODE more directly.  */
-      bool assign_op = IDENTIFIER_ASSIGN_OP_P (name);
-      const ovl_op_info_t *ovl_op = OVL_OP_INFO (assign_op, 0);
-      if (false)
-       ;
-#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, KIND)                \
-      else if (ovl_op[CODE].identifier == name)                        \
-       operator_code = (CODE);
-#include "operators.def"
-#undef DEF_OPERATOR
-      else
-       gcc_unreachable ();
-      gcc_assert (operator_code != ERROR_MARK);
-      op_flags = ovl_op[operator_code].flags;
+      const ovl_op_info_t *ovl_op = IDENTIFIER_OVL_OP_INFO (name);
+
+      operator_code = ovl_op->tree_code;
+      op_flags = ovl_op->flags;
+      gcc_checking_assert (operator_code != ERROR_MARK);
       DECL_OVERLOADED_OPERATOR_CODE (decl) = operator_code;
     }
 
@@ -13071,70 +13035,43 @@ grok_op_properties (tree decl, bool complain)
     }
 
   /* Verify correct number of arguments.  */
-  if (ambi_op_p (operator_code))
+  switch (op_flags)
     {
+    case OVL_OP_FLAG_AMBIARY:
       if (arity == 1)
-       /* We pick the one-argument operator codes by default, so
-          we don't have to change anything.  */
-       ;
-      else if (arity == 2)
        {
-         /* If we thought this was a unary operator, we now know
-            it to be a binary operator.  */
-         switch (operator_code)
-           {
-           case INDIRECT_REF:
-             operator_code = MULT_EXPR;
-             break;
-
-           case ADDR_EXPR:
-             operator_code = BIT_AND_EXPR;
-             break;
-
-           case UNARY_PLUS_EXPR:
-             operator_code = PLUS_EXPR;
-             break;
-
-           case NEGATE_EXPR:
-             operator_code = MINUS_EXPR;
-             break;
-
-           case PREINCREMENT_EXPR:
-             operator_code = POSTINCREMENT_EXPR;
-             break;
-
-           case PREDECREMENT_EXPR:
-             operator_code = POSTDECREMENT_EXPR;
-             break;
-
-           default:
-             gcc_unreachable ();
-           }
-
+         /* We have a unary instance of an ambi-ary op.  Remap to the
+            unary one.  */
+         unsigned alt = ovl_op_alternate[ovl_op_mapping [operator_code]];
+         const ovl_op_info_t *ovl_op = &ovl_op_info[false][alt];
+         gcc_checking_assert (ovl_op->flags == OVL_OP_FLAG_UNARY);
+         operator_code = ovl_op->tree_code;
          DECL_OVERLOADED_OPERATOR_CODE (decl) = operator_code;
-
-         if ((operator_code == POSTINCREMENT_EXPR
-              || operator_code == POSTDECREMENT_EXPR)
-             && ! processing_template_decl
-             && ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)), integer_type_node))
-           {
-             error (methodp
-                ? G_("postfix %qD must have %<int%> as its argument")
-                : G_("postfix %qD must have %<int%> as its second argument"),
-                decl);
-             return false;
-           }
        }
-      else
+      else if (arity != 2)
        {
+         /* This was an ambiguous operator but is invalid. */
          error (methodp
                 ? G_("%qD must have either zero or one argument")
                 : G_("%qD must have either one or two arguments"), decl);
          return false;
        }
-    }
-  else if (unary_op_p (operator_code))
-    {
+      else if ((operator_code == POSTINCREMENT_EXPR
+               || operator_code == POSTDECREMENT_EXPR)
+              && ! processing_template_decl
+              /* x++ and x--'s second argument must be an int.  */
+              && ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)),
+                                integer_type_node))
+       {
+         error (methodp
+                ? G_("postfix %qD must have %<int%> as its argument")
+                : G_("postfix %qD must have %<int%> as its second argument"),
+                decl);
+         return false;
+       }
+      break;
+
+    case OVL_OP_FLAG_UNARY:
       if (arity != 1)
        {
          error (methodp
@@ -13142,9 +13079,9 @@ grok_op_properties (tree decl, bool complain)
                 : G_("%qD must have exactly one argument"), decl);
          return false;
        }
-    }
-  else
-    {
+      break;
+
+    case OVL_OP_FLAG_BINARY:
       if (arity != 2)
        {
          error (methodp
@@ -13152,8 +13089,12 @@ grok_op_properties (tree decl, bool complain)
                 : G_("%qD must have exactly two arguments"), decl);
          return false;
        }
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  
+
   /* There can be no default arguments.  */
   for (tree arg = argtypes; arg != void_list_node; arg = TREE_CHAIN (arg))
     if (TREE_PURPOSE (arg))
index af081f4..7754145 100644 (file)
@@ -77,7 +77,20 @@ cxx_finish (void)
   c_common_finish ();
 }
 
-ovl_op_info_t ovl_op_info[2][MAX_TREE_CODES];
+ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] = 
+  {
+    {
+      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
+      {NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
+#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
+      {NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
+#define OPERATOR_TRANSITION }, {                       \
+      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
+#include "operators.def"
+    }
+  };
+unsigned char ovl_op_mapping[MAX_TREE_CODES];
+unsigned char ovl_op_alternate[OVL_OP_MAX];
 
 /* Get the name of the kind of identifier T.  */
 
@@ -129,26 +142,77 @@ set_operator_ident (ovl_op_info_t *ptr)
   return ident;
 }
 
+/* Initialize data structures that keep track of operator names.  */
+
 static void
 init_operators (void)
 {
-  tree identifier;
-  ovl_op_info_t *oni;
-
-#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, KIND)                        \
-  oni = OVL_OP_INFO (KIND == cik_assign_op, CODE);                     \
-  oni->name = NAME;                                                    \
-  oni->mangled_name = MANGLING;                                                \
-  oni->tree_code = CODE;                                               \
-  oni->flags = FLAGS;                                                  \
-  if (NAME) {                                                          \
-    identifier = set_operator_ident (oni);                             \
-    if (KIND != cik_simple_op || !IDENTIFIER_ANY_OP_P (identifier))    \
-      set_identifier_kind (identifier, KIND);                          \
-  }
+  /* We rely on both these being zero.  */
+  gcc_checking_assert (!OVL_OP_ERROR_MARK && !ERROR_MARK);
 
-#include "operators.def"
-#undef DEF_OPERATOR
+  /* This loop iterates backwards because we need to move the
+     assignment operators down to their correct slots.  I.e. morally
+     equivalent to an overlapping memmove where dest > src.  Slot
+     zero is for error_mark, so hae no operator. */
+  for (unsigned ix = OVL_OP_MAX; --ix;)
+    {
+      ovl_op_info_t *op_ptr = &ovl_op_info[false][ix];
+
+      if (op_ptr->name)
+       {
+         /* Make sure it fits in lang_decl_fn::operator_code. */
+         gcc_checking_assert (op_ptr->ovl_op_code < (1 << 6));
+         tree ident = set_operator_ident (op_ptr);
+         if (unsigned index = IDENTIFIER_CP_INDEX (ident))
+           {
+             ovl_op_info_t *bin_ptr = &ovl_op_info[false][index];
+
+             /* They should only differ in unary/binary ness.  */
+             gcc_checking_assert ((op_ptr->flags ^ bin_ptr->flags)
+                                  == OVL_OP_FLAG_AMBIARY);
+             bin_ptr->flags |= op_ptr->flags;
+             ovl_op_alternate[index] = ix;
+           }
+         else
+           {
+             IDENTIFIER_CP_INDEX (ident) = ix;
+             set_identifier_kind (ident,
+                                  op_ptr->flags & OVL_OP_FLAG_ALLOC
+                                  ? cik_newdel_op : cik_simple_op);
+           }
+       }
+      if (op_ptr->tree_code)
+       {
+         gcc_checking_assert (op_ptr->ovl_op_code == ix
+                              && !ovl_op_mapping[op_ptr->tree_code]);
+         ovl_op_mapping[op_ptr->tree_code] = op_ptr->ovl_op_code;
+       }
+
+      ovl_op_info_t *as_ptr = &ovl_op_info[true][ix];
+      if (as_ptr->name)
+       {
+         /* These will be placed at the start of the array, move to
+            the correct slot and initialize.  */
+         if (as_ptr->ovl_op_code != ix)
+           {
+             ovl_op_info_t *dst_ptr = &ovl_op_info[true][as_ptr->ovl_op_code];
+             gcc_assert (as_ptr->ovl_op_code > ix && !dst_ptr->tree_code);
+             memcpy (dst_ptr, as_ptr, sizeof (*dst_ptr));
+             memset (as_ptr, 0, sizeof (*as_ptr));
+             as_ptr = dst_ptr;
+           }
+
+         tree ident = set_operator_ident (as_ptr);
+         gcc_checking_assert (!IDENTIFIER_CP_INDEX (ident));
+         IDENTIFIER_CP_INDEX (ident) = as_ptr->ovl_op_code;
+         set_identifier_kind (ident, cik_assign_op);
+
+         gcc_checking_assert (!ovl_op_mapping[as_ptr->tree_code]
+                              || (ovl_op_mapping[as_ptr->tree_code]
+                                  == as_ptr->ovl_op_code));
+         ovl_op_mapping[as_ptr->tree_code] = as_ptr->ovl_op_code;
+       }
+    }
 }
 
 /* Initialize the reserved words.  */
index 7feb889..27530f9 100644 (file)
@@ -1265,30 +1265,8 @@ write_unqualified_id (tree identifier)
     write_conversion_operator_name (TREE_TYPE (identifier));
   else if (IDENTIFIER_ANY_OP_P (identifier))
     {
-      const char *mangled_name = NULL;
-      bool assop = IDENTIFIER_ASSIGN_OP_P (identifier);
-
-      /* Unfortunately, there is no easy way to go from the
-        name of the operator back to the corresponding tree
-        code.  */
-      for (unsigned i = 0; i < MAX_TREE_CODES; ++i)
-       {
-         const ovl_op_info_t *ovl_op = OVL_OP_INFO (assop, i);
-
-         if (ovl_op->identifier == identifier)
-           {
-             /* The ABI says that we prefer binary operator
-                names to unary operator names.  */
-             if (ovl_op->flags == OVL_OP_FLAG_BINARY)
-               {
-                 mangled_name = ovl_op->mangled_name;
-                 break;
-               }
-             else if (!mangled_name)
-               mangled_name = ovl_op->mangled_name;
-           }
-       }
-      write_string (mangled_name);
+      const ovl_op_info_t *ovl_op = IDENTIFIER_OVL_OP_INFO (identifier);
+      write_string (ovl_op->mangled_name);
     }
   else if (UDLIT_OPER_P (identifier))
     write_literal_operator_name (identifier);
index 51d2c3a..119529c 100644 (file)
@@ -50,110 +50,109 @@ along with GCC; see the file COPYING3.  If not see
      ovl_op_flags bits.  Postincrement and postdecrement operators are
      marked as binary.
 
-   ASSN_P
-
-     A boolean value.  If nonzero, this is an assignment operator.
-
    Before including this file, you should define DEF_OPERATOR
    to take these arguments.
 
    There is code (such as in grok_op_properties) that depends on the
-   order the operators are presented in this file.  In particular,
-   unary operators must precede binary operators.  */
-
-/* Use DEF_SIMPLE_OPERATOR to define a non-assignment operator.  Its
-   arguments are as for DEF_OPERATOR, but there is no need to provide
-   an ASSIGNMENT_P argument; it is always zero.  */
-
-#define DEF_SIMPLE_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
-  DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, cik_simple_op)
+   order the operators are presented in this file.  Unary_ops must
+   preceed a matching binary op (i.e. '+').  Assignment operators must
+   be last, after OPERATOR_TRANSITION.  */
 
 /* Use DEF_ASSN_OPERATOR to define an assignment operator.  Its
    arguments are as for DEF_OPERATOR, but there is no need to provide
-   an ASSIGNMENT_P argument; it is always one.  */
+   FLAGS (OVL_OP_FLAG_BINARY).  */
 
-#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
-  DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, cik_assign_op)
+#ifndef DEF_ASSN_OPERATOR
+#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) \
+  DEF_OPERATOR(NAME, CODE, MANGLING, OVL_OP_FLAG_BINARY)
+#endif
 
-/* Memory allocation operators.  */
-DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC, cik_newdel_op)
+/* Memory allocation operators.  ARITY has special meaning. */
+DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC)
 DEF_OPERATOR ("new []", VEC_NEW_EXPR, "na",
-             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_VEC, cik_newdel_op)
+             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_VEC)
 DEF_OPERATOR ("delete", DELETE_EXPR, "dl",
-             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE, cik_newdel_op)
+             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE)
 DEF_OPERATOR ("delete []", VEC_DELETE_EXPR, "da",
-             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE | OVL_OP_FLAG_VEC,
-             cik_newdel_op)
+             OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE | OVL_OP_FLAG_VEC)
 
 /* Unary operators.  */
-DEF_SIMPLE_OPERATOR ("+", UNARY_PLUS_EXPR, "ps", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("-", NEGATE_EXPR, "ng", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("&", ADDR_EXPR, "ad", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("*", INDIRECT_REF, "de", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("~", BIT_NOT_EXPR, "co", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("!", TRUTH_NOT_EXPR, "nt", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("++", PREINCREMENT_EXPR, "pp", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("--", PREDECREMENT_EXPR, "mm", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("sizeof", SIZEOF_EXPR, "sz", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("+", UNARY_PLUS_EXPR, "ps", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("-", NEGATE_EXPR, "ng", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("&", ADDR_EXPR, "ad", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("*", INDIRECT_REF, "de", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("~", BIT_NOT_EXPR, "co", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("!", TRUTH_NOT_EXPR, "nt", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("++", PREINCREMENT_EXPR, "pp", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("--", PREDECREMENT_EXPR, "mm", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("->", COMPONENT_REF, "pt", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("sizeof", SIZEOF_EXPR, "sz", OVL_OP_FLAG_UNARY)
+
 /* These are extensions.  */
-DEF_SIMPLE_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
-DEF_SIMPLE_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
 
 /* Binary operators.  */
-DEF_SIMPLE_OPERATOR ("+", PLUS_EXPR, "pl", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("-", MINUS_EXPR, "mi", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("*", MULT_EXPR, "ml", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("/", TRUNC_DIV_EXPR, "dv", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("%", TRUNC_MOD_EXPR, "rm", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("&", BIT_AND_EXPR, "an", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("|", BIT_IOR_EXPR, "or", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("^", BIT_XOR_EXPR, "eo", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("<<", LSHIFT_EXPR, "ls", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR (">>", RSHIFT_EXPR, "rs", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("==", EQ_EXPR, "eq", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("!=", NE_EXPR, "ne", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("<", LT_EXPR, "lt", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR (">", GT_EXPR, "gt", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("<=", LE_EXPR, "le", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR (">=", GE_EXPR, "ge", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("&&", TRUTH_ANDIF_EXPR, "aa", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("||", TRUTH_ORIF_EXPR, "oo", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR (",", COMPOUND_EXPR, "cm", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("->*", MEMBER_REF, "pm", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR (".*", DOTSTAR_EXPR, "ds", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("->", COMPONENT_REF, "pt", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("[]", ARRAY_REF, "ix", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", OVL_OP_FLAG_BINARY)
-DEF_SIMPLE_OPERATOR ("--", POSTDECREMENT_EXPR, "mm", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("+", PLUS_EXPR, "pl", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("-", MINUS_EXPR, "mi", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("*", MULT_EXPR, "ml", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("/", TRUNC_DIV_EXPR, "dv", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("%", TRUNC_MOD_EXPR, "rm", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("&", BIT_AND_EXPR, "an", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("|", BIT_IOR_EXPR, "or", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("^", BIT_XOR_EXPR, "eo", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("<<", LSHIFT_EXPR, "ls", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR (">>", RSHIFT_EXPR, "rs", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("==", EQ_EXPR, "eq", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("!=", NE_EXPR, "ne", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("<", LT_EXPR, "lt", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR (">", GT_EXPR, "gt", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("<=", LE_EXPR, "le", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR (">=", GE_EXPR, "ge", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("&&", TRUTH_ANDIF_EXPR, "aa", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("||", TRUTH_ORIF_EXPR, "oo", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR (",", COMPOUND_EXPR, "cm", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("->*", MEMBER_REF, "pm", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR (".*", DOTSTAR_EXPR, "ds", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("[]", ARRAY_REF, "ix", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", OVL_OP_FLAG_BINARY)
+DEF_OPERATOR ("--", POSTDECREMENT_EXPR, "mm", OVL_OP_FLAG_BINARY)
 
 /* Miscellaneous.  */
-DEF_SIMPLE_OPERATOR ("?:", COND_EXPR, "qu", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR ("()", CALL_EXPR, "cl", OVL_OP_FLAG_NONE)
+DEF_OPERATOR ("?:", COND_EXPR, "qu", OVL_OP_FLAG_NONE)
+DEF_OPERATOR ("()", CALL_EXPR, "cl", OVL_OP_FLAG_NONE)
 
 /* Operators needed for mangling.  */
-DEF_SIMPLE_OPERATOR (NULL, CAST_EXPR, "cv", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, DYNAMIC_CAST_EXPR, "dc", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, REINTERPRET_CAST_EXPR, "rc", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, CONST_CAST_EXPR, "cc", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, STATIC_CAST_EXPR, "sc", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, SCOPE_REF, "sr", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, EXPR_PACK_EXPANSION, "sp", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, UNARY_LEFT_FOLD_EXPR, "fl", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, UNARY_RIGHT_FOLD_EXPR, "fr", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, BINARY_LEFT_FOLD_EXPR, "fL", OVL_OP_FLAG_NONE)
-DEF_SIMPLE_OPERATOR (NULL, BINARY_RIGHT_FOLD_EXPR, "fR", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, CAST_EXPR, "cv", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR (NULL, DYNAMIC_CAST_EXPR, "dc", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR (NULL, REINTERPRET_CAST_EXPR, "rc", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR (NULL, CONST_CAST_EXPR, "cc", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR (NULL, STATIC_CAST_EXPR, "sc", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR (NULL, SCOPE_REF, "sr", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, EXPR_PACK_EXPANSION, "sp", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, UNARY_LEFT_FOLD_EXPR, "fl", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, UNARY_RIGHT_FOLD_EXPR, "fr", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, BINARY_LEFT_FOLD_EXPR, "fL", OVL_OP_FLAG_NONE)
+DEF_OPERATOR (NULL, BINARY_RIGHT_FOLD_EXPR, "fR", OVL_OP_FLAG_NONE)
+
+#ifdef OPERATOR_TRANSITION
+OPERATOR_TRANSITION
+#undef OPERATOR_TRANSITION
+#endif
 
 /* Assignment operators.  */
-DEF_ASSN_OPERATOR ("=", NOP_EXPR, "aS", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("+=", PLUS_EXPR, "pL", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("-=", MINUS_EXPR, "mI", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("*=", MULT_EXPR, "mL", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("/=", TRUNC_DIV_EXPR, "dV", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("%=", TRUNC_MOD_EXPR, "rM", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("&=", BIT_AND_EXPR, "aN", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("|=", BIT_IOR_EXPR, "oR", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("^=", BIT_XOR_EXPR, "eO", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR ("<<=", LSHIFT_EXPR, "lS", OVL_OP_FLAG_BINARY)
-DEF_ASSN_OPERATOR (">>=", RSHIFT_EXPR, "rS", OVL_OP_FLAG_BINARY)
-
+DEF_ASSN_OPERATOR ("=", NOP_EXPR, "aS")
+DEF_ASSN_OPERATOR ("+=", PLUS_EXPR, "pL")
+DEF_ASSN_OPERATOR ("-=", MINUS_EXPR, "mI")
+DEF_ASSN_OPERATOR ("*=", MULT_EXPR, "mL")
+DEF_ASSN_OPERATOR ("/=", TRUNC_DIV_EXPR, "dV")
+DEF_ASSN_OPERATOR ("%=", TRUNC_MOD_EXPR, "rM")
+DEF_ASSN_OPERATOR ("&=", BIT_AND_EXPR, "aN")
+DEF_ASSN_OPERATOR ("|=", BIT_IOR_EXPR, "oR")
+DEF_ASSN_OPERATOR ("^=", BIT_XOR_EXPR, "eO")
+DEF_ASSN_OPERATOR ("<<=", LSHIFT_EXPR, "lS")
+DEF_ASSN_OPERATOR (">>=", RSHIFT_EXPR, "rS")
+
+#undef DEF_ASSN_OPERATOR
+#undef DEF_OPERATOR