Skip to content

Commit db35cab

Browse files
Merge pull request #33932 from rockbruno/negative-aval
[SE-0290] Add #unavailable (Negative platform checks)
2 parents 8226e54 + adfb983 commit db35cab

22 files changed

+588
-98
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,12 @@ WARNING(parameter_unnamed_warn,none,
931931
ERROR(parameter_curry_syntax_removed,none,
932932
"cannot have more than one parameter list", ())
933933

934+
ERROR(availability_cannot_be_mixed,none,
935+
"#available and #unavailable cannot be in the same statement", ())
936+
937+
ERROR(false_available_is_called_unavailable,none,
938+
"#available cannot be used as an expression, did you mean to use '#unavailable'?", ())
939+
934940
ERROR(initializer_as_typed_pattern,none,
935941
"unexpected initializer in pattern; did you mean to use '='?", ())
936942

@@ -1223,8 +1229,8 @@ ERROR(invalid_float_literal_missing_leading_zero,none,
12231229
"'.%0' is not a valid floating point literal; it must be written '0.%0'",
12241230
(StringRef))
12251231
ERROR(availability_query_outside_if_stmt_guard, none,
1226-
"#available may only be used as condition of an 'if', 'guard'"
1227-
" or 'while' statement", ())
1232+
"%0 may only be used as condition of an 'if', 'guard'"
1233+
" or 'while' statement", (StringRef))
12281234

12291235
ERROR(empty_arg_label_underscore, none,
12301236
"an empty argument label is spelled with '_'", ())
@@ -1812,14 +1818,17 @@ ERROR(avail_query_version_comparison_not_needed,
18121818
ERROR(availability_query_wildcard_required, none,
18131819
"must handle potential future platforms with '*'", ())
18141820

1821+
ERROR(unavailability_query_wildcard_not_required, none,
1822+
"platform wildcard '*' is always implicit in #unavailable", ())
1823+
18151824
ERROR(availability_must_occur_alone, none,
18161825
"'%0' version-availability must be specified alone", (StringRef))
18171826

18181827
ERROR(pound_available_swift_not_allowed, none,
1819-
"Swift language version checks not allowed in #available(...)", ())
1828+
"Swift language version checks not allowed in %0(...)", (StringRef))
18201829

18211830
ERROR(pound_available_package_description_not_allowed, none,
1822-
"PackageDescription version checks not allowed in #available(...)", ())
1831+
"PackageDescription version checks not allowed in %0(...)", (StringRef))
18231832

18241833
ERROR(availability_query_repeated_platform, none,
18251834
"version for '%0' already specified", (StringRef))

include/swift/AST/Stmt.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,17 @@ class alignas(8) PoundAvailableInfo final :
341341
/// This is filled in by Sema.
342342
VersionRange VariantAvailableRange;
343343

344+
/// Indicates that the expression is checking if a version range
345+
/// is **not** available.
346+
bool _isUnavailability;
347+
344348
PoundAvailableInfo(SourceLoc PoundLoc, SourceLoc LParenLoc,
345-
ArrayRef<AvailabilitySpec *> queries, SourceLoc RParenLoc)
349+
ArrayRef<AvailabilitySpec *> queries, SourceLoc RParenLoc,
350+
bool isUnavailability)
346351
: PoundLoc(PoundLoc), LParenLoc(LParenLoc), RParenLoc(RParenLoc),
347352
NumQueries(queries.size()), AvailableRange(VersionRange::empty()),
348-
VariantAvailableRange(VersionRange::empty()) {
353+
VariantAvailableRange(VersionRange::empty()),
354+
_isUnavailability(isUnavailability) {
349355
std::uninitialized_copy(queries.begin(), queries.end(),
350356
getTrailingObjects<AvailabilitySpec *>());
351357
}
@@ -354,7 +360,8 @@ class alignas(8) PoundAvailableInfo final :
354360
static PoundAvailableInfo *create(ASTContext &ctx, SourceLoc PoundLoc,
355361
SourceLoc LParenLoc,
356362
ArrayRef<AvailabilitySpec *> queries,
357-
SourceLoc RParenLoc);
363+
SourceLoc RParenLoc,
364+
bool isUnavailability);
358365

359366
ArrayRef<AvailabilitySpec *> getQueries() const {
360367
return llvm::makeArrayRef(getTrailingObjects<AvailabilitySpec *>(),
@@ -379,6 +386,8 @@ class alignas(8) PoundAvailableInfo final :
379386
void setVariantAvailableRange(const VersionRange &Range) {
380387
VariantAvailableRange = Range;
381388
}
389+
390+
bool isUnavailability() const { return _isUnavailability; }
382391
};
383392

384393

include/swift/Parse/Parser.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,11 +1769,21 @@ class Parser {
17691769
//===--------------------------------------------------------------------===//
17701770
// Availability Specification Parsing
17711771

1772+
/// The source of an availability spec list.
1773+
enum class AvailabilitySpecSource: uint8_t {
1774+
/// A spec from '@available(<spec>, ...)' or '#available(<spec>, ...)'.
1775+
Available,
1776+
/// A spec from '#unavailable(<spec>, ...)'.
1777+
Unavailable,
1778+
/// A spec from a '-define-availability "Name:<spec>, ..."' frontend arg.
1779+
Macro,
1780+
};
1781+
17721782
/// Parse a comma-separated list of availability specifications. Try to
1773-
/// expand availability macros when /p ParsingMacroDefinition is false.
1783+
/// expand availability macros when /p Source is not a command line macro.
17741784
ParserStatus
17751785
parseAvailabilitySpecList(SmallVectorImpl<AvailabilitySpec *> &Specs,
1776-
bool ParsingMacroDefinition = false);
1786+
AvailabilitySpecSource Source);
17771787

17781788
/// Does the current matches an argument macro name? Parsing compiler
17791789
/// arguments as required without consuming tokens from the source file

lib/AST/Stmt.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,15 +281,15 @@ void LabeledConditionalStmt::setCond(StmtCondition e) {
281281
Cond = e;
282282
}
283283

284-
PoundAvailableInfo *PoundAvailableInfo::create(ASTContext &ctx,
285-
SourceLoc PoundLoc,
286-
SourceLoc LParenLoc,
287-
ArrayRef<AvailabilitySpec *> queries,
288-
SourceLoc RParenLoc) {
284+
PoundAvailableInfo *
285+
PoundAvailableInfo::create(ASTContext &ctx, SourceLoc PoundLoc,
286+
SourceLoc LParenLoc,
287+
ArrayRef<AvailabilitySpec *> queries,
288+
SourceLoc RParenLoc, bool isUnavailability) {
289289
unsigned size = totalSizeToAlloc<AvailabilitySpec *>(queries.size());
290290
void *Buffer = ctx.Allocate(size, alignof(PoundAvailableInfo));
291291
return ::new (Buffer) PoundAvailableInfo(PoundLoc, LParenLoc, queries,
292-
RParenLoc);
292+
RParenLoc, isUnavailability);
293293
}
294294

295295
SourceLoc PoundAvailableInfo::getEndLoc() const {

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2294,7 +2294,8 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
22942294
peekAvailabilityMacroName())) {
22952295
// We have the short form of available: @available(iOS 8.0.1, *)
22962296
SmallVector<AvailabilitySpec *, 5> Specs;
2297-
ParserStatus Status = parseAvailabilitySpecList(Specs);
2297+
ParserStatus Status = parseAvailabilitySpecList(Specs,
2298+
AvailabilitySpecSource::Available);
22982299

22992300
if (Status.isErrorOrHasCompletion())
23002301
return false;

lib/Parse/ParseExpr.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
229229
// this, because then we can produce a fixit to rewrite the && into a ,
230230
// if we're in a stmt-condition.
231231
if (Tok.getText() == "&&" &&
232-
peekToken().isAny(tok::pound_available,
232+
peekToken().isAny(tok::pound_available, tok::pound_unavailable,
233233
tok::kw_let, tok::kw_var, tok::kw_case))
234234
goto done;
235235

@@ -1745,10 +1745,12 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
17451745
case tok::l_square:
17461746
return parseExprCollection();
17471747

1748-
case tok::pound_available: {
1749-
// For better error recovery, parse but reject #available in an expr
1748+
case tok::pound_available:
1749+
case tok::pound_unavailable: {
1750+
// For better error recovery, parse but reject availability in an expr
17501751
// context.
1751-
diagnose(Tok.getLoc(), diag::availability_query_outside_if_stmt_guard);
1752+
diagnose(Tok.getLoc(), diag::availability_query_outside_if_stmt_guard,
1753+
Tok.getText());
17521754
auto res = parseStmtConditionPoundAvailable();
17531755
if (res.hasCodeCompletion())
17541756
return makeParserCodeCompletionStatus();

0 commit comments

Comments
 (0)