I also uncovered a bug in cp_parser_declarator, where we were setting
*parenthesized_p to true despite the comment saying the exact opposite.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
gcc/c-family/ChangeLog:
PR c++/25814
* c.opt (Wvexing-parse): New option.
gcc/cp/ChangeLog:
PR c++/25814
* parser.c (cp_parser_init_declarator): Maybe set warn_ambig_parse.
Pass it to cp_parser_declarator.
(cp_parser_declarator): Add a tree parameter with a default
value. Set *parenthesized_p to false rather than to true. Pass
warn_ambig_parse to cp_parser_direct_declarator.
(warn_about_ambiguous_parse): New function.
(cp_parser_direct_declarator): Add a tree parameter with a default
value. Have cp_parser_parameter_declaration_clause set a flag
if it encountered a vexing parse. Call warn_about_ambiguous_parse
if desirable.
(cp_parser_parameter_declaration_clause): New bool * parameter
with a default value. Set it. Pass it to
cp_parser_parameter_declaration_list.
(cp_parser_parameter_declaration_list): New bool * parameter.
Set it.
(cp_parser_cache_defarg): Adjust the call to
cp_parser_parameter_declaration_list.
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/parser.c | 176 +++++++++++++++---
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 +-
24 files changed, 584 insertions(+), 37 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 bbf7da89658..ac2cd1e3135 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1260,6 +1260,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/parser.c b/gcc/cp/parser.c
index 7ec7d42773c..c7c5e2f9305 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2251,10 +2251,10 @@ static tree cp_parser_init_declarator
location_t *, tree *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool *,
- bool, bool, bool);
+ bool, bool, bool, tree = NULL_TREE);
static cp_declarator *cp_parser_direct_declarator
(cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool,
- bool);
+ bool, tree = NULL_TREE);
static enum tree_code cp_parser_ptr_operator
(cp_parser *, tree *, cp_cv_quals *, tree *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
@@ -2279,9 +2279,9 @@ static tree cp_parser_type_id_1
static void cp_parser_type_specifier_seq
(cp_parser *, cp_parser_flags, bool, bool, cp_decl_specifier_seq *);
static tree cp_parser_parameter_declaration_clause
- (cp_parser *, cp_parser_flags);
+ (cp_parser *, cp_parser_flags, bool * = nullptr);
static tree cp_parser_parameter_declaration_list
- (cp_parser *, cp_parser_flags);
+ (cp_parser *, cp_parser_flags, bool *);
static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, cp_parser_flags, bool, bool *);
static tree cp_parser_default_argument
@@ -20700,6 +20700,14 @@ cp_parser_init_declarator (cp_parser* parser,
if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval))
flags |= CP_PARSER_FLAGS_CONSTEVAL;
+ /* Decide if we might want to warn about the most vexing parse. */
+ tree warn_ambig_parse = NULL_TREE;
+ if (decl_specifiers->storage_class == sc_none
+ && at_function_scope_p ()
+ && !member_p
+ && !decl_spec_seq_has_spec_p (decl_specifiers, ds_typedef))
+ warn_ambig_parse = decl_specifiers->type;
+
/* Gather the attributes that were provided with the
decl-specifiers. */
prefix_attributes = decl_specifiers->attributes;
@@ -20725,7 +20733,8 @@ cp_parser_init_declarator (cp_parser* parser,
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
flags, &ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL,
- member_p, friend_p, /*static_p=*/false);
+ member_p, friend_p, /*static_p=*/false,
+ warn_ambig_parse);
/* Gather up the deferred checks. */
stop_deferring_access_checks ();
@@ -21153,7 +21162,9 @@ cp_parser_init_declarator (cp_parser* parser,
FRIEND_P is true iff this declarator is a friend.
- STATIC_P is true iff the keyword static was seen. */
+ STATIC_P is true iff the keyword static was seen.
+
+ WARN_AMBIG_PARSE is used for -Wvexing-parse. */
static cp_declarator *
cp_parser_declarator (cp_parser* parser,
@@ -21161,7 +21172,8 @@ cp_parser_declarator (cp_parser* parser,
cp_parser_flags flags,
int* ctor_dtor_or_conv_p,
bool* parenthesized_p,
- bool member_p, bool friend_p, bool static_p)
+ bool member_p, bool friend_p, bool static_p,
+ tree warn_ambig_parse/*=NULL_TREE*/)
{
cp_declarator *declarator;
enum tree_code code;
@@ -21191,7 +21203,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)
@@ -21222,7 +21234,8 @@ cp_parser_declarator (cp_parser* parser,
CPP_OPEN_PAREN);
declarator = cp_parser_direct_declarator (parser, dcl_kind,
flags, ctor_dtor_or_conv_p,
- member_p, friend_p, static_p);
+ member_p, friend_p, static_p,
+ warn_ambig_parse);
}
if (gnu_attributes && declarator && declarator != cp_error_declarator)
@@ -21230,6 +21243,90 @@ cp_parser_declarator (cp_parser* parser,
return declarator;
}
+/* 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; PARAMS is the
+ TREE_LIST of its parameters; PARENS_START and PARENS_END are locations
+ of the beginning and end of the parameter-list. */
+
+static void
+warn_about_ambiguous_parse (tree type, tree params, location_t parens_start,
+ location_t parens_end)
+{
+ 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 range_loc = make_location (parens_start, parens_start,
parens_end);
+ 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 (range_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 (range_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 (range_loc, "or replace parentheses with braces to "
+ "aggregate-initialize a variable");
+ else
+ inform (range_loc, "or replace parentheses with braces to "
+ "value-initialize a variable");
+ }
+ }
+ }
+ }
+ /* The T t(X()) case. */
+ else if (list_length (params) == 2)
+ {
+ if (warning_at (range_loc, OPT_Wvexing_parse,
+ "parentheses were disambiguated as a function "
+ "declaration"))
+ {
+ gcc_rich_location iloc (range_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 (parens_start, "{");
+ iloc.add_fixit_replace (parens_end, "}");
+ inform (&iloc, "replace parentheses with braces to declare a "
+ "variable");
+ }
+ else
+ {
+ iloc.add_fixit_insert_after (parens_start, "(");
+ iloc.add_fixit_insert_before (parens_end, ")");
+ inform (&iloc, "add parentheses to declare a variable");
+ }
+ }
+ }
+ /* The T t(X(), X()) case. */
+ else
+ warning_at (range_loc, OPT_Wvexing_parse,
+ "parentheses were disambiguated as a function "
+ "declaration");
+}
+
/* Parse a direct-declarator or direct-abstract-declarator.
direct-declarator:
@@ -21259,14 +21356,17 @@ cp_parser_declarator (cp_parser* parser,
[dcl.ambig.res].
The parser flags FLAGS is used to control type-specifier parsing.
CTOR_DTOR_OR_CONV_P, MEMBER_P, FRIEND_P, and STATIC_P are
- as for cp_parser_declarator. */
+ as for cp_parser_declarator. WARN_AMBIG_PARSE is used to implement
+ the -Wvexing-parse warning and is the return type of the function
+ declaration. */
static cp_declarator *
cp_parser_direct_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
cp_parser_flags flags,
int* ctor_dtor_or_conv_p,
- bool member_p, bool friend_p, bool static_p)
+ bool member_p, bool friend_p, bool static_p,
+ tree warn_ambig_parse/*= NULL_TREE*/)
{
cp_token *token;
cp_declarator *declarator = NULL;
@@ -21338,6 +21438,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)
@@ -21355,8 +21456,12 @@ cp_parser_direct_declarator (cp_parser* parser,
current_binding_level->immediate_fn_ctx_p = true;
/* Parse the parameter-declaration-clause. */
+ bool vexing_parse_p = false;
params
- = cp_parser_parameter_declaration_clause (parser, flags);
+ = cp_parser_parameter_declaration_clause (parser, flags,
+ &vexing_parse_p);
+ const location_t parens_end
+ = cp_lexer_peek_token (parser->lexer)->location;
/* Consume the `)'. */
parens.require_close (parser);
@@ -21444,6 +21549,15 @@ cp_parser_direct_declarator (cp_parser* parser,
/* Restore the state of local_variables_forbidden_p. */
parser->local_variables_forbidden_p
= local_variables_forbidden_p;
+
+ if (vexing_parse_p
+ && warn_ambig_parse
+ && declarator->declarator
+ && declarator->declarator->kind == cdk_id
+ && identifier_p (get_unqualified_id (declarator))
+ && !cp_parser_error_occurred (parser))
+ warn_about_ambiguous_parse (warn_ambig_parse, params,
+ parens_start, parens_end);
}
/* Remove the function parms from scope. */
@@ -22638,11 +22752,14 @@ function_being_declared_is_template_p (cp_parser*
parser)
Returns a representation for the parameter declarations. A return
value of NULL indicates a parameter-declaration-clause consisting
- only of an ellipsis. */
+ only of an ellipsis. This function might set VEXING_PARSE_P if it
+ detects a syntactic ambiguity between a variable definition and a
+ function declaration. */
static tree
cp_parser_parameter_declaration_clause (cp_parser* parser,
- cp_parser_flags flags)
+ cp_parser_flags flags,
+ bool *vexing_parse_p/*=nullptr*/)
{
tree parameters;
cp_token *token;
@@ -22671,8 +22788,12 @@ cp_parser_parameter_declaration_clause (cp_parser*
parser,
return NULL_TREE;
}
else if (token->type == CPP_CLOSE_PAREN)
- /* There are no parameters. */
- return void_list_node;
+ {
+ /* There are no parameters. */
+ if (vexing_parse_p)
+ *vexing_parse_p = true;
+ return void_list_node;
+ }
/* Check for `(void)', too, which is a special case. */
else if (token->keyword == RID_VOID
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
@@ -22685,7 +22806,8 @@ cp_parser_parameter_declaration_clause (cp_parser*
parser,
}
/* Parse the parameter-declaration-list. */
- parameters = cp_parser_parameter_declaration_list (parser, flags);
+ parameters = cp_parser_parameter_declaration_list (parser, flags,
+ vexing_parse_p);
/* If a parse error occurred while parsing the
parameter-declaration-list, then the entire
parameter-declaration-clause is erroneous. */
@@ -22732,10 +22854,14 @@ cp_parser_parameter_declaration_clause (cp_parser*
parser,
Returns a representation of the parameter-declaration-list, as for
cp_parser_parameter_declaration_clause. However, the
- `void_list_node' is never appended to the list. */
+ `void_list_node' is never appended to the list. This function might
+ set VEXING_PARSE_P if it detects a syntactic ambiguity between a variable
+ definition and a function declaration. */
static tree
-cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags)
+cp_parser_parameter_declaration_list (cp_parser* parser,
+ cp_parser_flags flags,
+ bool *vexing_parse_p)
{
tree parameters = NULL_TREE;
tree *tail = ¶meters;
@@ -22812,7 +22938,14 @@ 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. */
+ if (vexing_parse_p)
+ *vexing_parse_p = parenthesized_p;
+ break;
+ }
else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
{
cp_token *token;
@@ -31860,7 +31993,8 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
cp_lexer_consume_token (parser->lexer);
begin_scope (sk_function_parms, NULL_TREE);
tree t = cp_parser_parameter_declaration_list
- (parser, CP_PARSER_FLAGS_NONE);
+ (parser, CP_PARSER_FLAGS_NONE,
+ /*vexing_parse_p=*/nullptr);
if (t == error_mark_node)
error = true;
pop_bindings_and_leave_scope ();
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3c3c51cb4b1..0dbfa7c1628 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -252,7 +252,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
@@ -3847,6 +3848,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: c7c4a2787bae1a3eb239f5e69826727ff5c44373