summaryrefslogtreecommitdiff
path: root/lib/Parse/ParseExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseExpr.cpp')
-rw-r--r--lib/Parse/ParseExpr.cpp179
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());
+}