I'd like to request a warning to notify that a statement like "X x(const Y&)" is parsed as function declaration and not a definition of variable x. See the code below. At least as couple of PRs have been filed (9217,19503) on this topic. I've just spent at least 2 hrs trying to figure out why my constructor and destructor were not called and did not show up in the assembly code either. I think this particular problem might affect users that use the resource-acquisition idiom. The real problem is that the code compiles and links and runs without problems, except it doesn't actually work. #include <cstdio> struct Y {}; struct X { inline X (const Y&) {} inline ~X () { ::std::printf("1\n"); } }; int main() { X x(Y()); return 0; }
Maybe if more C++ books actually talked about this issue, there would not be a problem (sorry I could not resists). Also warning about very valid and defined code even if it is a common mistake that beginers make. I would rather have people actually taught this rule than GCC warning about it. "The real problem is that the code compiles and links and runs without problems, except it doesn't actually work." that should say doesn't actually work the way the person is expecting so it is working as the C++ standard says it should work.
Subject: Re: Request for warning for parser ambiguity of function declarations and variable declarations with initializations "pinskia at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes: | Maybe if more C++ books actually talked about this issue, there would not be a | problem (sorry I could not resists). C++ books do take about it -- just check out the good ones. This very problem, if you check out writings from Bjarne or me (see, e.g., our proposal for "generalized initializer list" for discussions), is a problem inherited from the C syntax which permits redundant parenthesis in declarations, exacerbed by the functional notation. Check out details from D&E. | Also warning about very valid and defined | code even if it is a common mistake that beginers make. I would rather have | people actually taught this rule than GCC warning about it. this is somehow hard to diagnose, but I guess one could engineer the front-end to remember redundant parens, but it would be rather low priority for me. -- Gaby
I would not consider myself a beginner, but I'm no c++ language laywer either. Usually the problem will get caught as soon as you try to invoke a method, but if it's something like a guard object, without methods, then it can be a problem. This is such an infrequent event (I think it happened to me before, years ago) it's easy to forget about this rule and no amount of teaching about it in books will help ( and I do use the Stroustrup book ). I agree that it is probably hard to fix because it's a grammar problem, but might it be possible to warn about a locally unused declaration? Maybe it makes sense to warn about any local declaration (I've never really seen those)? Or maybe it's a statement that has no effect? Priority-wise, it's probably low considering the rare occurrence.
I think we can confirm the problem. I doubt anyone will come around to actually taking this on anytime soon, though... W.
Raimund.Merkert@baesystems.com wrote: "Usually the problem will get caught as soon as you try to invoke a method, but if it's something like a guard object, without methods, then it can be a problem." At least in this case there should be a warning if -Wunused-function is used, shouldn't it?
It does not seem to warn about unused functions. I also tried the following test case where 4.0.0 (solaris) does not warn even about foo ( I guess because it's referenced in Y's constructor?) gcc -Wunused-function test.cpp #include <cstdio> static void foo() {} struct Y { Y() { foo(); } }; struct X { inline X (const Y&) {} inline ~X () { ::std::printf("1\n"); } }; int main() { X x(Y()); return 0; }
Clang gives: prog.cc:19:6: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse] X x(Y()); ^~~~~ prog.cc:19:7: note: add a pair of parentheses to declare a variable X x(Y()); ^ ( ) 1 warning generated.
Turns out there's actually an entire Wikipedia article on this issue: https://en.wikipedia.org/wiki/Most_vexing_parse It mentions that Scott Meyers talks about it in his "Effective STL" book, so maybe if GCC adds a -Wvexing-parse option, it could have it be automatically enabled by the -Weffc++ option.
*** Bug 52960 has been marked as a duplicate of this bug. ***
*** Bug 86556 has been marked as a duplicate of this bug. ***
ASSIGNED since there's an assignee
GCC 9.1 has been released.
GCC 9.2 has been released.
GCC 9.3.0 has been released, adjusting target milestone.
David, presumably you're not working on this at the moment?
(In reply to Marek Polacek from comment #15) > David, presumably you're not working on this at the moment? You're correct. Sorry about that. Switching back from ASSIGNED to NEW; resetting assignee to default
(In reply to David Malcolm from comment #16) > (In reply to Marek Polacek from comment #15) > > David, presumably you're not working on this at the moment? > You're correct. Sorry about that. Switching back from ASSIGNED to NEW; > resetting assignee to default No worries. I'm interested in this but won't assign until I have at least a WIP patch.
I now have a patch.
The master branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>: https://gcc.gnu.org/g:5b2003105b35f8fe8e074c055a718c8f484d9d32 commit r11-4756-g5b2003105b35f8fe8e074c055a718c8f484d9d32 Author: Marek Polacek <polacek@redhat.com> Date: Fri Oct 2 09:46:30 2020 -0400 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.
Implemented in GCC 11.