Skip to content

Commit ceaa5db

Browse files
authored
Merge pull request #17960 from danielmartin/new-unary-operator-ifconfig
[Parser] Support "<" unary operator in #if swift() and #if compiler() expressions
2 parents 61057b8 + 5d6f4f6 commit ceaa5db

File tree

5 files changed

+93
-18
lines changed

5 files changed

+93
-18
lines changed

include/swift/Basic/Version.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ class Version {
161161
};
162162

163163
bool operator>=(const Version &lhs, const Version &rhs);
164+
bool operator<(const Version &lhs, const Version &rhs);
164165
bool operator==(const Version &lhs, const Version &rhs);
165166
inline bool operator!=(const Version &lhs, const Version &rhs) {
166167
return !(lhs == rhs);

lib/Basic/Version.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,11 @@ bool operator>=(const class Version &lhs,
384384
return true;
385385
}
386386

387+
bool operator<(const class Version &lhs, const class Version &rhs) {
388+
389+
return !(lhs >= rhs);
390+
}
391+
387392
bool operator==(const class Version &lhs,
388393
const class Version &rhs) {
389394
auto n = std::max(lhs.size(), rhs.size());
@@ -446,4 +451,3 @@ std::string getSwiftRevision() {
446451

447452
} // end namespace version
448453
} // end namespace swift
449-

lib/Parse/ParseIfConfig.cpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace {
3636
/// Get PlatformConditionKind from platform condition name.
3737
static
3838
Optional<PlatformConditionKind> getPlatformConditionKind(StringRef Name) {
39-
return llvm::StringSwitch<llvm::Optional<PlatformConditionKind>>(Name)
39+
return llvm::StringSwitch<Optional<PlatformConditionKind>>(Name)
4040
.Case("os", PlatformConditionKind::OS)
4141
.Case("arch", PlatformConditionKind::Arch)
4242
.Case("_endian", PlatformConditionKind::Endianness)
@@ -53,6 +53,20 @@ static StringRef extractExprSource(SourceManager &SM, Expr *E) {
5353
return SM.extractText(Range);
5454
}
5555

56+
static bool isValidPrefixUnaryOperator(Optional<StringRef> UnaryOperator) {
57+
return UnaryOperator != None &&
58+
(UnaryOperator.getValue() == ">=" || UnaryOperator.getValue() == "<");
59+
}
60+
61+
static bool isValidVersion(const version::Version &Version,
62+
const version::Version &ExpectedVersion,
63+
StringRef UnaryOperator) {
64+
if (UnaryOperator == ">=")
65+
return Version >= ExpectedVersion;
66+
if (UnaryOperator == "<")
67+
return Version < ExpectedVersion;
68+
llvm_unreachable("unsupported unary operator");
69+
}
5670

5771
/// The condition validator.
5872
class ValidateIfConfigCondition :
@@ -63,7 +77,7 @@ class ValidateIfConfigCondition :
6377
bool HasError;
6478

6579
/// Get the identifier string of the UnresolvedDeclRefExpr.
66-
llvm::Optional<StringRef> getDeclRefStr(Expr *E, DeclRefKind Kind) {
80+
Optional<StringRef> getDeclRefStr(Expr *E, DeclRefKind Kind) {
6781
auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(E);
6882
if (!UDRE ||
6983
!UDRE->hasName() ||
@@ -85,7 +99,7 @@ class ValidateIfConfigCondition :
8599
Expr *foldSequence(Expr *LHS, ArrayRef<Expr*> &S, bool isRecurse = false) {
86100
assert(!S.empty() && ((S.size() & 1) == 0));
87101

88-
auto getNextOperator = [&]() -> llvm::Optional<StringRef> {
102+
auto getNextOperator = [&]() -> Optional<StringRef> {
89103
assert((S.size() & 1) == 0);
90104
while (!S.empty()) {
91105
auto Name = getDeclRefStr(S[0], DeclRefKind::BinaryOperator);
@@ -109,7 +123,7 @@ class ValidateIfConfigCondition :
109123
// If failed, it's not a sequence anymore.
110124
return LHS;
111125
Expr *Op = S[0];
112-
126+
113127
// We will definitely be consuming at least one operator.
114128
// Pull out the prospective RHS and slice off the first two elements.
115129
Expr *RHS = validate(S[1]);
@@ -216,16 +230,16 @@ class ValidateIfConfigCondition :
216230
return E;
217231
}
218232

219-
// 'swift' '(' '>=' float-literal ( '.' integer-literal )* ')'
220-
// 'compiler' '(' '>=' float-literal ( '.' integer-literal )* ')'
233+
// 'swift' '(' ('>=' | '<') float-literal ( '.' integer-literal )* ')'
234+
// 'compiler' '(' ('>=' | '<') float-literal ( '.' integer-literal )* ')'
221235
if (*KindName == "swift" || *KindName == "compiler") {
222236
auto PUE = dyn_cast<PrefixUnaryExpr>(Arg);
223-
llvm::Optional<StringRef> PrefixName = PUE ?
224-
getDeclRefStr(PUE->getFn(), DeclRefKind::PrefixOperator) : None;
225-
if (!PrefixName || *PrefixName != ">=") {
226-
D.diagnose(Arg->getLoc(),
227-
diag::unsupported_platform_condition_argument,
228-
"a unary comparison, such as '>=2.2'");
237+
Optional<StringRef> PrefixName =
238+
PUE ? getDeclRefStr(PUE->getFn(), DeclRefKind::PrefixOperator) : None;
239+
if (!isValidPrefixUnaryOperator(PrefixName)) {
240+
D.diagnose(
241+
Arg->getLoc(), diag::unsupported_platform_condition_argument,
242+
"a unary comparison '>=' or '<'; for example, '>=2.2' or '<2.2'");
229243
return nullptr;
230244
}
231245
auto versionString = extractExprSource(Ctx.SourceMgr, PUE->getArg());
@@ -382,13 +396,17 @@ class EvaluateIfConfigCondition :
382396
return thisVersion >= Val;
383397
} else if ((KindName == "swift") || (KindName == "compiler")) {
384398
auto PUE = cast<PrefixUnaryExpr>(Arg);
399+
auto PrefixName = getDeclRefStr(PUE->getFn());
385400
auto Str = extractExprSource(Ctx.SourceMgr, PUE->getArg());
386401
auto Val = version::Version::parseVersionString(
387402
Str, SourceLoc(), nullptr).getValue();
388403
if (KindName == "swift") {
389-
return Ctx.LangOpts.EffectiveLanguageVersion >= Val;
404+
return isValidVersion(Ctx.LangOpts.EffectiveLanguageVersion, Val,
405+
PrefixName);
390406
} else if (KindName == "compiler") {
391-
return version::Version::getCurrentLanguageVersion() >= Val;
407+
auto currentLanguageVersion =
408+
version::Version::getCurrentLanguageVersion();
409+
return isValidVersion(currentLanguageVersion, Val, PrefixName);
392410
} else {
393411
llvm_unreachable("unsupported version conditional");
394412
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-typecheck-verify-swift -swift-version 4
3+
4+
#if !compiler(>=4.1)
5+
// There should be no error here.
6+
foo bar
7+
#else
8+
let _: Int = 1
9+
#endif
10+
11+
#if compiler(<4.1)
12+
// There should be no error here.
13+
foo bar
14+
#else
15+
let _: Int = 1
16+
#endif
17+
18+
#if (compiler(>=4.1))
19+
let _: Int = 1
20+
#else
21+
// There should be no error here.
22+
foo bar
23+
#endif
24+
25+
#if !compiler(<4.1)
26+
let _: Int = 1
27+
#else
28+
// There should be no error here.
29+
foo bar
30+
#endif

test/Parse/ConditionalCompilation/language_version.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77
asdf asdf asdf asdf
88
#endif
99

10+
#if swift(<1.2)
11+
#endif
12+
13+
#if swift(<4.2)
14+
let a = 1
15+
#else
16+
let a = 2
17+
#endif
18+
19+
#if swift(<1.0)
20+
// This shouldn't emit any diagnostics.
21+
asdf asdf asdf asdf
22+
#endif
23+
1024
#if swift(>=1.2)
1125

1226
#if os(iOS)
@@ -34,13 +48,21 @@
3448
%#^*&
3549
#endif
3650

37-
#if swift(">=7.1") // expected-error {{unexpected platform condition argument: expected a unary comparison, such as '>=2.2'}}
51+
#if !swift(<1000.0)
52+
// This shouldn't emit any diagnostics.
53+
%#^*&
54+
#endif
55+
56+
#if swift(">=7.1") // expected-error {{unexpected platform condition argument: expected a unary comparison '>=' or '<'; for example, '>=2.2' or '<2.2'}}
57+
#endif
58+
59+
#if swift("<7.1") // expected-error {{unexpected platform condition argument: expected a unary comparison '>=' or '<'; for example, '>=2.2' or '<2.2'}}
3860
#endif
3961

40-
#if swift(">=2n.2") // expected-error {{unexpected platform condition argument: expected a unary comparison, such as '>=2.2'}}
62+
#if swift(">=2n.2") // expected-error {{unexpected platform condition argument: expected a unary comparison '>=' or '<'; for example, '>=2.2' or '<2.2'}}
4163
#endif
4264

43-
#if swift("") // expected-error {{unexpected platform condition argument: expected a unary comparison, such as '>=2.2'}}
65+
#if swift("") // expected-error {{unexpected platform condition argument: expected a unary comparison '>=' or '<'; for example, '>=2.2' or '<2.2'}}
4466
#endif
4567

4668
#if swift(>=2.2.1)

0 commit comments

Comments
 (0)