Skip to content

Commit 8c5c5ec

Browse files
committed
[Parse] Support macCatalyst conditional compilation
Add support for conditional compilation under macCatalyst Developers can now detect whether they are compiling for macCatalyst at compile time with: #if targetEnvironment(macCatalyst) // Code only compiled under macCatalyst. #end
1 parent 655d89b commit 8c5c5ec

File tree

6 files changed

+94
-16
lines changed

6 files changed

+94
-16
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,8 @@ ERROR(empty_version_string,none,
16511651
WARNING(unknown_platform_condition_argument,none,
16521652
"unknown %0 for build configuration '%1'",
16531653
(StringRef, StringRef))
1654+
WARNING(renamed_platform_condition_argument,none,
1655+
"'%0' has been renamed to '%1'", (StringRef, StringRef))
16541656
WARNING(likely_simulator_platform_condition,none,
16551657
"platform condition appears to be testing for simulator environment; "
16561658
"use 'targetEnvironment(simulator)' instead",

include/swift/Basic/LangOptions.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,8 @@ namespace swift {
413413
///
414414
/// \param suggestedKind Populated with suggested replacement platform condition
415415
/// \param suggestedValues Populated with suggested replacement values
416-
/// if a match is not found.
416+
/// if a match is not found, or if the value has been deprecated
417+
/// in favor of a newer one.
417418
static bool checkPlatformConditionSupported(
418419
PlatformConditionKind Kind, StringRef Value,
419420
PlatformConditionKind &suggestedKind,

lib/Basic/LangOptions.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,18 @@
2626

2727
using namespace swift;
2828

29-
static const StringRef SupportedConditionalCompilationOSs[] = {
29+
struct SupportedConditionalValue {
30+
StringRef value;
31+
32+
/// If the value has been deprecated, the new value to replace it with.
33+
StringRef replacement = "";
34+
35+
SupportedConditionalValue(const char *value) : value(value) {}
36+
SupportedConditionalValue(const char *value, const char *replacement)
37+
: value(value), replacement(replacement) {}
38+
};
39+
40+
static const SupportedConditionalValue SupportedConditionalCompilationOSs[] = {
3041
"OSX",
3142
"macOS",
3243
"tvOS",
@@ -42,7 +53,7 @@ static const StringRef SupportedConditionalCompilationOSs[] = {
4253
"WASI",
4354
};
4455

45-
static const StringRef SupportedConditionalCompilationArches[] = {
56+
static const SupportedConditionalValue SupportedConditionalCompilationArches[] = {
4657
"arm",
4758
"arm64",
4859
"i386",
@@ -53,18 +64,20 @@ static const StringRef SupportedConditionalCompilationArches[] = {
5364
"wasm32",
5465
};
5566

56-
static const StringRef SupportedConditionalCompilationEndianness[] = {
67+
static const SupportedConditionalValue SupportedConditionalCompilationEndianness[] = {
5768
"little",
5869
"big"
5970
};
6071

61-
static const StringRef SupportedConditionalCompilationRuntimes[] = {
72+
static const SupportedConditionalValue SupportedConditionalCompilationRuntimes[] = {
6273
"_ObjC",
6374
"_Native",
6475
};
6576

66-
static const StringRef SupportedConditionalCompilationTargetEnvironments[] = {
77+
static const SupportedConditionalValue SupportedConditionalCompilationTargetEnvironments[] = {
6778
"simulator",
79+
{ "macabi", "macCatalyst" },
80+
"macCatalyst", // A synonym for "macabi" when compiling for iOS
6881
};
6982

7083
static const PlatformConditionKind AllPublicPlatformConditionKinds[] = {
@@ -73,7 +86,7 @@ static const PlatformConditionKind AllPublicPlatformConditionKinds[] = {
7386
#include "swift/AST/PlatformConditionKinds.def"
7487
};
7588

76-
ArrayRef<StringRef> getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) {
89+
ArrayRef<SupportedConditionalValue> getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) {
7790
switch (Kind) {
7891
case PlatformConditionKind::OS:
7992
return SupportedConditionalCompilationOSs;
@@ -97,11 +110,11 @@ PlatformConditionKind suggestedPlatformConditionKind(PlatformConditionKind Kind,
97110
for (const PlatformConditionKind& candidateKind : AllPublicPlatformConditionKinds) {
98111
if (candidateKind != Kind) {
99112
auto supportedValues = getSupportedConditionalCompilationValues(candidateKind);
100-
for (const StringRef& candidateValue : supportedValues) {
101-
if (candidateValue.lower() == lower) {
113+
for (const SupportedConditionalValue& candidateValue : supportedValues) {
114+
if (candidateValue.value.lower() == lower) {
102115
suggestedValues.clear();
103-
if (candidateValue != V) {
104-
suggestedValues.emplace_back(candidateValue);
116+
if (candidateValue.value != V) {
117+
suggestedValues.emplace_back(candidateValue.value);
105118
}
106119
return candidateKind;
107120
}
@@ -118,19 +131,21 @@ bool isMatching(PlatformConditionKind Kind, const StringRef &V,
118131
unsigned minDistance = std::numeric_limits<unsigned>::max();
119132
std::string lower = V.lower();
120133
auto supportedValues = getSupportedConditionalCompilationValues(Kind);
121-
for (const StringRef& candidate : supportedValues) {
122-
if (candidate == V) {
134+
for (const SupportedConditionalValue& candidate : supportedValues) {
135+
if (candidate.value == V) {
123136
suggestedKind = Kind;
124137
suggestions.clear();
138+
if (!candidate.replacement.empty())
139+
suggestions.push_back(candidate.replacement);
125140
return true;
126141
}
127-
unsigned distance = StringRef(lower).edit_distance(candidate.lower());
142+
unsigned distance = StringRef(lower).edit_distance(candidate.value.lower());
128143
if (distance < minDistance) {
129144
suggestions.clear();
130145
minDistance = distance;
131146
}
132147
if (distance == minDistance)
133-
suggestions.emplace_back(candidate);
148+
suggestions.emplace_back(candidate.value);
134149
}
135150
suggestedKind = suggestedPlatformConditionKind(Kind, V, suggestions);
136151
return false;
@@ -171,6 +186,16 @@ checkPlatformCondition(PlatformConditionKind Kind, StringRef Value) const {
171186
if (Kind == PlatformConditionKind::OS && Value == "macOS")
172187
return checkPlatformCondition(Kind, "OSX");
173188

189+
// When compiling for iOS we consider "macCatalyst" to be a
190+
// synonym of "macabi". This enables the use of
191+
// #if targetEnvironment(macCatalyst) as a compilation
192+
// condition for macCatalyst.
193+
194+
if (Kind == PlatformConditionKind::TargetEnvironment &&
195+
Value == "macCatalyst" && Target.isiOS()) {
196+
return checkPlatformCondition(Kind, "macabi");
197+
}
198+
174199
for (auto &Opt : llvm::reverse(PlatformConditionValues)) {
175200
if (Opt.first == Kind)
176201
if (Opt.second == Value)
@@ -321,6 +346,10 @@ std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
321346
addPlatformConditionValue(PlatformConditionKind::TargetEnvironment,
322347
"simulator");
323348

349+
if (tripleIsMacCatalystEnvironment(Target))
350+
addPlatformConditionValue(PlatformConditionKind::TargetEnvironment,
351+
"macabi");
352+
324353
// If you add anything to this list, change the default size of
325354
// PlatformConditionValues to not require an extra allocation
326355
// in the common case.

lib/Parse/ParseIfConfig.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,16 @@ class ValidateIfConfigCondition :
311311
D.diagnose(Loc, diag::note_typo_candidate, suggestion)
312312
.fixItReplace(Arg->getSourceRange(), suggestion);
313313
}
314+
else if (!suggestedValues.empty()) {
315+
// The value the user gave has been replaced by something newer.
316+
assert(suggestedValues.size() == 1 && "only support one replacement");
317+
auto replacement = suggestedValues.front();
318+
319+
auto Loc = Arg->getLoc();
320+
D.diagnose(Loc, diag::renamed_platform_condition_argument,
321+
*ArgStr, replacement)
322+
.fixItReplace(Arg->getSourceRange(), replacement);
323+
}
314324

315325
return E;
316326
}

test/Parse/ConditionalCompilation/basicParseErrors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ undefinedFunc() // expected-error {{use of unresolved identifier 'undefinedFunc'
148148
#if _endian(arm64) // expected-warning {{unknown endianness for build configuration '_endian'}} expected-note {{did you mean 'arch'}} {{5-12=arch}}
149149
#endif
150150

151-
#if targetEnvironment(_ObjC) // expected-warning {{unknown target environment for build configuration 'targetEnvironment'}} expected-note {{did you mean 'simulator'}} {{23-28=simulator}}
151+
#if targetEnvironment(_ObjC) // expected-warning {{unknown target environment for build configuration 'targetEnvironment'}} expected-note {{did you mean 'macabi'}} {{23-28=macabi}}
152152
#endif
153153

154154
#if os(iOS) || os(simulator) // expected-warning {{unknown operating system for build configuration 'os'}} expected-note {{did you mean 'targetEnvironment'}} {{16-18=targetEnvironment}}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %swift -swift-version 4 -typecheck %s -verify -target x86_64-apple-ios12.0-macabi -parse-stdlib
2+
// RUN: %swift-ide-test -swift-version 4 -test-input-complete -source-filename=%s -target x86_64-apple-ios12.0-macabi
3+
4+
// REQUIRES: OS=maccatalyst
5+
6+
#if targetEnvironment(macabi) // expected-warning {{'macabi' has been renamed to 'macCatalyst'}} {{23-29=macCatalyst}}
7+
func underMacABI() {
8+
foo() // expected-error {{use of unresolved identifier 'foo'}}
9+
}
10+
#endif
11+
12+
#if !targetEnvironment(macabi) // expected-warning {{'macabi' has been renamed to 'macCatalyst'}} {{24-30=macCatalyst}}
13+
// This block does not typecheck but the #if prevents it from
14+
// from being a compiler error.
15+
let i: SomeType = "SomeString" // no-error
16+
#endif
17+
18+
#if targetEnvironment(macCatalyst)
19+
func underTargetEnvironmentMacCatalyst() {
20+
foo() // expected-error {{use of unresolved identifier 'foo'}}
21+
}
22+
#endif
23+
24+
// Make sure we don't treat the macabi environment as a simulator.
25+
#if targetEnvironment(simulator)
26+
// This block does not typecheck but the #if prevents it from
27+
// from being a compiler error.
28+
let i: SomeType = "SomeString" // no-error
29+
#endif
30+
31+
#if os(macCatalyst)
32+
// expected-warning@-1 {{unknown operating system for build configuration 'os'}}
33+
// expected-note@-2 *{{did you mean}}
34+
func underOSMacCatalyst() {
35+
}
36+
#endif

0 commit comments

Comments
 (0)