Bug 25814 (add-Wvexing-parse) - Request for warning for parser ambiguity of function declarations and variable declarations with initializations
Summary: Request for warning for parser ambiguity of function declarations and variabl...
Status: RESOLVED FIXED
Alias: add-Wvexing-parse
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.0.2
: P5 enhancement
Target Milestone: 9.4
Assignee: Marek Polacek
URL:
Keywords: diagnostic
: 52960 86556 (view as bug list)
Depends on:
Blocks: Weffc++ new-warning, new_warning
  Show dependency treegraph
 
Reported: 2006-01-17 00:42 UTC by merkert
Modified: 2025-01-31 18:54 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-07-19 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description merkert 2006-01-17 00:42:41 UTC
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;
}
Comment 1 Andrew Pinski 2006-01-17 00:58:01 UTC
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.
Comment 2 gdr@cs.tamu.edu 2006-01-17 04:01:03 UTC
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
Comment 3 merkert 2006-01-17 12:32:58 UTC
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.
Comment 4 Wolfgang Bangerth 2006-03-08 05:07:27 UTC
I think we can confirm the problem. I doubt anyone will come around to
actually taking this on anytime soon, though...

W.
Comment 5 Wolfgang Roemer 2006-11-14 15:35:58 UTC
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?
Comment 6 merkert 2006-11-14 15:52:41 UTC
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;
}
Comment 7 Manuel López-Ibáñez 2016-08-12 12:51:18 UTC
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.
Comment 8 Eric Gallager 2016-09-01 13:04:16 UTC
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.
Comment 9 Eric Gallager 2017-08-24 02:00:32 UTC
*** Bug 52960 has been marked as a duplicate of this bug. ***
Comment 10 Jonathan Wakely 2018-07-19 12:52:55 UTC
*** Bug 86556 has been marked as a duplicate of this bug. ***
Comment 11 Eric Gallager 2018-10-19 04:46:39 UTC
ASSIGNED since there's an assignee
Comment 12 Jakub Jelinek 2019-05-03 09:17:59 UTC
GCC 9.1 has been released.
Comment 13 Jakub Jelinek 2019-08-12 08:57:28 UTC
GCC 9.2 has been released.
Comment 14 Jakub Jelinek 2020-03-12 11:59:01 UTC
GCC 9.3.0 has been released, adjusting target milestone.
Comment 15 Marek Polacek 2020-08-26 12:22:18 UTC
David, presumably you're not working on this at the moment?
Comment 16 David Malcolm 2020-08-27 11:12:31 UTC
(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
Comment 17 Marek Polacek 2020-08-27 14:33:57 UTC
(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.
Comment 18 Marek Polacek 2020-10-22 15:02:44 UTC
I now have a patch.
Comment 19 GCC Commits 2020-11-05 20:56:42 UTC
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.
Comment 20 Marek Polacek 2020-11-05 20:59:54 UTC
Implemented in GCC 11.