[C++ PATCH] operator name cleanup prepatch
authorNathan Sidwell <nathan@acm.org>
Mon, 30 Oct 2017 19:04:53 +0000 (19:04 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Mon, 30 Oct 2017 19:04:53 +0000 (19:04 +0000)
https://gcc.gnu.org/ml/gcc-patches/2017-10/msg02240.html
cp/
* call.c (build_op_call_1): Test for FUNCTION_DECL in same manner
as a few lines earlier.
* cp-tree.h (PACK_EXPANSION_PATTERN): Fix white space.
* decl.c (grokfndecl): Fix indentation.
(compute_array_index_type): Use processing_template_decl_sentinel.
(grok_op_properties): Move warnings to end.  Reorder other checks
to group similar entities.  Tweak diagnostics.
* lex.c (unqualified_name_lookup_error): No need to check name is
not ERROR_MARK operator.
* parser.c (cp_parser_operator): Select operator code before
looking it up.
* typeck.c (check_return_expr): Fix indentation and line wrapping.

testsuite/

* g++.dg/other/operator2.C: Adjust diagnostic.
* g++.old-deja/g++.jason/operator.C: Likewise.

From-SVN: r254238

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/lex.c
gcc/cp/parser.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/operator2.C
gcc/testsuite/g++.old-deja/g++.jason/operator.C

index a4259f1..7630638 100644 (file)
@@ -1,3 +1,18 @@
+2017-10-30  Nathan Sidwell  <nathan@acm.org>
+
+       * call.c (build_op_call_1): Test for FUNCTION_DECL in same manner
+       as a few lines earlier.
+       * cp-tree.h (PACK_EXPANSION_PATTERN): Fix white space.
+       * decl.c (grokfndecl): Fix indentation.
+       (compute_array_index_type): Use processing_template_decl_sentinel.
+       (grok_op_properties): Move warnings to end.  Reorder other checks
+       to group similar entities.  Tweak diagnostics.
+       * lex.c (unqualified_name_lookup_error): No need to check name is
+       not ERROR_MARK operator.
+       * parser.c (cp_parser_operator): Select operator code before
+       looking it up.
+       * typeck.c (check_return_expr): Fix indentation and line wrapping.
+
 2017-10-27  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * pt.c (invalid_nontype_parm_type_p): Return a bool instead of an int.
index 8f33ab5..de3434b 100644 (file)
@@ -4565,11 +4565,14 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
        result = build_over_call (cand, LOOKUP_NORMAL, complain);
       else
        {
-         if (DECL_P (cand->fn))
+         if (TREE_CODE (cand->fn) == FUNCTION_DECL)
            obj = convert_like_with_context (cand->convs[0], obj, cand->fn,
                                             -1, complain);
          else
-           obj = convert_like (cand->convs[0], obj, complain);
+           {
+             gcc_checking_assert (TYPE_P (cand->fn));
+             obj = convert_like (cand->convs[0], obj, complain);
+           }
          obj = convert_from_reference (obj);
          result = cp_build_function_call_vec (obj, args, complain);
        }
index f2570b0..3aefd7e 100644 (file)
@@ -3460,7 +3460,7 @@ extern void decl_shadowed_for_var_insert (tree, tree);
 /* Extracts the type or expression pattern from a TYPE_PACK_EXPANSION or
    EXPR_PACK_EXPANSION.  */
 #define PACK_EXPANSION_PATTERN(NODE)                            \
-  (TREE_CODE (NODE) == TYPE_PACK_EXPANSION? TREE_TYPE (NODE)    \
+  (TREE_CODE (NODE) == TYPE_PACK_EXPANSION ? TREE_TYPE (NODE)    \
    : TREE_OPERAND (NODE, 0))
 
 /* Sets the type or expression pattern for a TYPE_PACK_EXPANSION or
index 519aa06..0e49e2b 100644 (file)
@@ -8698,7 +8698,7 @@ grokfndecl (tree ctype,
                  "deduction guide %qD must not have a function body", decl);
     }
   else if (IDENTIFIER_ANY_OP_P (DECL_NAME (decl))
-      && !grok_op_properties (decl, /*complain=*/true))
+          && !grok_op_properties (decl, /*complain=*/true))
     return NULL_TREE;
   else if (UDLIT_OPER_P (DECL_NAME (decl)))
     {
@@ -9472,22 +9472,20 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
     itype = build_min (MINUS_EXPR, sizetype, size, integer_one_node);
   else
     {
-      HOST_WIDE_INT saved_processing_template_decl;
-
       /* Compute the index of the largest element in the array.  It is
         one less than the number of elements in the array.  We save
         and restore PROCESSING_TEMPLATE_DECL so that computations in
         cp_build_binary_op will be appropriately folded.  */
-      saved_processing_template_decl = processing_template_decl;
-      processing_template_decl = 0;
-      itype = cp_build_binary_op (input_location,
-                                 MINUS_EXPR,
-                                 cp_convert (ssizetype, size, complain),
-                                 cp_convert (ssizetype, integer_one_node,
-                                             complain),
-                                 complain);
-      itype = maybe_constant_value (itype);
-      processing_template_decl = saved_processing_template_decl;
+      {
+       processing_template_decl_sentinel s;
+       itype = cp_build_binary_op (input_location,
+                                   MINUS_EXPR,
+                                   cp_convert (ssizetype, size, complain),
+                                   cp_convert (ssizetype, integer_one_node,
+                                               complain),
+                                   complain);
+       itype = maybe_constant_value (itype);
+      }
 
       if (!TREE_CONSTANT (itype))
        {
@@ -12909,25 +12907,14 @@ bool
 grok_op_properties (tree decl, bool complain)
 {
   tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
-  tree argtype;
   int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
   tree name = DECL_NAME (decl);
-  enum tree_code operator_code;
-  int arity;
-  bool ellipsis_p;
-  tree class_type;
-
-  /* Count the number of arguments and check for ellipsis.  */
-  for (argtype = argtypes, arity = 0;
-       argtype && argtype != void_list_node;
-       argtype = TREE_CHAIN (argtype))
-    ++arity;
-  ellipsis_p = !argtype;
 
-  class_type = DECL_CONTEXT (decl);
+  tree class_type = DECL_CONTEXT (decl);
   if (class_type && !CLASS_TYPE_P (class_type))
     class_type = NULL_TREE;
 
+  enum tree_code operator_code = ERROR_MARK;
   if (IDENTIFIER_CONV_OP_P (name))
     operator_code = TYPE_EXPR;
   else
@@ -12953,39 +12940,40 @@ grok_op_properties (tree decl, bool complain)
   gcc_assert (operator_code != MAX_TREE_CODES);
   SET_OVERLOADED_OPERATOR_CODE (decl, operator_code);
 
-  if (class_type)
-    switch (operator_code)
-      {
-      case NEW_EXPR:
-       TYPE_HAS_NEW_OPERATOR (class_type) = 1;
-       break;
+  if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR
+      || operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
+    {
+      /* operator new and operator delete are quite special.  */
+      if (class_type)
+       switch (operator_code)
+         {
+         case NEW_EXPR:
+           TYPE_HAS_NEW_OPERATOR (class_type) = 1;
+           break;
 
-      case DELETE_EXPR:
-       TYPE_GETS_DELETE (class_type) |= 1;
-       break;
+         case DELETE_EXPR:
+           TYPE_GETS_DELETE (class_type) |= 1;
+           break;
 
-      case VEC_NEW_EXPR:
-       TYPE_HAS_ARRAY_NEW_OPERATOR (class_type) = 1;
-       break;
+         case VEC_NEW_EXPR:
+           TYPE_HAS_ARRAY_NEW_OPERATOR (class_type) = 1;
+           break;
 
-      case VEC_DELETE_EXPR:
-       TYPE_GETS_DELETE (class_type) |= 2;
-       break;
+         case VEC_DELETE_EXPR:
+           TYPE_GETS_DELETE (class_type) |= 2;
+           break;
 
-      default:
-       break;
-      }
+         default:
+           gcc_unreachable ();
+         }
 
-    /* [basic.std.dynamic.allocation]/1:
+      /* [basic.std.dynamic.allocation]/1:
 
-       A program is ill-formed if an allocation function is declared
-       in a namespace scope other than global scope or declared static
-       in global scope.
+        A program is ill-formed if an allocation function is declared
+        in a namespace scope other than global scope or declared
+        static in global scope.
 
-       The same also holds true for deallocation functions.  */
-  if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR
-      || operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
-    {
+        The same also holds true for deallocation functions.  */
       if (DECL_NAMESPACE_SCOPE_P (decl))
        {
          if (CP_DECL_CONTEXT (decl) != global_namespace)
@@ -12993,287 +12981,292 @@ grok_op_properties (tree decl, bool complain)
              error ("%qD may not be declared within a namespace", decl);
              return false;
            }
-         else if (!TREE_PUBLIC (decl))
+
+         if (!TREE_PUBLIC (decl))
            {
              error ("%qD may not be declared as static", decl);
              return false;
            }
        }
-    }
 
-  if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR)
-    {
-      TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
-      DECL_IS_OPERATOR_NEW (decl) = 1;
+      if (operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
+       TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
+      else
+       {
+         TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
+         DECL_IS_OPERATOR_NEW (decl) = 1;
+       }
+
+      return true;
     }
-  else if (operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
-    TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
-  else
+
+  /* An operator function must either be a non-static member function
+     or have at least one parameter of a class, a reference to a class,
+     an enumeration, or a reference to an enumeration.  13.4.0.6 */
+  if (! methodp || DECL_STATIC_FUNCTION_P (decl))
     {
-      /* An operator function must either be a non-static member function
-        or have at least one parameter of a class, a reference to a class,
-        an enumeration, or a reference to an enumeration.  13.4.0.6 */
-      if (! methodp || DECL_STATIC_FUNCTION_P (decl))
+      if (operator_code == TYPE_EXPR
+         || operator_code == CALL_EXPR
+         || operator_code == COMPONENT_REF
+         || operator_code == ARRAY_REF
+         || operator_code == NOP_EXPR)
+       {
+         error ("%qD must be a nonstatic member function", decl);
+         return false;
+       }
+
+      if (DECL_STATIC_FUNCTION_P (decl))
+       {
+         error ("%qD must be either a non-static member "
+                "function or a non-member function", decl);
+         return false;
+       }
+
+      for (tree arg = argtypes; ; arg = TREE_CHAIN (arg))
        {
-         if (operator_code == TYPE_EXPR
-             || operator_code == CALL_EXPR
-             || operator_code == COMPONENT_REF
-             || operator_code == ARRAY_REF
-             || operator_code == NOP_EXPR)
+         if (!arg || arg == void_list_node)
            {
-             error ("%qD must be a nonstatic member function", decl);
+             if (complain)
+               error ("%qD must have an argument of class or "
+                      "enumerated type", decl);
              return false;
            }
-         else
-           {
-             tree p;
+      
+         tree type = non_reference (TREE_VALUE (arg));
+         if (type == error_mark_node)
+           return false;
+         
+         /* MAYBE_CLASS_TYPE_P, rather than CLASS_TYPE_P, is used
+            because these checks are performed even on template
+            functions.  */
+         if (MAYBE_CLASS_TYPE_P (type)
+             || TREE_CODE (type) == ENUMERAL_TYPE)
+           break;
+       }
+    }
 
-             if (DECL_STATIC_FUNCTION_P (decl))
-               {
-                 error ("%qD must be either a non-static member "
-                        "function or a non-member function", decl);
-                 return false;
-               }
+  /* There are no restrictions on the arguments to an overloaded
+     "operator ()".  */
+  if (operator_code == CALL_EXPR)
+    return true;
 
-             for (p = argtypes; p && p != void_list_node; p = TREE_CHAIN (p))
-               {
-                 tree arg = non_reference (TREE_VALUE (p));
-                 if (arg == error_mark_node)
-                   return false;
-
-                 /* MAYBE_CLASS_TYPE_P, rather than CLASS_TYPE_P, is used
-                    because these checks are performed even on
-                    template functions.  */
-                 if (MAYBE_CLASS_TYPE_P (arg)
-                     || TREE_CODE (arg) == ENUMERAL_TYPE)
-                   break;
-               }
+  if (operator_code == COND_EXPR)
+    {
+      /* 13.4.0.3 */
+      error ("ISO C++ prohibits overloading operator ?:");
+      return false;
+    }
 
-             if (!p || p == void_list_node)
-               {
-                 if (complain)
-                   error ("%qD must have an argument of class or "
-                          "enumerated type", decl);
-                 return false;
-               }
-           }
+  /* Count the number of arguments and check for ellipsis.  */
+  int arity = 0;
+  for (tree arg = argtypes; arg != void_list_node; arg = TREE_CHAIN (arg))
+    {
+      if (!arg)
+       {
+         /* Variadic.  */
+         error ("%qD must not have variable number of arguments", decl);
+         return false;
        }
+      ++arity;
+    }
 
-      /* There are no restrictions on the arguments to an overloaded
-        "operator ()".  */
-      if (operator_code == CALL_EXPR)
-       return true;
-
-      /* Warn about conversion operators that will never be used.  */
-      if (IDENTIFIER_CONV_OP_P (name)
-         && ! DECL_TEMPLATE_INFO (decl)
-         && warn_conversion
-         /* Warn only declaring the function; there is no need to
-            warn again about out-of-class definitions.  */
-         && class_type == current_class_type)
+  /* Verify correct number of arguments.  */
+  if (ambi_op_p (operator_code))
+    {
+      if (arity == 1)
+       /* We pick the one-argument operator codes by default, so
+          we don't have to change anything.  */
+       ;
+      else if (arity == 2)
        {
-         tree t = TREE_TYPE (name);
-         int ref = (TREE_CODE (t) == REFERENCE_TYPE);
+         /* 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;
 
-         if (ref)
-           t = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+           case ADDR_EXPR:
+             operator_code = BIT_AND_EXPR;
+             break;
 
-         if (VOID_TYPE_P (t))
-            warning (OPT_Wconversion,
-                     ref
-                     ? G_("conversion to a reference to void "
-                          "will never use a type conversion operator")
-                     : G_("conversion to void "
-                          "will never use a type conversion operator"));
-         else if (class_type)
-           {
-             if (t == class_type)
-                warning (OPT_Wconversion,
-                     ref
-                     ? G_("conversion to a reference to the same type "
-                          "will never use a type conversion operator")
-                     : G_("conversion to the same type "
-                          "will never use a type conversion operator"));               
-             /* Don't force t to be complete here.  */
-             else if (MAYBE_CLASS_TYPE_P (t)
-                      && COMPLETE_TYPE_P (t)
-                      && DERIVED_FROM_P (t, class_type))
-                 warning (OPT_Wconversion,
-                          ref
-                          ? G_("conversion to a reference to a base class "
-                               "will never use a type conversion operator")
-                          : G_("conversion to a base class "
-                               "will never use a type conversion operator"));          
+           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 ();
            }
 
-       }
+         SET_OVERLOADED_OPERATOR_CODE (decl, operator_code);
 
-      if (operator_code == COND_EXPR)
+         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
        {
-         /* 13.4.0.3 */
-         error ("ISO C++ prohibits overloading operator ?:");
+         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 (ellipsis_p)
+    }
+  else if (unary_op_p (operator_code))
+    {
+      if (arity != 1)
        {
-         error ("%qD must not have variable number of arguments", decl);
+         error (methodp
+                ? G_("%qD must have no arguments")
+                : G_("%qD must have exactly one argument"), decl);
          return false;
        }
-      else if (ambi_op_p (operator_code))
+    }
+  else
+    {
+      if (arity != 2)
        {
-         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;
+         error (methodp
+                ? G_("%qD must have exactly one argument")
+                : G_("%qD must have exactly two arguments"), decl);
+         return false;
+       }
+    }
+  
+  /* There can be no default arguments.  */
+  for (tree arg = argtypes; arg != void_list_node; arg = TREE_CHAIN (arg))
+    if (TREE_PURPOSE (arg))
+      {
+       TREE_PURPOSE (arg) = NULL_TREE;
+       if (operator_code == POSTINCREMENT_EXPR
+           || operator_code == POSTDECREMENT_EXPR)
+         pedwarn (input_location, OPT_Wpedantic,
+                  "%qD cannot have default arguments", decl);
+       else
+         {
+           error ("%qD cannot have default arguments", decl);
+           return false;
+         }
+      }
 
-               case UNARY_PLUS_EXPR:
-                 operator_code = PLUS_EXPR;
-                 break;
+  /* At this point the declaration is well-formed.  It may not be
+     sensible though.  */
 
-               case NEGATE_EXPR:
-                 operator_code = MINUS_EXPR;
-                 break;
+  /* Check member function warnings only on the in-class declaration.
+     There's no point warning on an out-of-class definition.  */
+  if (class_type && class_type != current_class_type)
+    return true;
 
-               case PREINCREMENT_EXPR:
-                 operator_code = POSTINCREMENT_EXPR;
-                 break;
+  /* Warn about conversion operators that will never be used.  */
+  if (IDENTIFIER_CONV_OP_P (name)
+      && ! DECL_TEMPLATE_INFO (decl)
+      && warn_conversion)
+    {
+      tree t = TREE_TYPE (name);
+      int ref = (TREE_CODE (t) == REFERENCE_TYPE);
 
-               case PREDECREMENT_EXPR:
-                 operator_code = POSTDECREMENT_EXPR;
-                 break;
+      if (ref)
+       t = TYPE_MAIN_VARIANT (TREE_TYPE (t));
 
-               default:
-                 gcc_unreachable ();
-               }
+      if (VOID_TYPE_P (t))
+       warning (OPT_Wconversion,
+                ref
+                ? G_("conversion to a reference to void "
+                     "will never use a type conversion operator")
+                : G_("conversion to void "
+                     "will never use a type conversion operator"));
+      else if (class_type)
+       {
+         if (t == class_type)
+           warning (OPT_Wconversion,
+                     ref
+                     ? G_("conversion to a reference to the same type "
+                          "will never use a type conversion operator")
+                     : G_("conversion to the same type "
+                          "will never use a type conversion operator"));
+         /* Don't force t to be complete here.  */
+         else if (MAYBE_CLASS_TYPE_P (t)
+                  && COMPLETE_TYPE_P (t)
+                  && DERIVED_FROM_P (t, class_type))
+           warning (OPT_Wconversion,
+                    ref
+                    ? G_("conversion to a reference to a base class "
+                         "will never use a type conversion operator")
+                    : G_("conversion to a base class "
+                         "will never use a type conversion operator"));
+       }
+    }
 
-             SET_OVERLOADED_OPERATOR_CODE (decl, operator_code);
+  if (!warn_ecpp)
+    return true;
 
-             if ((operator_code == POSTINCREMENT_EXPR
-                  || operator_code == POSTDECREMENT_EXPR)
-                 && ! processing_template_decl
-                 && ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)), integer_type_node))
-               {
-                 if (methodp)
-                   error ("postfix %qD must take %<int%> as its argument",
-                          decl);
-                 else
-                   error ("postfix %qD must take %<int%> as its second "
-                          "argument", decl);
-                 return false;
-               }
-           }
-         else
-           {
-             if (methodp)
-               error ("%qD must take either zero or one argument", decl);
-             else
-               error ("%qD must take either one or two arguments", decl);
-             return false;
-           }
+  /* Effective C++ rules below.  */
 
-         /* More Effective C++ rule 6.  */
-         if (warn_ecpp
-             && (operator_code == POSTINCREMENT_EXPR
-                 || operator_code == POSTDECREMENT_EXPR
-                 || operator_code == PREINCREMENT_EXPR
-                 || operator_code == PREDECREMENT_EXPR))
-           {
-             tree arg = TREE_VALUE (argtypes);
-             tree ret = TREE_TYPE (TREE_TYPE (decl));
-             if (methodp || TREE_CODE (arg) == REFERENCE_TYPE)
-               arg = TREE_TYPE (arg);
-             arg = TYPE_MAIN_VARIANT (arg);
-             if (operator_code == PREINCREMENT_EXPR
-                 || operator_code == PREDECREMENT_EXPR)
-               {
-                 if (TREE_CODE (ret) != REFERENCE_TYPE
-                     || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
-                                      arg))
-                   warning (OPT_Weffc__, "prefix %qD should return %qT", decl,
-                            build_reference_type (arg));
-               }
-             else
-               {
-                 if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg))
-                   warning (OPT_Weffc__, "postfix %qD should return %qT", decl, arg);
-               }
-           }
+  /* More Effective C++ rule 7.  */
+  if (operator_code == TRUTH_ANDIF_EXPR
+      || operator_code == TRUTH_ORIF_EXPR
+      || operator_code == COMPOUND_EXPR)
+    warning (OPT_Weffc__,
+            "user-defined %qD always evaluates both arguments", decl);
+  
+  /* More Effective C++ rule 6.  */
+  if (operator_code == POSTINCREMENT_EXPR
+      || operator_code == POSTDECREMENT_EXPR
+      || operator_code == PREINCREMENT_EXPR
+      || operator_code == PREDECREMENT_EXPR)
+    {
+      tree arg = TREE_VALUE (argtypes);
+      tree ret = TREE_TYPE (TREE_TYPE (decl));
+      if (methodp || TREE_CODE (arg) == REFERENCE_TYPE)
+       arg = TREE_TYPE (arg);
+      arg = TYPE_MAIN_VARIANT (arg);
+
+      if (operator_code == PREINCREMENT_EXPR
+         || operator_code == PREDECREMENT_EXPR)
+       {
+         if (TREE_CODE (ret) != REFERENCE_TYPE
+             || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)), arg))
+           warning (OPT_Weffc__, "prefix %qD should return %qT", decl,
+                    build_reference_type (arg));
        }
-      else if (unary_op_p (operator_code))
+      else
        {
-         if (arity != 1)
-           {
-             if (methodp)
-               error ("%qD must take %<void%>", decl);
-             else
-               error ("%qD must take exactly one argument", decl);
-             return false;
-           }
+         if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg))
+           warning (OPT_Weffc__, "postfix %qD should return %qT", decl, arg);
        }
-      else /* if (binary_op_p (operator_code)) */
-       {
-         if (arity != 2)
-           {
-             if (methodp)
-               error ("%qD must take exactly one argument", decl);
-             else
-               error ("%qD must take exactly two arguments", decl);
-             return false;
-           }
+    }
 
-         /* More Effective C++ rule 7.  */
-         if (warn_ecpp
-             && (operator_code == TRUTH_ANDIF_EXPR
-                 || operator_code == TRUTH_ORIF_EXPR
-                 || operator_code == COMPOUND_EXPR))
-           warning (OPT_Weffc__, "user-defined %qD always evaluates both arguments",
-                    decl);
-       }
+  /* Effective C++ rule 23.  */
+  if (!DECL_ASSIGNMENT_OPERATOR_P (decl)
+      && (operator_code == PLUS_EXPR
+         || operator_code == MINUS_EXPR
+         || operator_code == TRUNC_DIV_EXPR
+         || operator_code == MULT_EXPR
+         || operator_code == TRUNC_MOD_EXPR)
+      && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
+    warning (OPT_Weffc__, "%qD should return by value", decl);
 
-      /* Effective C++ rule 23.  */
-      if (warn_ecpp
-         && arity == 2
-         && !DECL_ASSIGNMENT_OPERATOR_P (decl)
-         && (operator_code == PLUS_EXPR
-             || operator_code == MINUS_EXPR
-             || operator_code == TRUNC_DIV_EXPR
-             || operator_code == MULT_EXPR
-             || operator_code == TRUNC_MOD_EXPR)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
-       warning (OPT_Weffc__, "%qD should return by value", decl);
-
-      /* [over.oper]/8 */
-      for (; argtypes && argtypes != void_list_node;
-         argtypes = TREE_CHAIN (argtypes))
-       if (TREE_PURPOSE (argtypes))
-         {
-           TREE_PURPOSE (argtypes) = NULL_TREE;
-           if (operator_code == POSTINCREMENT_EXPR
-               || operator_code == POSTDECREMENT_EXPR)
-             {
-               pedwarn (input_location, OPT_Wpedantic, "%qD cannot have default arguments", 
-                        decl);
-             }
-           else
-             {
-               error ("%qD cannot have default arguments", decl);
-               return false;
-             }
-         }
-    }
   return true;
 }
 \f
index da9187d..ff7160e 100644 (file)
@@ -462,10 +462,7 @@ unqualified_name_lookup_error (tree name, location_t loc)
     loc = EXPR_LOC_OR_LOC (name, input_location);
 
   if (IDENTIFIER_ANY_OP_P (name))
-    {
-      if (name != cp_operator_id (ERROR_MARK))
-       error_at (loc, "%qD not defined", name);
-    }
+    error_at (loc, "%qD not defined", name);
   else
     {
       if (!objc_diagnose_private_ivar (name))
index 2337be5..c31cd64 100644 (file)
@@ -14715,12 +14715,13 @@ cp_parser_operator (cp_parser* parser)
   location_t start_loc = token->location;
 
   /* Figure out which operator we have.  */
+  enum tree_code op = ERROR_MARK;
+  bool assop = false;
+  bool consumed = false;
   switch (token->type)
     {
     case CPP_KEYWORD:
       {
-       enum tree_code op;
-
        /* The keyword should be either `new' or `delete'.  */
        if (token->keyword == RID_NEW)
          op = NEW_EXPR;
@@ -14744,160 +14745,166 @@ cp_parser_operator (cp_parser* parser)
            if (cp_token *close_token
                = cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
              end_loc = close_token->location;
-           id = cp_operator_id (op == NEW_EXPR
-                             ? VEC_NEW_EXPR : VEC_DELETE_EXPR);
+           op = op == NEW_EXPR ? VEC_NEW_EXPR : VEC_DELETE_EXPR;
          }
-       /* Otherwise, we have the non-array variant.  */
-       else
-         id = cp_operator_id (op);
-
-       location_t loc = make_location (start_loc, start_loc, end_loc);
-
-       return cp_expr (id, loc);
+       start_loc = make_location (start_loc, start_loc, end_loc);
+       consumed = true;
+       break;
       }
 
     case CPP_PLUS:
-      id = cp_operator_id (PLUS_EXPR);
+      op = PLUS_EXPR;
       break;
 
     case CPP_MINUS:
-      id = cp_operator_id (MINUS_EXPR);
+      op = MINUS_EXPR;
       break;
 
     case CPP_MULT:
-      id = cp_operator_id (MULT_EXPR);
+      op = MULT_EXPR;
       break;
 
     case CPP_DIV:
-      id = cp_operator_id (TRUNC_DIV_EXPR);
+      op = TRUNC_DIV_EXPR;
       break;
 
     case CPP_MOD:
-      id = cp_operator_id (TRUNC_MOD_EXPR);
+      op = TRUNC_MOD_EXPR;
       break;
 
     case CPP_XOR:
-      id = cp_operator_id (BIT_XOR_EXPR);
+      op = BIT_XOR_EXPR;
       break;
 
     case CPP_AND:
-      id = cp_operator_id (BIT_AND_EXPR);
+      op = BIT_AND_EXPR;
       break;
 
     case CPP_OR:
-      id = cp_operator_id (BIT_IOR_EXPR);
+      op = BIT_IOR_EXPR;
       break;
 
     case CPP_COMPL:
-      id = cp_operator_id (BIT_NOT_EXPR);
+      op = BIT_NOT_EXPR;
       break;
 
     case CPP_NOT:
-      id = cp_operator_id (TRUTH_NOT_EXPR);
+      op = TRUTH_NOT_EXPR;
       break;
 
     case CPP_EQ:
-      id = cp_assignment_operator_id (NOP_EXPR);
+      assop = true;
+      op = NOP_EXPR;
       break;
 
     case CPP_LESS:
-      id = cp_operator_id (LT_EXPR);
+      op = LT_EXPR;
       break;
 
     case CPP_GREATER:
-      id = cp_operator_id (GT_EXPR);
+      op = GT_EXPR;
       break;
 
     case CPP_PLUS_EQ:
-      id = cp_assignment_operator_id (PLUS_EXPR);
+      assop = true;
+      op = PLUS_EXPR;
       break;
 
     case CPP_MINUS_EQ:
-      id = cp_assignment_operator_id (MINUS_EXPR);
+      assop = true;
+      op = MINUS_EXPR;
       break;
 
     case CPP_MULT_EQ:
-      id = cp_assignment_operator_id (MULT_EXPR);
+      assop = true;
+      op = MULT_EXPR;
       break;
 
     case CPP_DIV_EQ:
-      id = cp_assignment_operator_id (TRUNC_DIV_EXPR);
+      assop = true;
+      op = TRUNC_DIV_EXPR;
       break;
 
     case CPP_MOD_EQ:
-      id = cp_assignment_operator_id (TRUNC_MOD_EXPR);
+      assop = true;
+      op = TRUNC_MOD_EXPR;
       break;
 
     case CPP_XOR_EQ:
-      id = cp_assignment_operator_id (BIT_XOR_EXPR);
+      assop = true;
+      op = BIT_XOR_EXPR;
       break;
 
     case CPP_AND_EQ:
-      id = cp_assignment_operator_id (BIT_AND_EXPR);
+      assop = true;
+      op = BIT_AND_EXPR;
       break;
 
     case CPP_OR_EQ:
-      id = cp_assignment_operator_id (BIT_IOR_EXPR);
+      assop = true;
+      op = BIT_IOR_EXPR;
       break;
 
     case CPP_LSHIFT:
-      id = cp_operator_id (LSHIFT_EXPR);
+      op = LSHIFT_EXPR;
       break;
 
     case CPP_RSHIFT:
-      id = cp_operator_id (RSHIFT_EXPR);
+      op = RSHIFT_EXPR;
       break;
 
     case CPP_LSHIFT_EQ:
-      id = cp_assignment_operator_id (LSHIFT_EXPR);
+      assop = true;
+      op = LSHIFT_EXPR;
       break;
 
     case CPP_RSHIFT_EQ:
-      id = cp_assignment_operator_id (RSHIFT_EXPR);
+      assop = true;
+      op = RSHIFT_EXPR;
       break;
 
     case CPP_EQ_EQ:
-      id = cp_operator_id (EQ_EXPR);
+      op = EQ_EXPR;
       break;
 
     case CPP_NOT_EQ:
-      id = cp_operator_id (NE_EXPR);
+      op = NE_EXPR;
       break;
 
     case CPP_LESS_EQ:
-      id = cp_operator_id (LE_EXPR);
+      op = LE_EXPR;
       break;
 
     case CPP_GREATER_EQ:
-      id = cp_operator_id (GE_EXPR);
+      op = GE_EXPR;
       break;
 
     case CPP_AND_AND:
-      id = cp_operator_id (TRUTH_ANDIF_EXPR);
+      op = TRUTH_ANDIF_EXPR;
       break;
 
     case CPP_OR_OR:
-      id = cp_operator_id (TRUTH_ORIF_EXPR);
+      op = TRUTH_ORIF_EXPR;
       break;
 
     case CPP_PLUS_PLUS:
-      id = cp_operator_id (POSTINCREMENT_EXPR);
+      op = POSTINCREMENT_EXPR;
       break;
 
     case CPP_MINUS_MINUS:
-      id = cp_operator_id (PREDECREMENT_EXPR);
+      op = PREDECREMENT_EXPR;
       break;
 
     case CPP_COMMA:
-      id = cp_operator_id (COMPOUND_EXPR);
+      op = COMPOUND_EXPR;
       break;
 
     case CPP_DEREF_STAR:
-      id = cp_operator_id (MEMBER_REF);
+      op = MEMBER_REF;
       break;
 
     case CPP_DEREF:
-      id = cp_operator_id (COMPONENT_REF);
+      op = COMPONENT_REF;
       break;
 
     case CPP_OPEN_PAREN:
@@ -14907,7 +14914,9 @@ cp_parser_operator (cp_parser* parser)
         parens.consume_open (parser);
         /* Look for the matching `)'.  */
         parens.require_close (parser);
-        return cp_operator_id (CALL_EXPR);
+       op = CALL_EXPR;
+       consumed = true;
+       break;
       }
 
     case CPP_OPEN_SQUARE:
@@ -14915,7 +14924,9 @@ cp_parser_operator (cp_parser* parser)
       cp_lexer_consume_token (parser->lexer);
       /* Look for the matching `]'.  */
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
-      return cp_operator_id (ARRAY_REF);
+      op = ARRAY_REF;
+      consumed = true;
+      break;
 
     case CPP_UTF8STRING:
     case CPP_UTF8STRING_USERDEF:
@@ -14994,8 +15005,12 @@ cp_parser_operator (cp_parser* parser)
 
   /* If we have selected an identifier, we need to consume the
      operator token.  */
-  if (id)
-    cp_lexer_consume_token (parser->lexer);
+  if (op != ERROR_MARK)
+    {
+      id = assop ? cp_assignment_operator_id (op) : cp_operator_id (op);
+      if (!consumed)
+       cp_lexer_consume_token (parser->lexer);
+    }
   /* Otherwise, no valid operator name was present.  */
   else
     {
index 19fbe3c..a7dc418 100644 (file)
@@ -9045,10 +9045,11 @@ check_return_expr (tree retval, bool *no_warning)
        /* You can return a `void' value from a function of `void'
           type.  In that case, we have to evaluate the expression for
           its side-effects.  */
-         finish_expr_stmt (retval);
+       finish_expr_stmt (retval);
       else
-       permerror (input_location, "return-statement with a value, in function "
-                  "returning 'void'");
+       permerror (input_location,
+                  "return-statement with a value, in function "
+                  "returning %qT", valtype);
       current_function_returns_null = 1;
 
       /* There's really no value to return, after all.  */
index 93d2655..ad5d917 100644 (file)
@@ -1,3 +1,8 @@
+2017-10-30  Nathan Sidwell  <nathan@acm.org>
+
+       * g++.dg/other/operator2.C: Adjust diagnostic.
+       * g++.old-deja/g++.jason/operator.C: Likewise.
+
 2017-10-30  Steven Munroe  <munroesj@gcc.gnu.org>
 
        * sse2-check.h: New file.
index 4b952bf..cc68d53 100644 (file)
@@ -3,7 +3,7 @@
 
 struct A
 {
-  operator int&(int);  // { dg-error "void" }
+  operator int&(int);  // { dg-error "no arguments" }
 };
 
 A a;
index 339e6a4..bdcd549 100644 (file)
@@ -9,7 +9,7 @@ struct A {
   static int operator()(int a);           // { dg-error "must be a nonstatic member" }
   static int operator+(A,A);      // { dg-error "either a non-static member" } 
   int operator+(int a, int b = 1); // { dg-error "either zero or one" }
-  int operator++(char);                   // { dg-error "must take 'int'" } 
+  int operator++(char);                   // { dg-error "must have 'int'" }
   void operator delete (void *);   
   void operator delete (void *, unsigned long);        
 };