c++: Implement -Wvexing-parse [PR25814]
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.
This commit is contained in:
parent
22984f3f09
commit
5b2003105b
@ -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.
|
||||
|
||||
@ -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 all the
|
||||
parameters in the list have declarators 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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
155
gcc/cp/parser.c
155
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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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" }
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
|
||||
int main ()
|
||||
{
|
||||
auto foo ();
|
||||
extern auto foo ();
|
||||
}
|
||||
|
||||
@ -149,5 +149,5 @@ public:
|
||||
class XclImpRoot : XclRoot {};
|
||||
class XclImpColRowSettings : XclImpRoot {};
|
||||
void lcl_ExportExcelBiff() {
|
||||
XclRootData aExpData();
|
||||
extern XclRootData aExpData();
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
110
gcc/testsuite/g++.dg/warn/Wvexing-parse.C
Normal file
110
gcc/testsuite/g++.dg/warn/Wvexing-parse.C
Normal file
@ -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>());
|
||||
}
|
||||
24
gcc/testsuite/g++.dg/warn/Wvexing-parse2.C
Normal file
24
gcc/testsuite/g++.dg/warn/Wvexing-parse2.C
Normal file
@ -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();
|
||||
}
|
||||
129
gcc/testsuite/g++.dg/warn/Wvexing-parse3.C
Normal file
129
gcc/testsuite/g++.dg/warn/Wvexing-parse3.C
Normal file
@ -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 }
|
||||
}
|
||||
74
gcc/testsuite/g++.dg/warn/Wvexing-parse4.C
Normal file
74
gcc/testsuite/g++.dg/warn/Wvexing-parse4.C
Normal file
@ -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 "" } */
|
||||
}
|
||||
14
gcc/testsuite/g++.dg/warn/Wvexing-parse5.C
Normal file
14
gcc/testsuite/g++.dg/warn/Wvexing-parse5.C
Normal file
@ -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" }
|
||||
}
|
||||
24
gcc/testsuite/g++.dg/warn/Wvexing-parse6.C
Normal file
24
gcc/testsuite/g++.dg/warn/Wvexing-parse6.C
Normal file
@ -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" }
|
||||
}
|
||||
27
gcc/testsuite/g++.dg/warn/Wvexing-parse7.C
Normal file
27
gcc/testsuite/g++.dg/warn/Wvexing-parse7.C
Normal file
@ -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()));
|
||||
}
|
||||
@ -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.*
|
||||
}
|
||||
|
||||
@ -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" }
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,6 @@ int f (int);
|
||||
|
||||
int main ()
|
||||
{
|
||||
int f ();
|
||||
int f (); // { dg-warning "empty parentheses" }
|
||||
return f ();
|
||||
}
|
||||
|
||||
@ -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" }
|
||||
}
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
void test01()
|
||||
{
|
||||
int gen();
|
||||
int gen(); // { dg-warning "empty parentheses" }
|
||||
int a[2];
|
||||
std::generate_n(a, a+2, &gen);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user