aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2008-10-05 19:56:22 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2008-10-05 19:56:22 +0000
commit78c8d80f19cb0bccd4f3d590e71a230e727cfab5 (patch)
tree33e90db48d74ecb686e1f5c93e4a970c9354e149
parent9b533164570a67c81ad49f3691f02608530a042e (diff)
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
-rw-r--r--include/clang/Parse/Parser.h18
-rw-r--r--lib/Parse/ParseDecl.cpp2
-rw-r--r--lib/Parse/ParseExpr.cpp2
-rw-r--r--lib/Parse/ParseTentative.cpp59
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp2
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}}