forked from OSchip/llvm-project
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 llvm-svn: 72260
This commit is contained in:
parent
5da1f08587
commit
12179bc014
|
@ -660,6 +660,9 @@ private:
|
||||||
|
|
||||||
OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
|
OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
|
||||||
unsigned MinPrec);
|
unsigned MinPrec);
|
||||||
|
OwningExprResult ParseCastExpression(bool isUnaryExpression,
|
||||||
|
bool isAddressOfOperand,
|
||||||
|
bool &NotCastExpr);
|
||||||
OwningExprResult ParseCastExpression(bool isUnaryExpression,
|
OwningExprResult ParseCastExpression(bool isUnaryExpression,
|
||||||
bool isAddressOfOperand = false);
|
bool isAddressOfOperand = false);
|
||||||
OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
|
OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
|
||||||
|
@ -690,6 +693,11 @@ private:
|
||||||
TypeTy *&CastTy,
|
TypeTy *&CastTy,
|
||||||
SourceLocation &RParenLoc);
|
SourceLocation &RParenLoc);
|
||||||
|
|
||||||
|
OwningExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
|
||||||
|
TypeTy *&CastTy,
|
||||||
|
SourceLocation LParenLoc,
|
||||||
|
SourceLocation &RParenLoc);
|
||||||
|
|
||||||
OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty,
|
OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty,
|
||||||
SourceLocation LParenLoc,
|
SourceLocation LParenLoc,
|
||||||
SourceLocation RParenLoc);
|
SourceLocation RParenLoc);
|
||||||
|
@ -918,11 +926,16 @@ private:
|
||||||
/// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know
|
/// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know
|
||||||
/// whether the parens contain an expression or a type-id.
|
/// whether the parens contain an expression or a type-id.
|
||||||
/// Returns true for a type-id and false for an expression.
|
/// Returns true for a type-id and false for an expression.
|
||||||
bool isTypeIdInParens() {
|
bool isTypeIdInParens(bool &isAmbiguous) {
|
||||||
if (getLang().CPlusPlus)
|
if (getLang().CPlusPlus)
|
||||||
return isCXXTypeId(TypeIdInParens);
|
return isCXXTypeId(TypeIdInParens, isAmbiguous);
|
||||||
|
isAmbiguous = false;
|
||||||
return isTypeSpecifierQualifier();
|
return isTypeSpecifierQualifier();
|
||||||
}
|
}
|
||||||
|
bool isTypeIdInParens() {
|
||||||
|
bool isAmbiguous;
|
||||||
|
return isTypeIdInParens(isAmbiguous);
|
||||||
|
}
|
||||||
|
|
||||||
/// isCXXDeclarationStatement - C++-specialized function that disambiguates
|
/// isCXXDeclarationStatement - C++-specialized function that disambiguates
|
||||||
/// between a declaration or an expression statement, when parsing function
|
/// between a declaration or an expression statement, when parsing function
|
||||||
|
@ -951,7 +964,11 @@ private:
|
||||||
/// the function returns true to let the declaration parsing code handle it.
|
/// the function returns true to let the declaration parsing code handle it.
|
||||||
bool isCXXConditionDeclaration();
|
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
|
/// TPResult - Used as the result value for functions whose purpose is to
|
||||||
/// disambiguate C++ constructs by "tentatively parsing" them.
|
/// disambiguate C++ constructs by "tentatively parsing" them.
|
||||||
|
|
|
@ -400,6 +400,23 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
|
||||||
/// id-expression that is the operand of address-of gets special treatment
|
/// id-expression that is the operand of address-of gets special treatment
|
||||||
/// due to member pointers.
|
/// 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]
|
/// cast-expression: [C99 6.5.4]
|
||||||
/// unary-expression
|
/// unary-expression
|
||||||
/// '(' type-name ')' cast-expression
|
/// '(' type-name ')' cast-expression
|
||||||
|
@ -506,9 +523,11 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
|
||||||
/// '__is_base_of' [TODO]
|
/// '__is_base_of' [TODO]
|
||||||
///
|
///
|
||||||
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
bool isAddressOfOperand) {
|
bool isAddressOfOperand,
|
||||||
|
bool &NotCastExpr) {
|
||||||
OwningExprResult Res(Actions);
|
OwningExprResult Res(Actions);
|
||||||
tok::TokenKind SavedKind = Tok.getKind();
|
tok::TokenKind SavedKind = Tok.getKind();
|
||||||
|
NotCastExpr = false;
|
||||||
|
|
||||||
// This handles all of cast-expression, unary-expression, postfix-expression,
|
// This handles all of cast-expression, unary-expression, postfix-expression,
|
||||||
// and primary-expression. We handle them together like this for efficiency
|
// and primary-expression. We handle them together like this for efficiency
|
||||||
|
@ -797,7 +816,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
|
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
|
||||||
// FALL THROUGH.
|
// FALL THROUGH.
|
||||||
default:
|
default:
|
||||||
Diag(Tok, diag::err_expected_expression);
|
NotCastExpr = true;
|
||||||
return ExprError();
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1216,6 +1235,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
||||||
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
|
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
|
||||||
SourceLocation OpenLoc = ConsumeParen();
|
SourceLocation OpenLoc = ConsumeParen();
|
||||||
OwningExprResult Result(Actions, true);
|
OwningExprResult Result(Actions, true);
|
||||||
|
bool isAmbiguousTypeId;
|
||||||
CastTy = 0;
|
CastTy = 0;
|
||||||
|
|
||||||
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
|
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
|
||||||
|
@ -1227,9 +1247,20 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
||||||
if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
|
if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
|
||||||
Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation());
|
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.
|
// 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();
|
TypeResult Ty = ParseTypeName();
|
||||||
|
|
||||||
// Match the ')'.
|
// Match the ')'.
|
||||||
|
|
|
@ -1038,3 +1038,110 @@ Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
|
||||||
|
|
||||||
return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -287,7 +287,9 @@ bool Parser::isCXXConditionDeclaration() {
|
||||||
/// type-id:
|
/// type-id:
|
||||||
/// type-specifier-seq abstract-declarator[opt]
|
/// type-specifier-seq abstract-declarator[opt]
|
||||||
///
|
///
|
||||||
bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context) {
|
bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
|
||||||
|
|
||||||
|
isAmbiguous = false;
|
||||||
|
|
||||||
// C++ 8.2p2:
|
// C++ 8.2p2:
|
||||||
// The ambiguity arising from the similarity between a function-style cast and
|
// The ambiguity arising from the similarity between a function-style cast and
|
||||||
|
@ -326,16 +328,20 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context) {
|
||||||
if (TPR == TPResult::Ambiguous()) {
|
if (TPR == TPResult::Ambiguous()) {
|
||||||
// We are supposed to be inside parens, so if after the abstract declarator
|
// 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.
|
// 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();
|
TPR = TPResult::True();
|
||||||
|
isAmbiguous = true;
|
||||||
|
|
||||||
// We are supposed to be inside a template argument, so if after
|
// We are supposed to be inside a template argument, so if after
|
||||||
// the abstract declarator we encounter a '>', '>>' (in C++0x), or
|
// the abstract declarator we encounter a '>', '>>' (in C++0x), or
|
||||||
// ',', this is a type-id. Otherwise, it's an expression.
|
// ',', this is a type-id. Otherwise, it's an expression.
|
||||||
else if (Context == TypeIdAsTemplateArgument &&
|
} else if (Context == TypeIdAsTemplateArgument &&
|
||||||
(Tok.is(tok::greater) || Tok.is(tok::comma) ||
|
(Tok.is(tok::greater) || Tok.is(tok::comma) ||
|
||||||
(getLang().CPlusPlus0x && Tok.is(tok::greatergreater))))
|
(getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
|
||||||
TPR = TPResult::True();
|
TPR = TPResult::True();
|
||||||
else
|
isAmbiguous = true;
|
||||||
|
|
||||||
|
} else
|
||||||
TPR = TPResult::False();
|
TPR = TPResult::False();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue