From: Argyrios Kyrtzidis Date: Wed, 15 Oct 2008 23:21:32 +0000 (+0000) Subject: Issue a warning when there's an ambiguous function declarator (that could be a direct... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=259b0d91f2ff90d8daf39221fe133bf1596c5ffb;p=clang Issue a warning when there's an ambiguous function declarator (that could be a direct initializer for a variable defition). Idea originated from here: http://thread.gmane.org/gmane.comp.gcc.devel/101524 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57609 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index fc2b7f6088..98e760145b 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -557,6 +557,8 @@ DIAG(err_expected_equal_after_declarator, ERROR, "expected '=' after declarator") DIAG(warn_statement_disambiguation, WARNING, "statement was disambiguated as %0") +DIAG(warn_parens_disambiguated_as_function_decl, WARNING, + "parentheses were disambiguated as a function declarator") // Language specific pragmas diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index c1259c6965..de12549d7f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -615,10 +615,11 @@ private: /// isCXXFunctionDeclarator - Disambiguates between a function declarator or /// a constructor-style initializer, when parsing declaration statements. /// Returns true for function declarator and false for constructor-style - /// initializer. + /// initializer. If 'diagIfAmbiguous' is true a warning will be emitted to + /// indicate that the parens were disambiguated as function declarator. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. - bool isCXXFunctionDeclarator(); + bool isCXXFunctionDeclarator(bool diagIfAmbiguous); /// isCXXConditionDeclaration - Disambiguates between a declaration or an /// expression for a condition of a if/switch/while/for statement. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c541a1336f..142347687e 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1226,11 +1226,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { while (1) { if (Tok.is(tok::l_paren)) { + // When not in file scope, warn for ambiguous function declarators, just + // in case the author intended it as a variable definition. + bool diagIfAmbiguous = D.getContext() != Declarator::FileContext; // The paren may be part of a C++ direct initializer, eg. "int x(1);". // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit() && - !isCXXFunctionDeclarator()) + !isCXXFunctionDeclarator(diagIfAmbiguous)) break; ParseFunctionDeclarator(ConsumeParen(), D); } else if (Tok.is(tok::l_square)) { diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 5dbc327b71..1666e39ee1 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -453,7 +453,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // initializer that follows the declarator. Note that ctor-style // initializers are not possible in contexts where abstract declarators // are allowed. - if (!mayBeAbstract && !isCXXFunctionDeclarator()) + if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*diagIfAmbiguous*/)) break; // direct-declarator '(' parameter-declaration-clause ')' @@ -722,7 +722,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// -bool Parser::isCXXFunctionDeclarator() { +bool Parser::isCXXFunctionDeclarator(bool diagIfAmbiguous) { // C++ 8.2p1: // The ambiguity arising from the similarity between a function-style cast and @@ -740,15 +740,21 @@ bool Parser::isCXXFunctionDeclarator() { if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) TPR = TPResult::False(); + SourceLocation TPLoc = Tok.getLocation(); PA.Revert(); // In case of an error, let the declaration parsing code handle it. if (TPR == TPResult::Error()) return true; - // Function declarator has precedence over constructor-style initializer. - if (TPR == TPResult::Ambiguous()) + if (TPR == TPResult::Ambiguous()) { + // Function declarator has precedence over constructor-style initializer. + // Emit a warning just in case the author intended a variable definition. + if (diagIfAmbiguous) + Diag(Tok.getLocation(), diag::warn_parens_disambiguated_as_function_decl, + SourceRange(Tok.getLocation(), TPLoc)); return true; + } return TPR == TPResult::True(); } diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp index 3459d771ab..72948e6c75 100644 --- a/test/SemaCXX/decl-expr-ambiguity.cpp +++ b/test/SemaCXX/decl-expr-ambiguity.cpp @@ -22,7 +22,8 @@ void f() { (int())1; // expected-error {{used type 'int ()' where arithmetic or pointer type is required}} // Declarations. - T(*d)(int(p)); // expected-warning {{statement was disambiguated as declaration}} expected-error {{previous definition is here}} + int fd(T(a)); // expected-warning {{parentheses were disambiguated as a function declarator}} + T(*d)(int(p)); // expected-warning {{parentheses were disambiguated as a function declarator}} expected-warning {{statement was disambiguated as declaration}} expected-error {{previous definition is here}} T(d)[5]; // expected-warning {{statement was disambiguated as declaration}} expected-error {{redefinition of 'd'}} typeof(int[])(f) = { 1, 2 }; // expected-warning {{statement was disambiguated as declaration}} void(b)(int);