forked from OSchip/llvm-project
[ObjC] Implement @available in the Parser and AST
This patch adds a new AST node: ObjCAvailabilityCheckExpr, and teaches the Parser and Sema to generate it. This node represents an availability check of the form: @available(macos 10.10, *); Which will eventually compile to a runtime check of the host's OS version. This is the first patch of the feature I proposed here: http://lists.llvm.org/pipermail/cfe-dev/2016-July/049851.html Differential Revision: https://reviews.llvm.org/D22171 llvm-svn: 275654
This commit is contained in:
parent
21b3a032af
commit
29099ded0c
|
@ -2014,7 +2014,11 @@ enum CXCursorKind {
|
|||
*/
|
||||
CXCursor_OMPArraySectionExpr = 147,
|
||||
|
||||
CXCursor_LastExpr = CXCursor_OMPArraySectionExpr,
|
||||
/** \brief Represents an @available(...) check.
|
||||
*/
|
||||
CXCursor_ObjCAvailabilityCheckExpr = 148,
|
||||
|
||||
CXCursor_LastExpr = CXCursor_ObjCAvailabilityCheckExpr,
|
||||
|
||||
/* Statements */
|
||||
CXCursor_FirstStmt = 200,
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
//===--- Availability.h - Classes for availability --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files defines some classes that implement availability checking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_AVAILABILITY_H
|
||||
#define LLVM_CLANG_AST_AVAILABILITY_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief One specifier in an @available expression.
|
||||
///
|
||||
/// \code
|
||||
/// @available(macos 10.10, *)
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, 'macos 10.10' and '*' both map to an instance of this type.
|
||||
///
|
||||
class AvailabilitySpec {
|
||||
/// Represents the version that this specifier requires. If the host OS
|
||||
/// version is greater than or equal to Version, the @available will evaluate
|
||||
/// to true.
|
||||
VersionTuple Version;
|
||||
|
||||
/// Name of the platform that Version corresponds to.
|
||||
StringRef Platform;
|
||||
|
||||
SourceLocation BeginLoc, EndLoc;
|
||||
|
||||
public:
|
||||
AvailabilitySpec(VersionTuple Version, StringRef Platform,
|
||||
SourceLocation BeginLoc, SourceLocation EndLoc)
|
||||
: Version(Version), Platform(Platform), BeginLoc(BeginLoc),
|
||||
EndLoc(EndLoc) {}
|
||||
|
||||
/// This constructor is used when representing the '*' case.
|
||||
AvailabilitySpec(SourceLocation StarLoc)
|
||||
: BeginLoc(StarLoc), EndLoc(StarLoc) {}
|
||||
|
||||
VersionTuple getVersion() const { return Version; }
|
||||
StringRef getPlatform() const { return Platform; }
|
||||
SourceLocation getBeginLoc() const { return BeginLoc; }
|
||||
SourceLocation getEndLoc() const { return EndLoc; }
|
||||
|
||||
/// Returns true when this represents the '*' case.
|
||||
bool isOtherPlatformSpec() const { return Version.empty(); }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -1563,6 +1563,51 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief A runtime availability query.
|
||||
///
|
||||
/// There are 2 ways to spell this node:
|
||||
/// \code
|
||||
/// @available(macos 10.10, ios 8, *); // Objective-C
|
||||
/// __builtin_available(macos 10.10, ios 8, *); // C, C++, and Objective-C
|
||||
/// \endcode
|
||||
///
|
||||
/// Note that we only need to keep track of one \c VersionTuple here, which is
|
||||
/// the one that corresponds to the current deployment target. This is meant to
|
||||
/// be used in the condition of an \c if, but it is also usable as top level
|
||||
/// expressions.
|
||||
///
|
||||
class ObjCAvailabilityCheckExpr : public Expr {
|
||||
VersionTuple VersionToCheck;
|
||||
SourceLocation AtLoc, RParen;
|
||||
|
||||
friend class ASTStmtReader;
|
||||
public:
|
||||
ObjCAvailabilityCheckExpr(VersionTuple VersionToCheck, SourceLocation AtLoc,
|
||||
SourceLocation RParen, QualType Ty)
|
||||
: Expr(ObjCAvailabilityCheckExprClass, Ty, VK_RValue, OK_Ordinary, false,
|
||||
false, false, false),
|
||||
VersionToCheck(VersionToCheck), AtLoc(AtLoc), RParen(RParen) {}
|
||||
|
||||
explicit ObjCAvailabilityCheckExpr(EmptyShell Shell)
|
||||
: Expr(ObjCAvailabilityCheckExprClass, Shell) {}
|
||||
|
||||
SourceLocation getLocStart() const { return AtLoc; }
|
||||
SourceLocation getLocEnd() const { return RParen; }
|
||||
SourceRange getSourceRange() const { return {AtLoc, RParen}; }
|
||||
|
||||
/// \brief This may be '*', in which case this should fold to true.
|
||||
bool hasVersion() const { return !VersionToCheck.empty(); }
|
||||
VersionTuple getVersion() { return VersionToCheck; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAvailabilityCheckExprClass;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2352,6 +2352,7 @@ DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, {})
|
|||
DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
|
||||
})
|
||||
DEF_TRAVERSE_STMT(ObjCAvailabilityCheckExpr, {})
|
||||
DEF_TRAVERSE_STMT(ParenExpr, {})
|
||||
DEF_TRAVERSE_STMT(ParenListExpr, {})
|
||||
DEF_TRAVERSE_STMT(PredefinedExpr, {})
|
||||
|
|
|
@ -96,6 +96,7 @@ def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
|
|||
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
||||
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
|
||||
def PartialAvailability : DiagGroup<"partial-availability">;
|
||||
def UnguardedAvailability : DiagGroup<"unguarded-availability">;
|
||||
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
||||
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
|
||||
def DeprecatedRegister : DiagGroup<"deprecated-register">;
|
||||
|
|
|
@ -823,6 +823,21 @@ def warn_availability_and_unavailable : Warning<
|
|||
"'unavailable' availability overrides all other availability information">,
|
||||
InGroup<Availability>;
|
||||
|
||||
// @available(...)
|
||||
def err_avail_query_expected_condition : Error<
|
||||
"expected an availability condition here">;
|
||||
def err_avail_query_expected_platform_name : Error<
|
||||
"expected a platform name here">;
|
||||
|
||||
def err_avail_query_unrecognized_platform_name : Error<
|
||||
"unrecognized platform name %0">;
|
||||
def err_availability_query_wildcard_required: Error<
|
||||
"must handle potential future platforms with '*'">;
|
||||
def err_availability_query_repeated_platform: Error<
|
||||
"version for '%0' already specified">;
|
||||
def err_availability_query_repeated_star : Error<
|
||||
"'*' query has already been specified">;
|
||||
|
||||
// Type safety attributes
|
||||
def err_type_safety_unknown_flag : Error<
|
||||
"invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">;
|
||||
|
|
|
@ -2599,6 +2599,9 @@ def note_overridden_method : Note<
|
|||
def note_protocol_method : Note<
|
||||
"protocol method is here">;
|
||||
|
||||
def warn_available_using_star_case : Warning<
|
||||
"using '*' case here, platform %0 is not accounted for">, InGroup<UnguardedAvailability>;
|
||||
|
||||
// Thread Safety Attributes
|
||||
def warn_invalid_capability_name : Warning<
|
||||
"invalid capability name '%0'; capability name must be 'mutex' or 'role'">,
|
||||
|
|
|
@ -165,6 +165,7 @@ def ObjCIsaExpr : DStmt<Expr>;
|
|||
def ObjCIndirectCopyRestoreExpr : DStmt<Expr>;
|
||||
def ObjCBoolLiteralExpr : DStmt<Expr>;
|
||||
def ObjCSubscriptRefExpr : DStmt<Expr>;
|
||||
def ObjCAvailabilityCheckExpr : DStmt<Expr>;
|
||||
|
||||
// Obj-C ARC Expressions.
|
||||
def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>;
|
||||
|
|
|
@ -630,6 +630,8 @@ KEYWORD(__builtin_convertvector , KEYALL)
|
|||
ALIAS("__char16_t" , char16_t , KEYCXX)
|
||||
ALIAS("__char32_t" , char32_t , KEYCXX)
|
||||
|
||||
KEYWORD(__builtin_available , KEYALL)
|
||||
|
||||
// Clang-specific keywords enabled only in testing.
|
||||
TESTING_KEYWORD(__unknown_anytype , KEYALL)
|
||||
|
||||
|
@ -668,6 +670,7 @@ OBJC2_AT_KEYWORD(optional)
|
|||
OBJC2_AT_KEYWORD(synthesize)
|
||||
OBJC2_AT_KEYWORD(dynamic)
|
||||
OBJC2_AT_KEYWORD(import)
|
||||
OBJC2_AT_KEYWORD(available)
|
||||
|
||||
// TODO: What to do about context-sensitive keywords like:
|
||||
// bycopy/byref/in/inout/oneway/out?
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_PARSE_PARSER_H
|
||||
#define LLVM_CLANG_PARSE_PARSER_H
|
||||
|
||||
#include "clang/AST/Availability.h"
|
||||
#include "clang/Basic/OpenMPKinds.h"
|
||||
#include "clang/Basic/OperatorPrecedence.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
|
@ -2244,6 +2245,9 @@ private:
|
|||
SourceLocation ScopeLoc,
|
||||
AttributeList::Syntax Syntax);
|
||||
|
||||
Optional<AvailabilitySpec> ParseAvailabilitySpec();
|
||||
ExprResult ParseAvailabilityCheckExpr(SourceLocation StartLoc);
|
||||
|
||||
void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
|
||||
SourceLocation ObjCBridgeRelatedLoc,
|
||||
ParsedAttributes &attrs,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define LLVM_CLANG_SEMA_SEMA_H
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Availability.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
|
@ -4739,6 +4740,10 @@ public:
|
|||
/// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals.
|
||||
ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
|
||||
|
||||
ExprResult
|
||||
ActOnObjCAvailabilityCheckExpr(llvm::ArrayRef<AvailabilitySpec> AvailSpecs,
|
||||
SourceLocation AtLoc, SourceLocation RParen);
|
||||
|
||||
/// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
|
||||
ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc);
|
||||
|
||||
|
|
|
@ -1349,8 +1349,10 @@ namespace clang {
|
|||
STMT_OBJC_AT_THROW,
|
||||
/// \brief An ObjCAutoreleasePoolStmt record.
|
||||
STMT_OBJC_AUTORELEASE_POOL,
|
||||
/// \brief A ObjCBoolLiteralExpr record.
|
||||
/// \brief An ObjCBoolLiteralExpr record.
|
||||
EXPR_OBJC_BOOL_LITERAL,
|
||||
/// \brief An ObjCAvailabilityCheckExpr record.
|
||||
EXPR_OBJC_AVAILABILITY_CHECK,
|
||||
|
||||
// C++
|
||||
|
||||
|
|
|
@ -2856,6 +2856,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
|||
case ObjCStringLiteralClass:
|
||||
case ObjCEncodeExprClass:
|
||||
case ObjCBoolLiteralExprClass:
|
||||
case ObjCAvailabilityCheckExprClass:
|
||||
case CXXUuidofExprClass:
|
||||
case OpaqueValueExprClass:
|
||||
// These never have a side-effect.
|
||||
|
|
|
@ -178,6 +178,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
|||
case Expr::ObjCArrayLiteralClass:
|
||||
case Expr::ObjCDictionaryLiteralClass:
|
||||
case Expr::ObjCBoolLiteralExprClass:
|
||||
case Expr::ObjCAvailabilityCheckExprClass:
|
||||
case Expr::ParenListExprClass:
|
||||
case Expr::SizeOfPackExprClass:
|
||||
case Expr::SubstNonTypeTemplateParmPackExprClass:
|
||||
|
|
|
@ -9402,6 +9402,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
|
|||
case Expr::ObjCPropertyRefExprClass:
|
||||
case Expr::ObjCSubscriptRefExprClass:
|
||||
case Expr::ObjCIsaExprClass:
|
||||
case Expr::ObjCAvailabilityCheckExprClass:
|
||||
case Expr::ShuffleVectorExprClass:
|
||||
case Expr::ConvertVectorExprClass:
|
||||
case Expr::BlockExprClass:
|
||||
|
|
|
@ -3239,6 +3239,7 @@ recurse:
|
|||
case Expr::ObjCDictionaryLiteralClass:
|
||||
case Expr::ObjCSubscriptRefExprClass:
|
||||
case Expr::ObjCIndirectCopyRestoreExprClass:
|
||||
case Expr::ObjCAvailabilityCheckExprClass:
|
||||
case Expr::OffsetOfExprClass:
|
||||
case Expr::PredefinedExprClass:
|
||||
case Expr::ShuffleVectorExprClass:
|
||||
|
|
|
@ -497,6 +497,11 @@ void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) {
|
|||
OS << ";\n";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCAvailabilityCheckExpr(
|
||||
ObjCAvailabilityCheckExpr *Node) {
|
||||
OS << "@available(...)";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
|
||||
Indent() << "@synchronized (";
|
||||
PrintExpr(Node->getSynchExpr());
|
||||
|
|
|
@ -1632,6 +1632,11 @@ void StmtProfiler::VisitObjCBridgedCastExpr(const ObjCBridgedCastExpr *S) {
|
|||
ID.AddBoolean(S->getBridgeKind());
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitObjCAvailabilityCheckExpr(
|
||||
const ObjCAvailabilityCheckExpr *S) {
|
||||
VisitExpr(S);
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitDecl(const Decl *D) {
|
||||
ID.AddInteger(D? D->getKind() : 0);
|
||||
|
||||
|
|
|
@ -720,7 +720,7 @@ static bool VersionNumberSeparator(const char Separator) {
|
|||
/// simple-integer ',' simple-integer
|
||||
/// simple-integer ',' simple-integer ',' simple-integer
|
||||
VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
|
||||
Range = Tok.getLocation();
|
||||
Range = SourceRange(Tok.getLocation(), Tok.getEndLoc());
|
||||
|
||||
if (!Tok.is(tok::numeric_constant)) {
|
||||
Diag(Tok, diag::err_expected_version);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -2858,6 +2858,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
|||
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
|
||||
case tok::objc_selector:
|
||||
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
|
||||
case tok::objc_available:
|
||||
return ParseAvailabilityCheckExpr(AtLoc);
|
||||
default: {
|
||||
const char *str = nullptr;
|
||||
if (GetLookAheadToken(1).is(tok::l_brace)) {
|
||||
|
|
|
@ -1146,6 +1146,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
|
|||
case Expr::ObjCIndirectCopyRestoreExprClass:
|
||||
case Expr::ObjCProtocolExprClass:
|
||||
case Expr::ObjCSelectorExprClass:
|
||||
case Expr::ObjCAvailabilityCheckExprClass:
|
||||
case Expr::OffsetOfExprClass:
|
||||
case Expr::PackExpansionExprClass:
|
||||
case Expr::PseudoObjectExprClass:
|
||||
|
|
|
@ -15083,3 +15083,27 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
|
|||
return new (Context)
|
||||
ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc);
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
|
||||
llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc,
|
||||
SourceLocation RParen) {
|
||||
|
||||
StringRef Platform = getASTContext().getTargetInfo().getPlatformName();
|
||||
|
||||
auto Spec = std::find_if(AvailSpecs.begin(), AvailSpecs.end(),
|
||||
[&](const AvailabilitySpec &Spec) {
|
||||
return Spec.getPlatform() == Platform;
|
||||
});
|
||||
|
||||
VersionTuple Version;
|
||||
if (Spec != AvailSpecs.end())
|
||||
Version = Spec->getVersion();
|
||||
else
|
||||
// This is the '*' case in @available. We should diagnose this; the
|
||||
// programmer should explicitly account for this case if they target this
|
||||
// platform.
|
||||
Diag(AtLoc, diag::warn_available_using_star_case) << RParen << Platform;
|
||||
|
||||
return new (Context)
|
||||
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
|
||||
}
|
||||
|
|
|
@ -11112,6 +11112,12 @@ TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
|
|||
Result.get());
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
ExprResult TreeTransform<Derived>::TransformObjCAvailabilityCheckExpr(
|
||||
ObjCAvailabilityCheckExpr *E) {
|
||||
return E;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
|
||||
|
|
|
@ -1182,6 +1182,14 @@ void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
|
|||
E->setLocation(ReadSourceLocation(Record, Idx));
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
|
||||
VisitExpr(E);
|
||||
SourceRange R = Reader.ReadSourceRange(F, Record, Idx);
|
||||
E->AtLoc = R.getBegin();
|
||||
E->RParen = R.getEnd();
|
||||
E->VersionToCheck = Reader.ReadVersionTuple(Record, Idx);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C++ Expressions and Statements
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -3221,6 +3229,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
|||
case EXPR_OBJC_BOOL_LITERAL:
|
||||
S = new (Context) ObjCBoolLiteralExpr(Empty);
|
||||
break;
|
||||
case EXPR_OBJC_AVAILABILITY_CHECK:
|
||||
S = new (Context) ObjCAvailabilityCheckExpr(Empty);
|
||||
break;
|
||||
case STMT_SEH_LEAVE:
|
||||
S = new (Context) SEHLeaveStmt(Empty);
|
||||
break;
|
||||
|
|
|
@ -1142,6 +1142,13 @@ void ASTStmtWriter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
|
|||
Code = serialization::EXPR_OBJC_BOOL_LITERAL;
|
||||
}
|
||||
|
||||
void ASTStmtWriter::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
|
||||
VisitExpr(E);
|
||||
Record.AddSourceRange(E->getSourceRange());
|
||||
Record.AddVersionTuple(E->getVersion());
|
||||
Code = serialization::EXPR_OBJC_AVAILABILITY_CHECK;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C++ Expressions and Statements.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -916,6 +916,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
case Stmt::CXXScalarValueInitExprClass:
|
||||
case Stmt::CXXBoolLiteralExprClass:
|
||||
case Stmt::ObjCBoolLiteralExprClass:
|
||||
case Stmt::ObjCAvailabilityCheckExprClass:
|
||||
case Stmt::FloatingLiteralClass:
|
||||
case Stmt::NoInitExprClass:
|
||||
case Stmt::SizeOfPackExprClass:
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -triple x86_64-apple-macosx10.10.0 -verify %s
|
||||
|
||||
void f() {
|
||||
|
||||
if (@available(macos 10.12, *)) {}
|
||||
else if (@available(macos 10.11, *)) {}
|
||||
else {}
|
||||
|
||||
(void)__builtin_available(ios 8, macos 10.10, *);
|
||||
|
||||
(void)@available(macos 10.11); // expected-error{{must handle potential future platforms with '*'}}
|
||||
(void)@available(macos 10.11, macos 10.11, *); // expected-error{{version for 'macos' already specified}}
|
||||
|
||||
(void)@available(erik_os 10.11, *); // expected-error{{unrecognized platform name erik_os}}
|
||||
|
||||
(void)@available(erik_os 10.10, hat_os 1.0, *); // expected-error 2 {{unrecognized platform name}}
|
||||
|
||||
(void)@available(ios 8, *); // expected-warning{{using '*' case here, platform macos is not accounted for}}
|
||||
|
||||
(void)@available(); // expected-error{{expected a platform name here}}
|
||||
(void)@available(macos 10.10,); // expected-error{{expected a platform name here}}
|
||||
(void)@available(macos); // expected-error{{expected a version}}
|
||||
(void)@available; // expected-error{{expected '('}}
|
||||
}
|
|
@ -4611,6 +4611,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
|
|||
return cxstring::createRef("ObjCStringLiteral");
|
||||
case CXCursor_ObjCBoolLiteralExpr:
|
||||
return cxstring::createRef("ObjCBoolLiteralExpr");
|
||||
case CXCursor_ObjCAvailabilityCheckExpr:
|
||||
return cxstring::createRef("ObjCAvailabilityCheckExpr");
|
||||
case CXCursor_ObjCSelfExpr:
|
||||
return cxstring::createRef("ObjCSelfExpr");
|
||||
case CXCursor_ObjCEncodeExpr:
|
||||
|
|
|
@ -448,6 +448,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
|
|||
K = CXCursor_ObjCBoolLiteralExpr;
|
||||
break;
|
||||
|
||||
case Stmt::ObjCAvailabilityCheckExprClass:
|
||||
K = CXCursor_ObjCAvailabilityCheckExpr;
|
||||
break;
|
||||
|
||||
case Stmt::ObjCBridgedCastExprClass:
|
||||
K = CXCursor_ObjCBridgedCastExpr;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue