[PATCH v2] c++: Implement -Wvexing-parse [PR25814]
Jason Merrill
jason@redhat.com
Fri Oct 30 20:33:48 GMT 2020
On 10/29/20 11:00 PM, Marek Polacek wrote:
> On Thu, Oct 29, 2020 at 02:25:33PM -0400, Jason Merrill via Gcc-patches wrote:
>> On 10/29/20 2:11 PM, Marek Polacek wrote:
>>> On Thu, Oct 29, 2020 at 11:17:37AM -0400, Jason Merrill via Gcc-patches wrote:
>>>> On 10/28/20 7:40 PM, Marek Polacek wrote:
>>>>> On Wed, Oct 28, 2020 at 03:09:08PM -0400, Jason Merrill wrote:
>>>>>> On 10/28/20 1:58 PM, Marek Polacek wrote:
>>>>>>> On Wed, Oct 28, 2020 at 01:26:53AM -0400, Jason Merrill via Gcc-patches wrote:
>>>>>>>> On 10/24/20 7:40 PM, Marek Polacek wrote:
>>>>>>>>> On Fri, Oct 23, 2020 at 09:33:38PM -0400, Jason Merrill via Gcc-patches wrote:
>>>>>>>>>> On 10/23/20 3:01 PM, Marek Polacek wrote:
>>>>>>>>>>> This patch implements the -Wvexing-parse warning to warn about the
>>>>>>>>>>> sneaky most vexing parse rule in C++: the cases when a declaration
>>>>>>>>>>> looks like a variable definition, but the C++ language requires it
>>>>>>>>>>> to be interpreted as a function declaration. This warning is on by
>>>>>>>>>>> default (like clang++). From the docs:
>>>>>>>>>>>
>>>>>>>>>>> void f(double a) {
>>>>>>>>>>> int i(); // extern int i (void);
>>>>>>>>>>> int n(int(a)); // extern int n (int);
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> Another example:
>>>>>>>>>>>
>>>>>>>>>>> struct S { S(int); };
>>>>>>>>>>> void f(double a) {
>>>>>>>>>>> S x(int(a)); // extern struct S x (int);
>>>>>>>>>>> S y(int()); // extern struct S y (int (*) (void));
>>>>>>>>>>> S z(); // extern struct S z (void);
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> You can find more on this in [dcl.ambig.res].
>>>>>>>>>>>
>>>>>>>>>>> I spent a fair amount of time on fix-it hints so that GCC can recommend
>>>>>>>>>>> various ways to resolve such an ambiguity. Sometimes that's tricky.
>>>>>>>>>>> E.g., suggesting default-initialization when the class doesn't have
>>>>>>>>>>> a default constructor would not be optimal. Suggesting {}-init is also
>>>>>>>>>>> not trivial because it can use an initializer-list constructor if no
>>>>>>>>>>> default constructor is available (which ()-init wouldn't do). And of
>>>>>>>>>>> course, pre-C++11, we shouldn't be recommending {}-init at all.
>>>>>>>>>>
>>>>>>>>>> What do you think of, instead of passing the type down into the declarator
>>>>>>>>>> parse, adding the paren locations to cp_declarator::function and giving the
>>>>>>>>>> diagnostic from cp_parser_init_declarator instead?
>>>>>>>>
>>>>>>>> Oops, now I see there's already cp_declarator::parenthesized; might as well
>>>>>>>> reuse that. And maybe change it to a range, while we're at it.
>>>>>>>
>>>>>>> I'm afraid I can't reuse it because grokdeclarator uses it to warn about
>>>>>>> "unnecessary parentheses in declaration". So when we have:
>>>>>>>
>>>>>>> int (x());
>>>>>>>
>>>>>>> declarator->parenthesized points to the outer parens (if any), whereas
>>>>>>> declarator->u.function.parens_loc should point to the inner ones. We also
>>>>>>> have declarator->id_loc but I think we should only use it for declarator-ids.
>>>>>>
>>>>>> Makes sense.
>>>>>>
>>>>>>> (We should still adjust ->parenthesized to be a range to generate a better
>>>>>>> diagnostic; I shall send a patch soon.)
>>>>>>>
>>>>>>>> Hmm, I wonder why we have the parenthesized_p parameter to some of these
>>>>>>>> functions, since we can look at the declarator to find that information...
>>>>>>>
>>>>>>> That would be a nice cleanup.
>>>>>>>
>>>>>>>>> Interesting idea. I suppose it's better, and makes the implementation
>>>>>>>>> more localized. The approach here is that if the .function.parens_loc
>>>>>>>>> is UNKNOWN_LOCATION, we've not seen a vexing parse.
>>>>>>>>
>>>>>>>> I'd rather always set the parens location, and then analyze the
>>>>>>>> cp_declarator in warn_about_ambiguous_parse to see if it's a vexing parse;
>>>>>>>> we should have all the information we need.
>>>>>>>
>>>>>>> I could always set .parens_loc, but then I'd still need another flag telling
>>>>>>> me whether we had an ambiguity. Otherwise I don't know how I would tell
>>>>>>> apart e.g. "int f()" (warn) v. "int f(void)" (don't warn), etc.
>>>>>>
>>>>>> Ah, I was thinking that we still had the parameter declarators, but now I
>>>>>> see that cp_parser_parameter_declaration_list groks them and returns a
>>>>>> TREE_LIST. We could set a TREE_LANG_FLAG on each TREE_LIST if its parameter
>>>>>> declarator was parenthesized?
>>>>>
>>>>> I think so, looks like we have a bunch of free TREE_LANG_FLAG slots on
>>>>> a TREE_LIST. But cp_parser_parameter_declaration_clause can return
>>>>> a void_list_node, so I assume I'd have to copy_node it before setting
>>>>> some new flag in it. Do you think that'd be fine?
>>>>
>>>> There's no declarator in a void_list_node, so we shouldn't need to set a
>>>> "declarator is parenthesized" flag on it.
>>>
>>> I guess I'm still not clear on how I would distinguish between
>>> int f() and int f(void). When I look at the cdk_function declarator,
>>> all I can see is the .parameters TREE_LIST, which for both cases will
>>> be the same void_list_node, but we should only warn for the former.
>>>
>>> What am I missing?
>>
>> I'm just being dense. You're right that we would need to distinguish those
>> two. Perhaps an explicit_void_parms_node or something like that for during
>> parsing; it looks like grokparms will turn it into void_list_node as other
>> code expects.
>
> Gotcha. Now we do most of the work in warn_about_ambiguous_parse.
Thanks, just a few tweaks left.
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>
> -- >8 --
> This patch implements the -Wvexing-parse warning to warn about the
> sneaky most vexing parse rule in C++: the cases when a declaration
> looks like a variable definition, but the C++ language requires it
> to be interpreted as a function declaration. This warning is on by
> default (like clang++). From the docs:
>
> void f(double a) {
> int i(); // extern int i (void);
> int n(int(a)); // extern int n (int);
> }
>
> Another example:
>
> struct S { S(int); };
> void f(double a) {
> S x(int(a)); // extern struct S x (int);
> S y(int()); // extern struct S y (int (*) (void));
> S z(); // extern struct S z (void);
> }
>
> You can find more on this in [dcl.ambig.res].
>
> I spent a fair amount of time on fix-it hints so that GCC can recommend
> various ways to resolve such an ambiguity. Sometimes that's tricky.
> E.g., suggesting default-initialization when the class doesn't have
> a default constructor would not be optimal. Suggesting {}-init is also
> not trivial because it can use an initializer-list constructor if no
> default constructor is available (which ()-init wouldn't do). And of
> course, pre-C++11, we shouldn't be recommending {}-init at all.
>
> I also uncovered a bug in cp_parser_declarator, where we were setting
> *parenthesized_p to true despite the comment saying the exact opposite.
>
> gcc/c-family/ChangeLog:
>
> PR c++/25814
> * c.opt (Wvexing-parse): New option.
>
> gcc/cp/ChangeLog:
>
> PR c++/25814
> * cp-tree.h (enum cp_tree_index): Add CPTI_EXPLICIT_VOID_LIST.
> (explicit_void_list_node): Define.
> (PARENTHESIZED_LIST_P): New macro.
> (struct cp_declarator): Add function::parens_loc.
> * decl.c (cxx_init_decl_processing): Initialize explicit_void_list_node.
> (grokparms): Also break when explicit_void_list_node.
> * parser.c (make_call_declarator): New location_t parameter. Use it
> to set declarator->u.function.parens_loc.
> (cp_parser_lambda_declarator_opt): Pass UNKNOWN_LOCATION to
> make_call_declarator.
> (warn_about_ambiguous_parse): New function.
> (cp_parser_init_declarator): Call warn_about_ambiguous_parse.
> (cp_parser_declarator): Set *parenthesized_p to false rather than to
> true.
> (cp_parser_direct_declarator): Create a location for the function's
> parentheses and pass it to make_call_declarator.
> (cp_parser_parameter_declaration_clause): Return explicit_void_list_node
> for (void).
> (cp_parser_parameter_declaration_list): Set PARENTHESIZED_LIST_P
> in the parameters tree.
>
> gcc/ChangeLog:
>
> PR c++/25814
> * doc/invoke.texi: Document -Wvexing-parse.
>
> gcc/testsuite/ChangeLog:
>
> PR c++/25814
> * g++.dg/cpp2a/fn-template16.C: Add a dg-warning.
> * g++.dg/cpp2a/fn-template7.C: Likewise.
> * g++.dg/lookup/pr80891-5.C: Likewise.
> * g++.dg/lto/pr79050_0.C: Add extern.
> * g++.dg/lto/pr84805_0.C: Likewise.
> * g++.dg/parse/pr58898.C: Add a dg-warning.
> * g++.dg/template/scope5.C: Likewise.
> * g++.old-deja/g++.brendan/recurse.C: Likewise.
> * g++.old-deja/g++.jason/template4.C: Likewise.
> * g++.old-deja/g++.law/arm4.C: Likewise.
> * g++.old-deja/g++.mike/for2.C: Likewise.
> * g++.old-deja/g++.other/local4.C: Likewise.
> * g++.old-deja/g++.pt/crash3.C: Likewise.
> * g++.dg/warn/Wvexing-parse.C: New test.
> * g++.dg/warn/Wvexing-parse2.C: New test.
> * g++.dg/warn/Wvexing-parse3.C: New test.
> * g++.dg/warn/Wvexing-parse4.C: New test.
> * g++.dg/warn/Wvexing-parse5.C: New test.
> * g++.dg/warn/Wvexing-parse6.C: New test.
>
> libstdc++-v3/ChangeLog:
>
> PR c++/25814
> * testsuite/20_util/reference_wrapper/lwg2993.cc: Add a dg-warning.
> * testsuite/25_algorithms/generate_n/87982_neg.cc: Likewise.
> ---
> gcc/c-family/c.opt | 4 +
> gcc/cp/cp-tree.h | 8 +
> gcc/cp/decl.c | 5 +-
> gcc/cp/parser.c | 144 +++++++++++++++++-
> gcc/doc/invoke.texi | 34 ++++-
> gcc/testsuite/g++.dg/cpp2a/fn-template16.C | 2 +-
> gcc/testsuite/g++.dg/cpp2a/fn-template7.C | 2 +-
> gcc/testsuite/g++.dg/lookup/pr80891-5.C | 2 +-
> gcc/testsuite/g++.dg/lto/pr79050_0.C | 2 +-
> gcc/testsuite/g++.dg/lto/pr84805_0.C | 2 +-
> gcc/testsuite/g++.dg/parse/pr58898.C | 4 +-
> gcc/testsuite/g++.dg/template/scope5.C | 2 +-
> gcc/testsuite/g++.dg/warn/Wvexing-parse.C | 110 +++++++++++++
> gcc/testsuite/g++.dg/warn/Wvexing-parse2.C | 24 +++
> gcc/testsuite/g++.dg/warn/Wvexing-parse3.C | 129 ++++++++++++++++
> gcc/testsuite/g++.dg/warn/Wvexing-parse4.C | 74 +++++++++
> gcc/testsuite/g++.dg/warn/Wvexing-parse5.C | 14 ++
> gcc/testsuite/g++.dg/warn/Wvexing-parse6.C | 24 +++
> .../g++.old-deja/g++.brendan/recurse.C | 2 +-
> .../g++.old-deja/g++.jason/template4.C | 2 +-
> gcc/testsuite/g++.old-deja/g++.law/arm4.C | 2 +-
> gcc/testsuite/g++.old-deja/g++.mike/for2.C | 2 +-
> gcc/testsuite/g++.old-deja/g++.other/local4.C | 2 +-
> gcc/testsuite/g++.old-deja/g++.pt/crash3.C | 2 +
> .../20_util/reference_wrapper/lwg2993.cc | 2 +-
> .../25_algorithms/generate_n/87982_neg.cc | 2 +-
> 26 files changed, 578 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse.C
> create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse2.C
> create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse3.C
> create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse4.C
> create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse5.C
> create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse6.C
>
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 10e53ea67c9..0991094e34d 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1274,6 +1274,10 @@ Wvarargs
> C ObjC C++ ObjC++ Warning Var(warn_varargs) Init(1)
> Warn about questionable usage of the macros used to retrieve variable arguments.
>
> +Wvexing-parse
> +C++ ObjC++ Warning Var(warn_vexing_parse) Init(1)
> +Warn about the most vexing parse syntactic ambiguity.
> +
> Wvla
> C ObjC C++ ObjC++ Var(warn_vla) Init(-1) Warning
> Warn if a variable length array is used.
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index fdb8ee57f0b..b044098277c 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -125,6 +125,7 @@ enum cp_tree_index
> CPTI_CLASS_TYPE,
> CPTI_UNKNOWN_TYPE,
> CPTI_INIT_LIST_TYPE,
> + CPTI_EXPLICIT_VOID_LIST,
> CPTI_VTBL_TYPE,
> CPTI_VTBL_PTR_TYPE,
> CPTI_STD,
> @@ -232,6 +233,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
> #define class_type_node cp_global_trees[CPTI_CLASS_TYPE]
> #define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE]
> #define init_list_type_node cp_global_trees[CPTI_INIT_LIST_TYPE]
> +#define explicit_void_list_node cp_global_trees[CPTI_EXPLICIT_VOID_LIST]
> #define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE]
> #define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE]
> #define std_node cp_global_trees[CPTI_STD]
> @@ -413,6 +415,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
> ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
> ABI_TAG_IMPLICIT (in the TREE_LIST for the argument of abi_tag)
> LAMBDA_CAPTURE_EXPLICIT_P (in a TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST)
> + PARENTHESIZED_LIST_P (in the TREE_LIST for a parameter-declaration-list)
> CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR)
> LAMBDA_EXPR_CAPTURES_THIS_P (in LAMBDA_EXPR)
> DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE)
> @@ -3395,6 +3398,10 @@ struct GTY(()) lang_decl {
> was inherited from a template parameter, not explicitly indicated. */
> #define ABI_TAG_IMPLICIT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
>
> +/* In a TREE_LIST for a parameter-declaration-list, indicates that this
> + list was enclosed in (). */
> +#define PARENTHESIZED_LIST_P(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
> +
> /* Non zero if this is a using decl for a dependent scope. */
> #define DECL_DEPENDENT_P(NODE) DECL_LANG_FLAG_0 (USING_DECL_CHECK (NODE))
>
> @@ -6051,6 +6058,7 @@ struct cp_declarator {
> tree late_return_type;
> /* The trailing requires-clause, if any. */
> tree requires_clause;
> + location_t parens_loc;
> } function;
> /* For arrays. */
> struct {
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 39f56b81275..81666fecfcb 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -4378,6 +4378,9 @@ cxx_init_decl_processing (void)
> init_list_type_node = make_node (LANG_TYPE);
> record_unknown_type (init_list_type_node, "init list");
>
> + /* Used when parsing to distinguish parameter-lists () and (void). */
> + explicit_void_list_node = build_void_list_node ();
> +
> {
> /* Make sure we get a unique function type, so we can give
> its pointer type a name. (This wins for gdb.) */
> @@ -14033,7 +14036,7 @@ grokparms (tree parmlist, tree *parms)
> tree init = TREE_PURPOSE (parm);
> tree decl = TREE_VALUE (parm);
>
> - if (parm == void_list_node)
> + if (parm == void_list_node || parm == explicit_void_list_node)
> break;
Is this hunk needed? I thought explicit_void_type_node would be handled
by the if (VOID_TYPE_P) block below.
> if (! decl || TREE_TYPE (decl) == error_mark_node)
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index bd8c241dd82..00a419032af 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -1438,7 +1438,8 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
> VAR_DECLs or FUNCTION_DECLs) should do that directly. */
>
> static cp_declarator *make_call_declarator
> - (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree, tree, tree);
> + (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier,
> + tree, tree, tree, tree, location_t);
> static cp_declarator *make_array_declarator
> (cp_declarator *, tree);
> static cp_declarator *make_pointer_declarator
> @@ -1621,7 +1622,8 @@ make_call_declarator (cp_declarator *target,
> tree tx_qualifier,
> tree exception_specification,
> tree late_return_type,
> - tree requires_clause)
> + tree requires_clause,
> + location_t parens_loc)
> {
> cp_declarator *declarator;
>
> @@ -1635,6 +1637,7 @@ make_call_declarator (cp_declarator *target,
> declarator->u.function.exception_specification = exception_specification;
> declarator->u.function.late_return_type = late_return_type;
> declarator->u.function.requires_clause = requires_clause;
> + declarator->u.function.parens_loc = parens_loc;
> if (target)
> {
> declarator->id_loc = target->id_loc;
> @@ -11246,7 +11249,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
> tx_qual,
> exception_spec,
> return_type,
> - trailing_requires_clause);
> + trailing_requires_clause,
> + UNKNOWN_LOCATION);
> declarator->std_attributes = std_attrs;
>
> fco = grokmethod (&return_type_specs,
> @@ -20613,6 +20617,112 @@ strip_declarator_types (tree type, cp_declarator *declarator)
> return type;
> }
>
> +/* Warn about the most vexing parse syntactic ambiguity, i.e., warn when
> + a construct looks like a variable definition but is actually a function
> + declaration. TYPE is the return type of such a function; DECLARATOR is
> + the declarator for this function declaration. */
> +
> +static void
> +warn_about_ambiguous_parse (tree type, const cp_declarator *declarator)
> +{
> + if (declarator->kind != cdk_function
> + || !declarator->declarator
> + || declarator->declarator->kind != cdk_id
> + || !identifier_p (get_unqualified_id
> + (const_cast<cp_declarator *>(declarator))))
> + return;
> +
> + /* Don't warn when the whole declarator (not just the declarator-id!)
> + was parenthesized. That is, don't warn for int(n()) but do warn
> + for int(f)(). */
> + if (declarator->parenthesized != UNKNOWN_LOCATION)
> + return;
> +
> + location_t loc = declarator->u.function.parens_loc;
> + if (loc == UNKNOWN_LOCATION)
> + return;
Is this still possible?
> + if (TREE_CODE (type) == TYPE_DECL)
> + type = TREE_TYPE (type);
> +
> + /* If the return type is void there is no ambiguity. */
> + if (same_type_p (type, void_type_node))
> + return;
> +
> + auto_diagnostic_group d;
> + tree params = declarator->u.function.parameters;
> + const bool has_list_ctor_p = CLASS_TYPE_P (type) && TYPE_HAS_LIST_CTOR (type);
> +
> + /* The T t() case. */
> + if (params == void_list_node)
> + {
> + if (warning_at (loc, OPT_Wvexing_parse,
> + "empty parentheses were disambiguated as a function "
> + "declaration"))
> + {
> + /* () means value-initialization (C++03 and up); {} (C++11 and up)
> + means value-initialization or aggregate--initialization, nothing
> + means default-initialization. We can only suggest removing the
> + parentheses/adding {} if T has a default constructor. */
> + if (!CLASS_TYPE_P (type) || TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
> + {
> + gcc_rich_location iloc (loc);
> + iloc.add_fixit_remove ();
> + inform (&iloc, "remove parentheses to default-initialize "
> + "a variable");
> + if (cxx_dialect >= cxx11 && !has_list_ctor_p)
> + {
> + if (CP_AGGREGATE_TYPE_P (type))
> + inform (loc, "or replace parentheses with braces to "
> + "aggregate-initialize a variable");
> + else
> + inform (loc, "or replace parentheses with braces to "
> + "value-initialize a variable");
> + }
> + }
> + }
> + return;
> + }
> +
> + /* If we had (...) or the parameter-list wasn't parenthesized,
> + we're done. */
> + if (params == NULL_TREE || !PARENTHESIZED_LIST_P (params))
> + return;
This needs to be a loop so we check all the elements of the list.
> + /* The T t(X()) case. */
> + if (list_length (params) == 2)
> + {
> + if (warning_at (loc, OPT_Wvexing_parse,
> + "parentheses were disambiguated as a function "
> + "declaration"))
> + {
> + gcc_rich_location iloc (loc);
> + /* {}-initialization means that we can use an initializer-list
> + constructor if no default constructor is available, so don't
> + suggest using {} for classes that have an initializer_list
> + constructor. */
> + if (cxx_dialect >= cxx11 && !has_list_ctor_p)
> + {
> + iloc.add_fixit_replace (get_start (loc), "{");
> + iloc.add_fixit_replace (get_finish (loc), "}");
> + inform (&iloc, "replace parentheses with braces to declare a "
> + "variable");
> + }
> + else
> + {
> + iloc.add_fixit_insert_after (get_start (loc), "(");
> + iloc.add_fixit_insert_before (get_finish (loc), ")");
> + inform (&iloc, "add parentheses to declare a variable");
> + }
> + }
> + }
> + /* The T t(X(), X()) case. */
> + else
> + warning_at (loc, OPT_Wvexing_parse,
> + "parentheses were disambiguated as a function "
> + "declaration");
> +}
Why not suggest braces for this case?
> +
> /* Declarators [gram.dcl.decl] */
>
> /* Parse an init-declarator.
> @@ -20807,6 +20917,13 @@ cp_parser_init_declarator (cp_parser* parser,
> }
> }
>
> + if (decl_specifiers->storage_class == sc_none
> + && at_function_scope_p ()
> + && !member_p
> + && !decl_spec_seq_has_spec_p (decl_specifiers, ds_typedef)
> + && !cp_parser_error_occurred (parser))
> + warn_about_ambiguous_parse (decl_specifiers->type, declarator);
Maybe pass decl_specifiers into warn_about_ambiguous_parse and move the
specifiers checks into the function?
> /* Check to see if the token indicates the start of a
> function-definition. */
> if (cp_parser_token_starts_function_definition_p (token))
> @@ -21201,7 +21318,7 @@ cp_parser_declarator (cp_parser* parser,
> /* If a ptr-operator was found, then this declarator was not
> parenthesized. */
> if (parenthesized_p)
> - *parenthesized_p = true;
> + *parenthesized_p = false;
> /* The dependent declarator is optional if we are parsing an
> abstract-declarator. */
> if (dcl_kind != CP_PARSER_DECLARATOR_NAMED)
> @@ -21348,6 +21465,7 @@ cp_parser_direct_declarator (cp_parser* parser,
> cp_parser_parse_tentatively (parser);
>
> /* Consume the `('. */
> + const location_t parens_start = token->location;
> matching_parens parens;
> parens.consume_open (parser);
> if (first)
> @@ -21367,6 +21485,8 @@ cp_parser_direct_declarator (cp_parser* parser,
> /* Parse the parameter-declaration-clause. */
> params
> = cp_parser_parameter_declaration_clause (parser, flags);
> + const location_t parens_end
> + = cp_lexer_peek_token (parser->lexer)->location;
>
> /* Consume the `)'. */
> parens.require_close (parser);
> @@ -21431,6 +21551,9 @@ cp_parser_direct_declarator (cp_parser* parser,
> /* Parse the virt-specifier-seq. */
> virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
>
> + location_t parens_loc = make_location (parens_start,
> + parens_start,
> + parens_end);
> /* Create the function-declarator. */
> declarator = make_call_declarator (declarator,
> params,
> @@ -21440,7 +21563,8 @@ cp_parser_direct_declarator (cp_parser* parser,
> tx_qual,
> exception_specification,
> late_return,
> - requires_clause);
> + requires_clause,
> + parens_loc);
> declarator->std_attributes = attrs;
> declarator->attributes = gnu_attrs;
> /* Any subsequent parameter lists are to do with
> @@ -22707,7 +22831,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser,
> /* Consume the `void' token. */
> cp_lexer_consume_token (parser->lexer);
> /* There are no parameters. */
> - return void_list_node;
> + return explicit_void_list_node;
> }
>
> /* Parse the parameter-declaration-list. */
> @@ -22838,7 +22962,13 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags)
> || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
> || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
> /* The parameter-declaration-list is complete. */
> - break;
> + {
> + /* If the parameters were parenthesized, it's the case of
> + T foo(X(x)) which looks like a variable definition but
> + is a function declaration. */
> + PARENTHESIZED_LIST_P (parameters) = parenthesized_p;
> + break;
> + }
> else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
> {
> cp_token *token;
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 79d479c72b7..bab6c2c4454 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -253,7 +253,8 @@ in the following sections.
> -Woverloaded-virtual -Wno-pmf-conversions -Wsign-promo @gol
> -Wsized-deallocation -Wsuggest-final-methods @gol
> -Wsuggest-final-types -Wsuggest-override @gol
> --Wno-terminate -Wuseless-cast -Wvirtual-inheritance @gol
> +-Wno-terminate -Wuseless-cast -Wno-vexing-parse @gol
> +-Wvirtual-inheritance @gol
> -Wno-virtual-move-assign -Wvolatile -Wzero-as-null-pointer-constant}
>
> @item Objective-C and Objective-C++ Language Options
> @@ -3886,6 +3887,37 @@ use the STL. One may also use using directives and qualified names.
> Disable the warning about a throw-expression that will immediately
> result in a call to @code{terminate}.
>
> +@item -Wno-vexing-parse @r{(C++ and Objective-C++ only)}
> +@opindex Wvexing-parse
> +@opindex Wno-vexing-parse
> +Warn about the most vexing parse syntactic ambiguity. This warns about
> +the cases when a declaration looks like a variable definition, but the
> +C++ language requires it to be interpreted as a function declaration.
> +For instance:
> +
> +@smallexample
> +void f(double a) @{
> + int i(); // extern int i (void);
> + int n(int(a)); // extern int n (int);
> +@}
> +@end smallexample
> +
> +Another example:
> +
> +@smallexample
> +struct S @{ S(int); @};
> +void f(double a) @{
> + S x(int(a)); // extern struct S x (int);
> + S y(int()); // extern struct S y (int (*) (void));
> + S z(); // extern struct S z (void);
> +@}
> +@end smallexample
> +
> +The warning will suggest options how to deal with such an ambiguity; e.g.,
> +it can suggest removing the parentheses or using braces instead.
> +
> +This warning is enabled by default.
> +
> @item -Wno-class-conversion @r{(C++ and Objective-C++ only)}
> @opindex Wno-class-conversion
> @opindex Wclass-conversion
> diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template16.C b/gcc/testsuite/g++.dg/cpp2a/fn-template16.C
> index becaff1e3fb..8ee783ad577 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/fn-template16.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template16.C
> @@ -7,7 +7,7 @@ struct undeclared<int> { }; // { dg-error "not a class template" }
> int
> main ()
> {
> - int foo ();
> + int foo (); // { dg-warning "empty parentheses" }
> int foo (int);
> int foo (int, int);
> int a, b = 10;
> diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template7.C b/gcc/testsuite/g++.dg/cpp2a/fn-template7.C
> index d048606c0d6..2c5ee120dcd 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/fn-template7.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template7.C
> @@ -7,7 +7,7 @@ struct undeclared<int> { }; // { dg-error "not a class template" }
> int
> main ()
> {
> - int foo ();
> + int foo (); // { dg-warning "empty parentheses" }
> int a, b = 10;
> a = foo<; // { dg-error "invalid template-argument-list|invalid" }
> a = foo < b; // { dg-error "invalid template-argument-list|invalid" }
> diff --git a/gcc/testsuite/g++.dg/lookup/pr80891-5.C b/gcc/testsuite/g++.dg/lookup/pr80891-5.C
> index e018922d68b..10d1ce3f3d5 100644
> --- a/gcc/testsuite/g++.dg/lookup/pr80891-5.C
> +++ b/gcc/testsuite/g++.dg/lookup/pr80891-5.C
> @@ -14,7 +14,7 @@ template <typename, typename, typename, typename,
> struct B {
> B(A, A, int, int, int, int);
> void m_fn1(SubGraphIsoMapCallback p1) {
> - __normal_iterator __trans_tmp_1();
> + __normal_iterator __trans_tmp_1(); // { dg-warning "empty parentheses" }
> p1(__trans_tmp_1, 0);
> }
> };
> diff --git a/gcc/testsuite/g++.dg/lto/pr79050_0.C b/gcc/testsuite/g++.dg/lto/pr79050_0.C
> index 1f31b5d0020..464f5594769 100644
> --- a/gcc/testsuite/g++.dg/lto/pr79050_0.C
> +++ b/gcc/testsuite/g++.dg/lto/pr79050_0.C
> @@ -3,5 +3,5 @@
>
> int main ()
> {
> - auto foo ();
> + extern auto foo ();
> }
> diff --git a/gcc/testsuite/g++.dg/lto/pr84805_0.C b/gcc/testsuite/g++.dg/lto/pr84805_0.C
> index 1509eae4845..668ba362aed 100644
> --- a/gcc/testsuite/g++.dg/lto/pr84805_0.C
> +++ b/gcc/testsuite/g++.dg/lto/pr84805_0.C
> @@ -149,5 +149,5 @@ public:
> class XclImpRoot : XclRoot {};
> class XclImpColRowSettings : XclImpRoot {};
> void lcl_ExportExcelBiff() {
> -XclRootData aExpData();
> +extern XclRootData aExpData();
> }
> diff --git a/gcc/testsuite/g++.dg/parse/pr58898.C b/gcc/testsuite/g++.dg/parse/pr58898.C
> index e788c913c66..e67011d2fe7 100644
> --- a/gcc/testsuite/g++.dg/parse/pr58898.C
> +++ b/gcc/testsuite/g++.dg/parse/pr58898.C
> @@ -5,12 +5,12 @@ struct Foo
> {
> Foo()
> {
> - int t(int()); // Error
> + int t(int()); // { dg-warning "parentheses were disambiguated" }
> }
> };
>
> int main()
> {
> - int t(int()); // OK
> + int t(int()); // { dg-warning "parentheses were disambiguated" }
> Foo<> a; // Error
> }
> diff --git a/gcc/testsuite/g++.dg/template/scope5.C b/gcc/testsuite/g++.dg/template/scope5.C
> index cf23a0837bd..b20d897b49f 100644
> --- a/gcc/testsuite/g++.dg/template/scope5.C
> +++ b/gcc/testsuite/g++.dg/template/scope5.C
> @@ -59,7 +59,7 @@ template <typename av> struct ac : ao<av> { typedef c::e<am::an> aq; };
> template <typename aw, typename i, typename ax> void ay(aw, i, ax) {
> // Not sure if this has been creduced from an initialization of a
> // variable to a block-scope extern function decl
> - au<c::e<ap<typename ak<i>::o>::f> > az2();
> + au<c::e<ap<typename ak<i>::o>::f> > az2(); // { dg-warning "empty parentheses" }
> }
> void v() {
> ad a;
> diff --git a/gcc/testsuite/g++.dg/warn/Wvexing-parse.C b/gcc/testsuite/g++.dg/warn/Wvexing-parse.C
> new file mode 100644
> index 00000000000..b02e904fa83
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse.C
> @@ -0,0 +1,110 @@
> +// PR c++/25814
> +// { dg-do compile }
> +// Test -Wvexing-parse.
> +
> +struct T { };
> +
> +struct X {
> + X();
> +};
> +
> +struct S {
> + S(int);
> + S foo (int (int));
> + S(T);
> + int m;
> +};
> +
> +struct W {
> + W();
> + W(X, X);
> + int m;
> +};
> +
> +int g;
> +int g1(int(g));
> +int g2(int());
> +void fg(int);
> +
> +void
> +fn1 (double (a))
> +{
> + extern int f0();
> + extern int f1(int(a));
> + int f2(int(a)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + int (*f3)(int(a));
> + int f4(int a);
> + int f5(int()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + int f6(...);
> + int f7((int(a)));
> + int (f8);
> + int f9(S(s)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + int(f10) __attribute__(());
> + int(f11(int()));
> + if (int(a) = 1) { }
> + int j, k, l(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + int m, f12(int(j)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> +
> + T t1(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + T t2(T()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + /* Declares a variable t3. */
> + T(t3);
> + T t4(), // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + t5(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> +
> + extern S s1(int(a));
> + S s2(int(a)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + S s3(int a);
> + S s4(int()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + S s5(int(int)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + S s6(...);
> + S s7((int(a)));
> + S s8((int)a);
> + S s9 = int(a);
> + S(T());
> + S s10(S()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + S s11(T());
> + S s12(X()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + S s13 = S(T());
> + S(T()).foo(0);
> + S (S::*foo)(int (int));
> + S(*s14)(int(a));
> + S s15(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + S s16(void);
> +
> + /* Don't warn here. */
> + void fv1(int(a));
> + void fv2(int());
> + void (fv3)();
> + void (fv4)(void);
> + void (fv5)(int);
> +
> + int n(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + int (n2)(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + int n3(void);
> +
> + typedef int F(const char*);
> + typedef int F2();
> + typedef int F3() const;
> + typedef int F4(int(a)) const;
> +
> + W w(X(), X()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> +}
> +
> +struct C1 {
> + C1(int);
> +};
> +
> +struct C2 {
> + C2(C1, int);
> +};
> +
> +template<int N> int value() { return N; }
> +
> +void
> +fn2 ()
> +{
> + int i = 0;
> + C2 c2(C1(int(i)), i);
> + C1(value<0>());
> +}
> diff --git a/gcc/testsuite/g++.dg/warn/Wvexing-parse2.C b/gcc/testsuite/g++.dg/warn/Wvexing-parse2.C
> new file mode 100644
> index 00000000000..0dbeb7255cc
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse2.C
> @@ -0,0 +1,24 @@
> +// PR c++/25814
> +// { dg-do compile { target c++11 } }
> +// Test -Wvexing-parse. C++11 features.
> +
> +struct X { };
> +struct T {
> + T(X);
> +};
> +
> +void
> +fn1 (double (a))
> +{
> + auto l = [](){
> + int f(int(a)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + };
> +
> + [[noreturn]] int(e)(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> +
> + T t1{X()};
> + T t2(X{});
> + T t3{X{}};
> +
> + using U = int();
> +}
> diff --git a/gcc/testsuite/g++.dg/warn/Wvexing-parse3.C b/gcc/testsuite/g++.dg/warn/Wvexing-parse3.C
> new file mode 100644
> index 00000000000..43fcdf29f61
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse3.C
> @@ -0,0 +1,129 @@
> +// PR c++/25814
> +// { dg-do compile { target c++11 } }
> +// { dg-additional-options "-fdiagnostics-show-caret" }
> +// Test -Wvexing-parse's fix-it hints in C++11.
> +
> +#include <initializer_list>
> +
> +struct X { };
> +
> +struct S {
> + S(X);
> + S(std::initializer_list<X>);
> + int m;
> +};
> +
> +struct T {
> + T(X);
> + int m;
> +};
> +
> +struct W {
> + W();
> + W(std::initializer_list<X>);
> + int m;
> +};
> +
> +struct U {
> + U();
> + int m;
> +};
> +
> +int
> +main ()
> +{
> + /*
> + Careful what we're suggesting:
> + S a((X())) -> S(X)
> + S a({X()}) -> (std::initializer_list<X>)
> + S a{X()} -> (std::initializer_list<X>)
> + */
> + S a(X()); // { dg-warning "6:parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + S a(X());
> + ^~~~~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:add parentheses to declare a variable" "" { target *-*-* } 41 }
> + /* { dg-begin-multiline-output "" }
> + S a(X());
> + ^~~~~
> + ( )
> + { dg-end-multiline-output "" } */
> +
> + T t(X()); // { dg-warning "6:parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + T t(X());
> + ^~~~~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:replace parentheses with braces to declare a variable" "" { target *-*-* } 53 }
> + /* { dg-begin-multiline-output "" }
> + T t(X());
> + ^~~~~
> + -
> + { -
> + }
> + { dg-end-multiline-output "" } */
> +
> + int n( ); // { dg-warning "8:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + int n( );
> + ^~~~~
> + { dg-end-multiline-output "" } */
> + // { dg-message "8:remove parentheses to default-initialize a variable" "" { target *-*-* } 67 }
> + /* { dg-begin-multiline-output "" }
> + int n( );
> + ^~~~~
> + -----
> + { dg-end-multiline-output "" } */
> + // { dg-message "8:or replace parentheses with braces to value-initialize a variable" "" { target *-*-* } 67 }
> +
> + S s(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + S s();
> + ^~
> + { dg-end-multiline-output "" } */
> +
> + X x(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + X x();
> + ^~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:remove parentheses to default-initialize a variable" "" { target *-*-* } 86 }
> + /* { dg-begin-multiline-output "" }
> + X x();
> + ^~
> + --
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:or replace parentheses with braces to aggregate-initialize a variable" "" { target *-*-* } 86 }
> +
> + W w(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + W w();
> + ^~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:remove parentheses to default-initialize a variable" "" { target *-*-* } 99 }
> + /* { dg-begin-multiline-output "" }
> + W w();
> + ^~
> + --
> + { dg-end-multiline-output "" } */
> +
> + T t2(); // { dg-warning "7:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + T t2();
> + ^~
> + { dg-end-multiline-output "" } */
> +
> + U u(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + U u();
> + ^~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:remove parentheses to default-initialize a variable" "" { target *-*-* } 117 }
> + /* { dg-begin-multiline-output "" }
> + U u();
> + ^~
> + --
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:or replace parentheses with braces to value-initialize a variable" "" { target *-*-* } 117 }
> +}
> diff --git a/gcc/testsuite/g++.dg/warn/Wvexing-parse4.C b/gcc/testsuite/g++.dg/warn/Wvexing-parse4.C
> new file mode 100644
> index 00000000000..3e010aaba3d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse4.C
> @@ -0,0 +1,74 @@
> +// PR c++/25814
> +// { dg-do compile { target c++98_only } }
> +// { dg-additional-options "-fdiagnostics-show-caret" }
> +// Test -Wvexing-parse's fix-it hints in C++98.
> +
> +struct X { };
> +
> +struct T {
> + T(X);
> + int m;
> +};
> +
> +struct U {
> + U();
> + int m;
> +};
> +
> +int
> +main ()
> +{
> + T t(X()); // { dg-warning "6:parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + T t(X());
> + ^~~~~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:add parentheses to declare a variable" "" { target *-*-* } 21 }
> + /* { dg-begin-multiline-output "" }
> + T t(X());
> + ^~~~~
> + ( )
> + { dg-end-multiline-output "" } */
> +
> + int n( ); // { dg-warning "8:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + int n( );
> + ^~~~~
> + { dg-end-multiline-output "" } */
> + // { dg-message "8:remove parentheses to default-initialize a variable" "" { target *-*-* } 33 }
> + /* { dg-begin-multiline-output "" }
> + int n( );
> + ^~~~~
> + -----
> + { dg-end-multiline-output "" } */
> +
> + T y(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + T y();
> + ^~
> + { dg-end-multiline-output "" } */
> +
> + X x(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + X x();
> + ^~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:remove parentheses to default-initialize a variable" "" { target *-*-* } 51 }
> + /* { dg-begin-multiline-output "" }
> + X x();
> + ^~
> + --
> + { dg-end-multiline-output "" } */
> +
> + U u(); // { dg-warning "6:empty parentheses were disambiguated as a function declaration" }
> + /* { dg-begin-multiline-output "" }
> + U u();
> + ^~
> + { dg-end-multiline-output "" } */
> + // { dg-message "6:remove parentheses to default-initialize a variable" "" { target *-*-* } 63 }
> + /* { dg-begin-multiline-output "" }
> + U u();
> + ^~
> + --
> + { dg-end-multiline-output "" } */
> +}
> diff --git a/gcc/testsuite/g++.dg/warn/Wvexing-parse5.C b/gcc/testsuite/g++.dg/warn/Wvexing-parse5.C
> new file mode 100644
> index 00000000000..3422e706160
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse5.C
> @@ -0,0 +1,14 @@
> +// PR c++/25814
> +// { dg-do compile }
> +// Test -Wvexing-parse in a template.
> +
> +struct X { };
> +
> +template<typename T>
> +void fn ()
> +{
> + T t(); // { dg-warning "empty parentheses were disambiguated as a function declaration" }
> + T a(X()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + X x(T()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + int i(T()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> +}
> diff --git a/gcc/testsuite/g++.dg/warn/Wvexing-parse6.C b/gcc/testsuite/g++.dg/warn/Wvexing-parse6.C
> new file mode 100644
> index 00000000000..58fa725a2ee
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse6.C
> @@ -0,0 +1,24 @@
> +// PR c++/25814
> +// { dg-do compile }
> +// Test from Wikipedia.
> +
> +class Timer {
> + public:
> + Timer();
> +};
> +
> +class TimeKeeper {
> + public:
> + TimeKeeper(const Timer& t);
> +
> + int get_time();
> +};
> +
> +void f(double adouble) {
> + int i(int(adouble)); // { dg-warning "parentheses were disambiguated as a function declaration" }
> +}
> +
> +int main() {
> + TimeKeeper time_keeper(Timer()); // { dg-warning "parentheses were disambiguated as a function declaration" }
> + return time_keeper.get_time(); // { dg-error "request for member" }
> +}
> diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/recurse.C b/gcc/testsuite/g++.old-deja/g++.brendan/recurse.C
> index de20a073221..0af1c147cd8 100644
> --- a/gcc/testsuite/g++.old-deja/g++.brendan/recurse.C
> +++ b/gcc/testsuite/g++.old-deja/g++.brendan/recurse.C
> @@ -73,7 +73,7 @@ public:
>
> int main()
> {
> - DBpathrec a(), b();
> + DBpathrec a(), b(); // { dg-warning "empty parentheses" }
>
> a = b;// { dg-error "" } non-lvalue in assignment.*
> }
> diff --git a/gcc/testsuite/g++.old-deja/g++.jason/template4.C b/gcc/testsuite/g++.old-deja/g++.jason/template4.C
> index de7d3312a71..1cf5a614411 100644
> --- a/gcc/testsuite/g++.old-deja/g++.jason/template4.C
> +++ b/gcc/testsuite/g++.old-deja/g++.jason/template4.C
> @@ -17,5 +17,5 @@ template <class T>
> ccList <T> cc_List<T>::copy (){}
>
> int main (int, char **) {
> - ccList <int> size1();
> + ccList <int> size1(); // { dg-warning "empty parentheses" }
> }
> diff --git a/gcc/testsuite/g++.old-deja/g++.law/arm4.C b/gcc/testsuite/g++.old-deja/g++.law/arm4.C
> index bbcf7df2391..59492ca952c 100644
> --- a/gcc/testsuite/g++.old-deja/g++.law/arm4.C
> +++ b/gcc/testsuite/g++.old-deja/g++.law/arm4.C
> @@ -20,7 +20,7 @@ int main(void)
> {
> double a = 2.0;
>
> - S x(int (a));
> + S x(int (a)); // { dg-warning "parentheses were disambiguated" }
> if (count > 0)
> { printf ("FAIL\n"); return 1; }
> else
> diff --git a/gcc/testsuite/g++.old-deja/g++.mike/for2.C b/gcc/testsuite/g++.old-deja/g++.mike/for2.C
> index 6eb5d66675e..4a7c3042544 100644
> --- a/gcc/testsuite/g++.old-deja/g++.mike/for2.C
> +++ b/gcc/testsuite/g++.old-deja/g++.mike/for2.C
> @@ -14,7 +14,7 @@ void bar() {
>
> void bee () {
> int i = 0;
> - for (int fun() = 0; i != 2; ++i) { // { dg-warning "extern" "extern" }
> + for (int fun() = 0; i != 2; ++i) { // { dg-warning "extern|empty parentheses" "extern" }
> // { dg-error "initialized" "init" { target *-*-* } .-1 }
> }
> }
> diff --git a/gcc/testsuite/g++.old-deja/g++.other/local4.C b/gcc/testsuite/g++.old-deja/g++.other/local4.C
> index b5514a54b46..492ce2b7e70 100644
> --- a/gcc/testsuite/g++.old-deja/g++.other/local4.C
> +++ b/gcc/testsuite/g++.old-deja/g++.other/local4.C
> @@ -6,6 +6,6 @@ int f (int);
>
> int main ()
> {
> - int f ();
> + int f (); // { dg-warning "empty parentheses" }
> return f ();
> }
> diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash3.C b/gcc/testsuite/g++.old-deja/g++.pt/crash3.C
> index 52701b776ef..d1d9b12738c 100644
> --- a/gcc/testsuite/g++.old-deja/g++.pt/crash3.C
> +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash3.C
> @@ -7,11 +7,13 @@ public:
> {
> // local-extern :)
> CVector<int> v(); // { dg-message "old declaration" }
> + // { dg-warning "empty parentheses" "" { target *-*-* } .-1 }
> return v; // { dg-error "convert" }
> }
> CVector<long> g() const
> {
> CVector<long> v(); // { dg-error "ambiguating new" }
> + // { dg-warning "empty parentheses" "" { target *-*-* } .-1 }
> return v; // { dg-error "convert" }
> }
> };
> diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/lwg2993.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/lwg2993.cc
> index d1f0cafe688..c30511cab11 100644
> --- a/libstdc++-v3/testsuite/20_util/reference_wrapper/lwg2993.cc
> +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/lwg2993.cc
> @@ -43,7 +43,7 @@ test01()
> void
> test02()
> {
> - std::reference_wrapper<int> purr();
> + std::reference_wrapper<int> purr(); // { dg-warning "empty parentheses" }
>
> // error, ambiguous: ICS exists from int prvalue to
> // reference_wrapper<int> and from reference_wrapper<int> to int
> diff --git a/libstdc++-v3/testsuite/25_algorithms/generate_n/87982_neg.cc b/libstdc++-v3/testsuite/25_algorithms/generate_n/87982_neg.cc
> index 4236b5a820d..73934638ee3 100644
> --- a/libstdc++-v3/testsuite/25_algorithms/generate_n/87982_neg.cc
> +++ b/libstdc++-v3/testsuite/25_algorithms/generate_n/87982_neg.cc
> @@ -23,7 +23,7 @@
>
> void test01()
> {
> - int gen();
> + int gen(); // { dg-warning "empty parentheses" }
> int a[2];
> std::generate_n(a, a+2, &gen);
> }
>
> base-commit: ffe6b4101501b5ada6f09a1fdf3822a23b68b5aa
>
More information about the Gcc-patches
mailing list