From ff6304874e9f0c56ef675deb7f71124348fae922 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 30 Oct 2017 19:04:53 +0000 Subject: [PATCH] [C++ PATCH] operator name cleanup prepatch 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 | 15 + gcc/cp/call.c | 7 +- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 573 +++++++++--------- gcc/cp/lex.c | 5 +- gcc/cp/parser.c | 117 ++-- gcc/cp/typeck.c | 7 +- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/other/operator2.C | 2 +- .../g++.old-deja/g++.jason/operator.C | 2 +- 10 files changed, 382 insertions(+), 353 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a4259f14a59..7630638329c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2017-10-30 Nathan Sidwell + + * 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 * pt.c (invalid_nontype_parm_type_p): Return a bool instead of an int. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 8f33ab51690..de3434b3dea 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4565,11 +4565,14 @@ build_op_call_1 (tree obj, vec **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); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f2570b00386..3aefd7e40f4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 519aa06a0f9..0e49e2b6088 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 % as its argument") + : G_("postfix %qD must have % 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 % as its argument", - decl); - else - error ("postfix %qD must take % 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 %", 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; } diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index da9187d6444..ff7160eb3af 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -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)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2337be52c38..c31cd64c026 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 19fbe3c4a4a..a7dc418a0d1 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 93d2655cbcf..ad5d9172a35 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-10-30 Nathan Sidwell + + * g++.dg/other/operator2.C: Adjust diagnostic. + * g++.old-deja/g++.jason/operator.C: Likewise. + 2017-10-30 Steven Munroe * sse2-check.h: New file. diff --git a/gcc/testsuite/g++.dg/other/operator2.C b/gcc/testsuite/g++.dg/other/operator2.C index 4b952bf11eb..cc68d53354e 100644 --- a/gcc/testsuite/g++.dg/other/operator2.C +++ b/gcc/testsuite/g++.dg/other/operator2.C @@ -3,7 +3,7 @@ struct A { - operator int&(int); // { dg-error "void" } + operator int&(int); // { dg-error "no arguments" } }; A a; diff --git a/gcc/testsuite/g++.old-deja/g++.jason/operator.C b/gcc/testsuite/g++.old-deja/g++.jason/operator.C index 339e6a447b4..bdcd5493a97 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/operator.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/operator.C @@ -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); }; -- 2.30.2