|
@@ -1009,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:
|
|
@@ -2869,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());
|
|
|
+}
|