diff options
Diffstat (limited to 'lib/Parse/ParseExpr.cpp')
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 179 |
1 files changed, 164 insertions, 15 deletions
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1fd98c140e0e..47d1326b7989 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -263,6 +263,9 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { Token OpToken = Tok; ConsumeToken(); + if (OpToken.is(tok::caretcaret)) { + return ExprError(Diag(Tok, diag::err_opencl_logical_exclusive_or)); + } // Bail out when encountering a comma followed by a token which can't // possibly be the start of an expression. For instance: // int f() { return 1, } @@ -428,6 +431,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } + ExprResult OrigLHS = LHS; if (!LHS.isInvalid()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { @@ -442,13 +446,22 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), OpToken.getKind(), LHS.get(), RHS.get()); - } else + + // In this case, ActOnBinOp performed the CorrectDelayedTyposInExpr check. + if (!getLangOpts().CPlusPlus) + continue; + } else { LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, LHS.get(), TernaryMiddle.get(), RHS.get()); - } else - // Ensure potential typos in the RHS aren't left undiagnosed. + } + } + // Ensure potential typos aren't left undiagnosed. + if (LHS.isInvalid()) { + Actions.CorrectDelayedTyposInExpr(OrigLHS); + Actions.CorrectDelayedTyposInExpr(TernaryMiddle); Actions.CorrectDelayedTyposInExpr(RHS); + } } } @@ -513,7 +526,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// \p 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. +/// diagnostic is emitted in this case and no tokens are consumed. /// /// \verbatim /// cast-expression: [C99 6.5.4] @@ -787,6 +800,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, REVERTIBLE_TYPE_TRAIT(__is_abstract); REVERTIBLE_TYPE_TRAIT(__is_arithmetic); REVERTIBLE_TYPE_TRAIT(__is_array); + REVERTIBLE_TYPE_TRAIT(__is_assignable); REVERTIBLE_TYPE_TRAIT(__is_base_of); REVERTIBLE_TYPE_TRAIT(__is_class); REVERTIBLE_TYPE_TRAIT(__is_complete_type); @@ -895,7 +909,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ((Tok.is(tok::identifier) && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || Tok.is(tok::code_completion))) { - Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(), + Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr, nullptr); break; } @@ -995,6 +1009,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] Res = ParseGenericSelectionExpression(); break; + case tok::kw___builtin_available: + return ParseAvailabilityCheckExpr(Tok.getLocation()); case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: @@ -1010,15 +1026,24 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // unary-expression: // ++ cast-expression // -- cast-expression - SourceLocation SavedLoc = ConsumeToken(); + Token SavedTok = Tok; + ConsumeToken(); // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. Res = ParseCastExpression(!getLangOpts().CPlusPlus, /*isAddressOfOperand*/false, NotCastExpr, NotTypeCast); + if (NotCastExpr) { + // If we return with NotCastExpr = true, we must not consume any tokens, + // so put the token back where we found it. + assert(Res.isInvalid()); + UnconsumeToken(SavedTok); + return ExprError(); + } if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); + Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(), + SavedKind, Res.get()); return Res; } case tok::amp: { // unary-expression: '&' cast-expression @@ -1148,10 +1173,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: - case tok::kw___vector: { + case tok::kw___vector: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" + { if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); @@ -1204,7 +1233,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, @@ -1395,7 +1424,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (getLangOpts().ObjC1 && !InMessageExpression && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), - ParsedType(), LHS.get()); + nullptr, LHS.get()); break; } @@ -1416,8 +1445,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. - if (CheckProhibitedCXX11Attribute()) + if (CheckProhibitedCXX11Attribute()) { + (void)Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); + } BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); @@ -1445,6 +1476,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { SourceLocation RLoc = Tok.getLocation(); + ExprResult OrigLHS = LHS; if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && Tok.is(tok::r_square)) { if (ColonLoc.isValid()) { @@ -1455,7 +1487,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Idx.get(), RLoc); } } else { - (void)Actions.CorrectDelayedTyposInExpr(LHS); + LHS = ExprError(); + } + if (LHS.isInvalid()) { + (void)Actions.CorrectDelayedTyposInExpr(OrigLHS); (void)Actions.CorrectDelayedTyposInExpr(Idx); (void)Actions.CorrectDelayedTyposInExpr(Length); LHS = ExprError(); @@ -1606,7 +1641,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /*EnteringContext=*/false, &MayBePseudoDestructor); if (SS.isNotEmpty()) - ObjectType = ParsedType(); + ObjectType = nullptr; } if (Tok.is(tok::code_completion)) { @@ -2160,7 +2195,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, ExprResult Result(true); bool isAmbiguousTypeId; - CastTy = ParsedType(); + CastTy = nullptr; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), @@ -2506,7 +2541,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { return ExprError(); } DefaultLoc = ConsumeToken(); - Ty = ParsedType(); + Ty = nullptr; } else { ColonProtectionRAIIObject X(*this); TypeResult TR = ParseTypeName(); @@ -2836,3 +2871,117 @@ ExprResult Parser::ParseObjCBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); } + +/// Validate availability spec list, emitting diagnostics if necessary. Returns +/// true if invalid. +static bool CheckAvailabilitySpecList(Parser &P, + ArrayRef<AvailabilitySpec> AvailSpecs) { + llvm::SmallSet<StringRef, 4> Platforms; + bool HasOtherPlatformSpec = false; + bool Valid = true; + for (const auto &Spec : AvailSpecs) { + if (Spec.isOtherPlatformSpec()) { + if (HasOtherPlatformSpec) { + P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_star); + Valid = false; + } + + HasOtherPlatformSpec = true; + continue; + } + + bool Inserted = Platforms.insert(Spec.getPlatform()).second; + if (!Inserted) { + // Rule out multiple version specs referring to the same platform. + // For example, we emit an error for: + // @available(macos 10.10, macos 10.11, *) + StringRef Platform = Spec.getPlatform(); + P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_platform) + << Spec.getEndLoc() << Platform; + Valid = false; + } + } + + if (!HasOtherPlatformSpec) { + SourceLocation InsertWildcardLoc = AvailSpecs.back().getEndLoc(); + P.Diag(InsertWildcardLoc, diag::err_availability_query_wildcard_required) + << FixItHint::CreateInsertion(InsertWildcardLoc, ", *"); + return true; + } + + return !Valid; +} + +/// Parse availability query specification. +/// +/// availability-spec: +/// '*' +/// identifier version-tuple +Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() { + if (Tok.is(tok::star)) { + return AvailabilitySpec(ConsumeToken()); + } else { + // Parse the platform name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_avail_query_expected_platform_name); + return None; + } + + IdentifierLoc *PlatformIdentifier = ParseIdentifierLoc(); + SourceRange VersionRange; + VersionTuple Version = ParseVersionTuple(VersionRange); + + if (Version.empty()) + return None; + + StringRef Platform = PlatformIdentifier->Ident->getName(); + + if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) { + Diag(PlatformIdentifier->Loc, + diag::err_avail_query_unrecognized_platform_name) + << Platform; + return None; + } + + return AvailabilitySpec(Version, Platform, PlatformIdentifier->Loc, + VersionRange.getEnd()); + } +} + +ExprResult Parser::ParseAvailabilityCheckExpr(SourceLocation BeginLoc) { + assert(Tok.is(tok::kw___builtin_available) || + Tok.isObjCAtKeyword(tok::objc_available)); + + // Eat the available or __builtin_available. + ConsumeToken(); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume()) + return ExprError(); + + SmallVector<AvailabilitySpec, 4> AvailSpecs; + bool HasError = false; + while (true) { + Optional<AvailabilitySpec> Spec = ParseAvailabilitySpec(); + if (!Spec) + HasError = true; + else + AvailSpecs.push_back(*Spec); + + if (!TryConsumeToken(tok::comma)) + break; + } + + if (HasError) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + CheckAvailabilitySpecList(*this, AvailSpecs); + + if (Parens.consumeClose()) + return ExprError(); + + return Actions.ActOnObjCAvailabilityCheckExpr(AvailSpecs, BeginLoc, + Parens.getCloseLocation()); +} |