On Fri, Oct 30, 2020 at 04:33:48PM -0400, Jason Merrill wrote:
> On 10/29/20 11:00 PM, Marek Polacek wrote:
> > Gotcha.  Now we do most of the work in warn_about_ambiguous_parse.
> 
> Thanks, just a few tweaks left.
> > --- 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.

Yeah, because explicit_/void_list_node don't have a type.

> > +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?

Looks like it isn't, removed.

> > +  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.

I think this can't be a loop, because we only set PARENTHESIZED_LIST_P
in the whole list.  But I realized that there still was an issue: I was
setting PARENTHESIZED_LIST_P only based on the last element in the list,
but we want to set it only if every parameter was parenthesized.  So I've
fixed setting of PARENTHESIZED_LIST_P instead.

> > +  /* 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?

I thought that this case was rare enough, but sure, why not; I've added
the code.

> > +
> >   /* 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?

Done.  And the at_function_scope_p check too.

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.
        * g++.dg/warn/Wvexing-parse7.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                               | 155 +++++++++++++++++-
 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 +++
 gcc/testsuite/g++.dg/warn/Wvexing-parse7.C    |  27 +++
 .../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 +-
 27 files changed, 617 insertions(+), 23 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
 create mode 100644 gcc/testsuite/g++.dg/warn/Wvexing-parse7.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 426636be839..5bfe3a68f66 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 26852f6f2e3..4b9a88931fc 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)
@@ -3382,6 +3385,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))
 
@@ -6038,6 +6045,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 9428fa05258..98c1a5decf2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4384,6 +4384,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.) */
@@ -14037,7 +14040,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;
 
       if (! decl || TREE_TYPE (decl) == error_mark_node)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b0d5c69f1d6..e7bfbf649a5 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,129 @@ 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.  DECL_SPECIFIERS is the decl-specifier-seq and DECLARATOR
+   is the declarator for this function declaration.  */
+
+static void
+warn_about_ambiguous_parse (const cp_decl_specifier_seq *decl_specifiers,
+                           const cp_declarator *declarator)
+{
+  /* Only warn if we are declaring a function at block scope.  */
+  if (!at_function_scope_p ())
+    return;
+
+  /* And only if there is no storage class specified.  */
+  if (decl_specifiers->storage_class != sc_none
+      || decl_spec_seq_has_spec_p (decl_specifiers, ds_typedef))
+    return;
+
+  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;
+
+  tree type = decl_specifiers->type;
+  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;
+  location_t loc = declarator->u.function.parens_loc;
+  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;
+
+  /* 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 if (warning_at (loc, OPT_Wvexing_parse,
+                      "parentheses were disambiguated as a function "
+                      "declaration"))
+    {
+      gcc_rich_location iloc (loc);
+      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");
+       }
+    }
+}
+
 /* Declarators [gram.dcl.decl] */
 
 /* Parse an init-declarator.
@@ -20808,6 +20935,9 @@ cp_parser_init_declarator (cp_parser* parser,
            }
        }
 
+      if (!member_p && !cp_parser_error_occurred (parser))
+       warn_about_ambiguous_parse (decl_specifiers, declarator);
+
       /* Check to see if the token indicates the start of a
         function-definition.  */
       if (cp_parser_token_starts_function_definition_p (token))
@@ -21202,7 +21332,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)
@@ -21349,6 +21479,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)
@@ -21368,6 +21499,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);
@@ -21432,6 +21565,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,
@@ -21441,7 +21577,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
@@ -22708,7 +22845,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.  */
@@ -22832,6 +22969,12 @@ cp_parser_parameter_declaration_list (cp_parser* 
parser, cp_parser_flags flags)
       *tail = build_tree_list (parameter->default_argument, decl);
       tail = &TREE_CHAIN (*tail);
 
+      /* 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.  */
+      if (index == 1 || PARENTHESIZED_LIST_P (parameters))
+       PARENTHESIZED_LIST_P (parameters) = parenthesized_p;
+
       /* Peek at the next token.  */
       if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
          || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5320e6c1e1e..812fa46e906 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++.dg/warn/Wvexing-parse7.C 
b/gcc/testsuite/g++.dg/warn/Wvexing-parse7.C
new file mode 100644
index 00000000000..9f4c7021cdc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wvexing-parse7.C
@@ -0,0 +1,27 @@
+// PR c++/25814
+// { dg-do compile }
+
+struct X { };
+struct W {
+  W(X, X);
+};
+
+void
+fn ()
+{
+  W w1(X(), X()); // { dg-warning "parentheses" }
+  W w2(X(a), X()); // { dg-warning "parentheses" }
+  W w3(X(), X(a)); // { dg-warning "parentheses" }
+  W w4(X(a), X(b)); // { dg-warning "parentheses" }
+  W w5(X, X);
+  W w6(X(a), X);
+  W w7(X, X(a));
+  W w8(X(a), X()); // { dg-warning "parentheses" }
+  W w9(X, X());
+  W w10(X, X());
+
+  // Not function declarations.
+  W z1(X(), (X()));
+  W z2((X()), X());
+  W z3((X()), (X()));
+}
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: e86fd6a17cdb26710d1f13c9a47a3878c76028f9
-- 
2.28.0

Reply via email to