From 78c8d80f19cb0bccd4f3d590e71a230e727cfab5 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Sun, 5 Oct 2008 19:56:22 +0000 Subject: [PATCH] Handle ambiguities between expressions and type-ids that occur inside parentheses, e.g.: sizeof(int()) -> "int()" is type-id sizeof(int()+1) -> "int()+1" is expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57131 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 18 ++++++++- lib/Parse/ParseDecl.cpp | 2 +- lib/Parse/ParseExpr.cpp | 2 +- lib/Parse/ParseTentative.cpp | 59 ++++++++++++++++++++++++++-- test/SemaCXX/decl-expr-ambiguity.cpp | 2 + 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 7510219e3a..c1259c6965 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -591,6 +591,15 @@ private: return isDeclarationSpecifier(); } + /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know + /// whether the parens contain an expression or a type-id. + /// Returns true for a type-id and false for an expression. + bool isTypeIdInParens() { + if (getLang().CPlusPlus) + return isCXXTypeIdInParens(); + return isTypeSpecifierQualifier(); + } + /// isCXXDeclarationStatement - C++-specialized function that disambiguates /// between a declaration or an expression statement, when parsing function /// bodies. Returns true for declaration, false for expression. @@ -617,6 +626,13 @@ private: /// the function returns true to let the declaration parsing code handle it. bool isCXXConditionDeclaration(); + /// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to + /// know whether the parens contain an expression or a type-id. + /// Returns true for a type-id and false for an expression. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXTypeIdInParens(); + /// TPResult - Used as the result value for functions whose purpose is to /// disambiguate C++ constructs by "tentatively parsing" them. /// This is a class instead of a simple enum because the implicit enum-to-bool @@ -659,7 +675,7 @@ private: TPResult TryParseSimpleDeclaration(); TPResult TryParseTypeofSpecifier(); TPResult TryParseInitDeclaratorList(); - TPResult TryParseDeclarator(bool mayBeAbstract); + TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); TPResult TryParseParameterDeclarationClause(); TPResult TryParseFunctionDeclarator(); TPResult TryParseBracketDeclarator(); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index eef071fd40..c22d9e871b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1581,7 +1581,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { SourceLocation LParenLoc = ConsumeParen(), RParenLoc; - if (isTypeSpecifierQualifier()) { + if (isTypeIdInParens()) { TypeTy *Ty = ParseTypeName(); assert(Ty && "Parser::ParseTypeofSpecifier(): missing type"); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 64f31ddbc8..c8d95cf053 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -981,7 +981,7 @@ Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, if (!Stmt.isInvalid && Tok.is(tok::r_paren)) Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.Val, Tok.getLocation()); - } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) { + } else if (ExprType >= CompoundLiteral && isTypeIdInParens()) { // Otherwise, this is a compound literal expression or cast expression. TypeTy *Ty = ParseTypeName(); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 2f1130ad74..9bd35dd110 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -282,6 +282,58 @@ bool Parser::isCXXConditionDeclaration() { return TPR == TPResult::True(); } +/// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to +/// know whether the parens contain an expression or a type-id. +/// Returns true for a type-id and false for an expression. +/// If during the disambiguation process a parsing error is encountered, +/// the function returns true to let the declaration parsing code handle it. +/// +/// type-id: +/// type-specifier-seq abstract-declarator[opt] +/// +bool Parser::isCXXTypeIdInParens() { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR != TPResult::Ambiguous()) + return TPR != TPResult::False(); // Returns true for TPResult::True() or + // TPResult::Error(). + + // FIXME: Add statistics about the number of ambiguous statements encountered + // and how they were resolved (number of declarations+number of expressions). + + // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. + // We need tentative parsing... + + TentativeParsingAction PA(*this); + + // type-specifier-seq + if (Tok.is(tok::kw_typeof)) + TryParseTypeofSpecifier(); + else + ConsumeToken(); + assert(Tok.is(tok::l_paren) && "Expected '('"); + + // declarator + TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); + + // In case of an error, let the declaration parsing code handle it. + if (TPR == TPResult::Error()) + TPR = TPResult::True(); + + if (TPR == TPResult::Ambiguous()) { + // We are supposed to be inside parens, so if after the abstract declarator + // we encounter a ')' this is a type-id, otherwise it's an expression. + if (Tok.is(tok::r_paren)) + TPR = TPResult::True(); + else + TPR = TPResult::False(); + } + + PA.Revert(); + + assert(TPR == TPResult::True() || TPR == TPResult::False()); + return TPR == TPResult::True(); +} + /// declarator: /// direct-declarator /// ptr-operator declarator @@ -332,7 +384,8 @@ bool Parser::isCXXConditionDeclaration() { /// '~' class-name [TODO] /// template-id [TODO] /// -Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) { +Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, + bool mayHaveIdentifier) { // declarator: // direct-declarator // ptr-operator declarator @@ -353,7 +406,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) { // direct-declarator: // direct-abstract-declarator: - if (Tok.is(tok::identifier)) { + if (Tok.is(tok::identifier) && mayHaveIdentifier) { // declarator-id ConsumeToken(); } else if (Tok.is(tok::l_paren)) { @@ -370,7 +423,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) { ConsumeParen(); if (Tok.is(tok::kw___attribute)) return TPResult::True(); // attributes indicate declaration - TPResult TPR = TryParseDeclarator(mayBeAbstract); + TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous()) return TPR; if (Tok.isNot(tok::r_paren)) diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp index 63f744a2c4..35805abac5 100644 --- a/test/SemaCXX/decl-expr-ambiguity.cpp +++ b/test/SemaCXX/decl-expr-ambiguity.cpp @@ -13,6 +13,8 @@ void f() { void(a), ++a; // expected-warning {{statement was disambiguated as expression}} expected-warning {{expression result unused}} if (int(a)+1) {} for (int(a)+1;;) {} + a = sizeof(int()+1); + typeof(int()+1) a2; // Declarations. T(*d)(int(p)); // expected-warning {{statement was disambiguated as declaration}} expected-error {{previous definition is here}} -- 2.40.0