[cfe-commits] r72260 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTentative.cpp test/Parser/cxx-ambig-paren-expr.cpp
Argiris Kirtzidis
akyrtzi at gmail.com
Fri May 22 03:24:43 PDT 2009
Author: akirtzidis
Date: Fri May 22 05:24:42 2009
New Revision: 72260
URL: http://llvm.org/viewvc/llvm-project?rev=72260&view=rev
Log:
Handle correctly a very ugly part of the C++ syntax. We cannot disambiguate between a parenthesized type-id and
a paren expression without considering the context past the parentheses.
Behold:
(T())x; - type-id
(T())*x; - type-id
(T())/x; - expression
(T()); - expression
Added:
cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=72260&r1=72259&r2=72260&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri May 22 05:24:42 2009
@@ -661,6 +661,9 @@
OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
unsigned MinPrec);
OwningExprResult ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand,
+ bool &NotCastExpr);
+ OwningExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand = false);
OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
OwningExprResult ParseSizeofAlignofExpression();
@@ -690,6 +693,11 @@
TypeTy *&CastTy,
SourceLocation &RParenLoc);
+ OwningExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+ TypeTy *&CastTy,
+ SourceLocation LParenLoc,
+ SourceLocation &RParenLoc);
+
OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
@@ -918,11 +926,16 @@
/// 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() {
+ bool isTypeIdInParens(bool &isAmbiguous) {
if (getLang().CPlusPlus)
- return isCXXTypeId(TypeIdInParens);
+ return isCXXTypeId(TypeIdInParens, isAmbiguous);
+ isAmbiguous = false;
return isTypeSpecifierQualifier();
}
+ bool isTypeIdInParens() {
+ bool isAmbiguous;
+ return isTypeIdInParens(isAmbiguous);
+ }
/// isCXXDeclarationStatement - C++-specialized function that disambiguates
/// between a declaration or an expression statement, when parsing function
@@ -951,7 +964,11 @@
/// the function returns true to let the declaration parsing code handle it.
bool isCXXConditionDeclaration();
- bool isCXXTypeId(TentativeCXXTypeIdContext Context);
+ bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous);
+ bool isCXXTypeId(TentativeCXXTypeIdContext Context) {
+ bool isAmbiguous;
+ return isCXXTypeId(Context, isAmbiguous);
+ }
/// TPResult - Used as the result value for functions whose purpose is to
/// disambiguate C++ constructs by "tentatively parsing" them.
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=72260&r1=72259&r2=72260&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri May 22 05:24:42 2009
@@ -400,6 +400,23 @@
/// id-expression that is the operand of address-of gets special treatment
/// due to member pointers.
///
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand) {
+ bool NotCastExpr;
+ OwningExprResult Res = ParseCastExpression(isUnaryExpression,
+ isAddressOfOperand,
+ NotCastExpr);
+ if (NotCastExpr)
+ Diag(Tok, diag::err_expected_expression);
+ return move(Res);
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers. NotCastExpr is set to true if the token is not the
+/// start of a cast-expression, and no diagnostic is emitted in this case.
+///
/// cast-expression: [C99 6.5.4]
/// unary-expression
/// '(' type-name ')' cast-expression
@@ -506,9 +523,11 @@
/// '__is_base_of' [TODO]
///
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
- bool isAddressOfOperand) {
+ bool isAddressOfOperand,
+ bool &NotCastExpr) {
OwningExprResult Res(Actions);
tok::TokenKind SavedKind = Tok.getKind();
+ NotCastExpr = false;
// This handles all of cast-expression, unary-expression, postfix-expression,
// and primary-expression. We handle them together like this for efficiency
@@ -797,7 +816,7 @@
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
// FALL THROUGH.
default:
- Diag(Tok, diag::err_expected_expression);
+ NotCastExpr = true;
return ExprError();
}
@@ -1216,6 +1235,7 @@
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
SourceLocation OpenLoc = ConsumeParen();
OwningExprResult Result(Actions, true);
+ bool isAmbiguousTypeId;
CastTy = 0;
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
@@ -1227,9 +1247,20 @@
if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation());
- } else if (ExprType >= CompoundLiteral && isTypeIdInParens()) {
+ } else if (ExprType >= CompoundLiteral &&
+ isTypeIdInParens(isAmbiguousTypeId)) {
// Otherwise, this is a compound literal expression or cast expression.
+
+ // In C++, if the type-id is ambiguous we disambiguate based on context.
+ // If stopIfCastExpr is true the context is a typeof/sizeof/alignof
+ // in which case we should treat it as type-id.
+ // if stopIfCastExpr is false, we need to determine the context past the
+ // parens, so we defer to ParseCXXAmbiguousParenExpression for that.
+ if (isAmbiguousTypeId && !stopIfCastExpr)
+ return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
+ OpenLoc, RParenLoc);
+
TypeResult Ty = ParseTypeName();
// Match the ')'.
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=72260&r1=72259&r2=72260&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri May 22 05:24:42 2009
@@ -1038,3 +1038,110 @@
return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
}
+
+/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
+/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
+/// based on the context past the parens.
+Parser::OwningExprResult
+Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+ TypeTy *&CastTy,
+ SourceLocation LParenLoc,
+ SourceLocation &RParenLoc) {
+ assert(getLang().CPlusPlus && "Should only be called for C++!");
+ assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
+ assert(isTypeIdInParens() && "Not a type-id!");
+
+ OwningExprResult Result(Actions, true);
+ CastTy = 0;
+
+ // We need to disambiguate a very ugly part of the C++ syntax:
+ //
+ // (T())x; - type-id
+ // (T())*x; - type-id
+ // (T())/x; - expression
+ // (T()); - expression
+ //
+ // The bad news is that we cannot use the specialized tentative parser, since
+ // it can only verify that the thing inside the parens can be parsed as
+ // type-id, it is not useful for determining the context past the parens.
+ //
+ // The good news is that the parser can disambiguate this part without
+ // making any unnecessary Action calls (apart from isTypeName).
+
+ // Start tentantive parsing.
+ TentativeParsingAction PA(*this);
+
+ // Parse the type-id but don't create a type with ActOnTypeName yet.
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the abstract-declarator, if present.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ if (!Tok.is(tok::r_paren)) {
+ PA.Commit();
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return ExprError();
+ }
+
+ RParenLoc = ConsumeParen();
+
+ if (Tok.is(tok::l_brace)) {
+ // Compound literal. Ok, we can commit the parsed tokens and continue
+ // normal parsing.
+ ExprType = CompoundLiteral;
+ PA.Commit();
+ TypeResult Ty = true;
+ if (!DeclaratorInfo.isInvalidType())
+ Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+ return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
+ }
+
+ // We parsed '(' type-name ')' and the thing after it wasn't a '{'.
+
+ if (DeclaratorInfo.isInvalidType()) {
+ PA.Commit();
+ return ExprError();
+ }
+
+ bool NotCastExpr;
+ // Parse the cast-expression that follows it next.
+ Result = ParseCastExpression(false/*isUnaryExpression*/,
+ false/*isAddressofOperand*/,
+ NotCastExpr);
+
+ if (NotCastExpr == false) {
+ // We parsed a cast-expression. That means it's really a type-id, so commit
+ // the parsed tokens and continue normal parsing.
+ PA.Commit();
+ TypeResult Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+ CastTy = Ty.get();
+ if (!Result.isInvalid())
+ Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result));
+ return move(Result);
+ }
+
+ // If we get here, it means the things after the parens are not the start of
+ // a cast-expression. This means we must actually parse the tokens inside
+ // the parens as an expression.
+ PA.Revert();
+
+ Result = ParseExpression();
+ ExprType = SimpleExpr;
+ if (!Result.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), move(Result));
+
+ // Match the ')'.
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return move(Result);
+}
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=72260&r1=72259&r2=72260&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Fri May 22 05:24:42 2009
@@ -287,7 +287,9 @@
/// type-id:
/// type-specifier-seq abstract-declarator[opt]
///
-bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context) {
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
+
+ isAmbiguous = false;
// C++ 8.2p2:
// The ambiguity arising from the similarity between a function-style cast and
@@ -326,16 +328,20 @@
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 (Context == TypeIdInParens && Tok.is(tok::r_paren))
+ if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
TPR = TPResult::True();
+ isAmbiguous = true;
+
// We are supposed to be inside a template argument, so if after
// the abstract declarator we encounter a '>', '>>' (in C++0x), or
// ',', this is a type-id. Otherwise, it's an expression.
- else if (Context == TypeIdAsTemplateArgument &&
- (Tok.is(tok::greater) || Tok.is(tok::comma) ||
- (getLang().CPlusPlus0x && Tok.is(tok::greatergreater))))
+ } else if (Context == TypeIdAsTemplateArgument &&
+ (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+ (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
TPR = TPResult::True();
- else
+ isAmbiguous = true;
+
+ } else
TPR = TPResult::False();
}
Added: cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp?rev=72260&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp (added)
+++ cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp Fri May 22 05:24:42 2009
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f() {
+ typedef int T;
+ int x, *px;
+
+ // Type id.
+ (T())x; // expected-error {{used type 'T (void)'}}
+ (T())+x; // expected-error {{used type 'T (void)'}}
+ (T())*px; // expected-error {{used type 'T (void)'}}
+
+ // Expression.
+ x = (T());
+ x = (T())/x;
+}
More information about the cfe-commits
mailing list