diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2011-04-15 00:35:48 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2011-04-15 00:35:48 +0000 |
commit | f111d935722ed488144600cea5ed03a6b5069e8f (patch) | |
tree | b9890fee5ac2d94380e448777c0a49223fbc578d /lib/Parse/ParseExpr.cpp | |
parent | 7e7fbd05a5dfdb0addfc8b5af2fcbed8c7b5fb87 (diff) |
C1X: implement generic selections
As an extension, generic selection support has been added for all
supported languages. The syntax is the same as for C1X.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129554 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseExpr.cpp')
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d8d73e9239..cf852f82e5 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -465,6 +465,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [C++] boolean-literal [C++ 2.13.5] /// [C++0x] 'nullptr' [C++0x 2.14.7] /// '(' expression ')' +/// [C1X] generic-selection /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' @@ -731,6 +732,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::wide_string_literal: Res = ParseStringLiteralExpression(); break; + case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1] + Res = ParseGenericSelectionExpression(); + break; case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: @@ -1802,6 +1806,100 @@ ExprResult Parser::ParseStringLiteralExpression() { return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); } +/// ParseGenericSelectionExpression - Parse a C1X generic-selection +/// [C1X 6.5.1.1]. +/// +/// generic-selection: +/// _Generic ( assignment-expression , generic-assoc-list ) +/// generic-assoc-list: +/// generic-association +/// generic-assoc-list , generic-association +/// generic-association: +/// type-name : assignment-expression +/// default : assignment-expression +ExprResult Parser::ParseGenericSelectionExpression() { + assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); + SourceLocation KeyLoc = ConsumeToken(); + + if (!getLang().C1X) + Diag(KeyLoc, diag::ext_c1x_generic_selection); + + SourceLocation LParenLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + return ExprError(); + + ExprResult ControllingExpr; + { + // C1X 6.5.1.1p3 "The controlling expression of a generic selection is + // not evaluated." + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + ControllingExpr = ParseAssignmentExpression(); + if (ControllingExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + SourceLocation DefaultLoc; + TypeVector Types(Actions); + ExprVector Exprs(Actions); + while (1) { + ParsedType Ty; + if (Tok.is(tok::kw_default)) { + // C1X 6.5.1.1p2 "A generic selection shall have no more than one default + // generic association." + if (!DefaultLoc.isInvalid()) { + Diag(Tok, diag::err_duplicate_default_assoc); + Diag(DefaultLoc, diag::note_previous_default_assoc); + SkipUntil(tok::r_paren); + return ExprError(); + } + DefaultLoc = ConsumeToken(); + Ty = ParsedType(); + } else { + ColonProtectionRAIIObject X(*this); + TypeResult TR = ParseTypeName(); + if (TR.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + Ty = TR.release(); + } + Types.push_back(Ty); + + if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + // FIXME: These expressions should be parsed in a potentially potentially + // evaluated context. + ExprResult ER(ParseAssignmentExpression()); + if (ER.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + Exprs.push_back(ER.release()); + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); + } + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return ExprError(); + + return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + ControllingExpr.release(), + move_arg(Types), move_arg(Exprs)); +} + /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// argument-expression-list: |