Skip to content

Commit 3456d04

Browse files
authored
"-swift-version 3" means Swift 3.1, not 3.0. (#7883)
Put in a general mechanism for mapping user-specified "compatibility versions" to proper "effective versions" (what #if and @available checking should respect). This may still be different from the intrinsic "language version"; right now master is considered a "3.1" compiler with a "Swift 4 mode", and we plan to ship a "4.0" compiler with a "Swift 3 mode" that will have a version number of something like "3.2". rdar://problem/29884401 / SR-3791
1 parent bc6ea5b commit 3456d04

File tree

7 files changed

+130
-42
lines changed

7 files changed

+130
-42
lines changed

include/swift/Basic/Version.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,16 @@ namespace version {
5252
/// a: [0 - 999]
5353
/// b: [0 - 999]
5454
class Version {
55-
SmallVector<uint64_t, 5> Components;
55+
SmallVector<unsigned, 5> Components;
5656
public:
5757
/// Create the empty compiler version - this always compares greater
5858
/// or equal to any other CompilerVersion, as in the case of building Swift
5959
/// from latest sources outside of a build/integration/release context.
6060
Version() = default;
6161

62+
/// Create a literal version from a list of components.
63+
Version(std::initializer_list<unsigned> Values) : Components(Values) {}
64+
6265
/// Create a version from a string in source code.
6366
///
6467
/// Must include only groups of digits separated by a dot.
@@ -94,11 +97,15 @@ class Version {
9497
/// away any 5th component that might be in this version.
9598
operator clang::VersionTuple() const;
9699

97-
/// Return whether this version is a valid Swift language version number
98-
/// to set the compiler to using -swift-version; this is not the same as
99-
/// the set of Swift versions that have ever existed, just those that we
100-
/// are attempting to maintain backward-compatibility support for.
101-
bool isValidEffectiveLanguageVersion() const;
100+
/// Returns the concrete version to use when \e this version is provided as
101+
/// an argument to -swift-version.
102+
///
103+
/// This is not the same as the set of Swift versions that have ever existed,
104+
/// just those that we are attempting to maintain backward-compatibility
105+
/// support for. It's also common for valid versions to produce a different
106+
/// result; for example "-swift-version 3" at one point instructed the
107+
/// compiler to act as if it is version 3.1.
108+
Optional<Version> getEffectiveLanguageVersion() const;
102109

103110
/// Whether this version is in the Swift 3 family
104111
bool isVersion3() const { return !empty() && Components[0] == 3; }
@@ -141,6 +148,10 @@ bool operator==(const Version &lhs, const Version &rhs);
141148
raw_ostream &operator<<(raw_ostream &os, const Version &version);
142149

143150
/// Retrieves the numeric {major, minor} Swift version.
151+
///
152+
/// Note that this is the underlying version of the language, ignoring any
153+
/// -swift-version flags that may have been used in a particular invocation of
154+
/// the compiler.
144155
std::pair<unsigned, unsigned> getSwiftNumericVersion();
145156

146157
/// Retrieves a string representing the complete Swift version, which includes

lib/Basic/Version.cpp

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,11 @@ Version Version::getCurrentCompilerVersion() {
242242
}
243243

244244
Version Version::getCurrentLanguageVersion() {
245-
#ifndef SWIFT_VERSION_STRING
246-
#error Swift language version is not set!
245+
#if SWIFT_VERSION_PATCHLEVEL
246+
return {SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR, SWIFT_VERSION_PATCHLEVEL};
247+
#else
248+
return {SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR};
247249
#endif
248-
auto currentVersion = Version::parseVersionString(
249-
SWIFT_VERSION_STRING, SourceLoc(), nullptr);
250-
assert(currentVersion.hasValue() &&
251-
"Embedded Swift language version couldn't be parsed: '"
252-
SWIFT_VERSION_STRING
253-
"'");
254-
return currentVersion.getValue();
255250
}
256251

257252
raw_ostream &operator<<(raw_ostream &os, const Version &version) {
@@ -304,18 +299,35 @@ Version::operator clang::VersionTuple() const
304299
}
305300
}
306301

307-
bool Version::isValidEffectiveLanguageVersion() const {
308-
for (auto verStr : getValidEffectiveVersions()) {
309-
auto v = parseVersionString(verStr, SourceLoc(), nullptr);
310-
assert(v.hasValue());
311-
// In this case, use logical-equality _and_ precision-equality. We do not
312-
// want to permit users requesting effective language versions more precise
313-
// than our whitelist (eg. we permit 3 but not 3.0 or 3.0.0), since
314-
// accepting such an argument promises more than we're able to deliver.
315-
if (v == *this && v.getValue().size() == size())
316-
return true;
302+
Optional<Version> Version::getEffectiveLanguageVersion() const {
303+
switch (size()) {
304+
case 0:
305+
return None;
306+
case 1:
307+
break;
308+
default:
309+
// We do not want to permit users requesting more precise effective language
310+
// versions since accepting such an argument promises more than we're able
311+
// to deliver.
312+
return None;
313+
}
314+
315+
// FIXME: When we switch to Swift 4 by default, the "3" case should return
316+
// a version newer than any released 3.x compiler (probably "3.2"), and the
317+
// "4" case should start returning getCurrentLanguageVersion. We should
318+
// also check for the presence of SWIFT_VERSION_PATCHLEVEL, and if that's
319+
// set apply it to the "3" case, so that Swift 4.0.1 will automatically
320+
// have a compatibility mode of 3.2.1.
321+
switch (Components[0]) {
322+
case 3:
323+
static_assert(SWIFT_VERSION_MAJOR == 3,
324+
"getCurrentLanguageVersion is no longer correct here");
325+
return Version::getCurrentLanguageVersion();
326+
case 4:
327+
return Version{4, 0};
328+
default:
329+
return None;
317330
}
318-
return false;
319331
}
320332

321333
Version Version::asMajorVersion() const {

lib/Frontend/CompilerInvocation.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ static void diagnoseSwiftVersion(Optional<version::Version> &vers, Arg *verArg,
802802

803803
// Check for an unneeded minor version, otherwise just list valid versions
804804
if (vers.hasValue() && !vers.getValue().empty() &&
805-
vers.getValue().asMajorVersion().isValidEffectiveLanguageVersion()) {
805+
vers.getValue().asMajorVersion().getEffectiveLanguageVersion()) {
806806
diags.diagnose(SourceLoc(), diag::note_swift_version_major,
807807
vers.getValue()[0]);
808808
} else {
@@ -822,12 +822,15 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
822822
if (auto A = Args.getLastArg(OPT_swift_version)) {
823823
auto vers = version::Version::parseVersionString(
824824
A->getValue(), SourceLoc(), &Diags);
825-
if (vers.hasValue() &&
826-
vers.getValue().isValidEffectiveLanguageVersion()) {
827-
Opts.EffectiveLanguageVersion = vers.getValue();
828-
} else {
829-
diagnoseSwiftVersion(vers, A, Args, Diags);
825+
bool isValid = false;
826+
if (vers.hasValue()) {
827+
if (auto effectiveVers = vers.getValue().getEffectiveLanguageVersion()) {
828+
Opts.EffectiveLanguageVersion = effectiveVers.getValue();
829+
isValid = true;
830+
}
830831
}
832+
if (!isValid)
833+
diagnoseSwiftVersion(vers, A, Args, Diags);
831834
}
832835

833836
Opts.AttachCommentsToDecls |= Args.hasArg(OPT_dump_api_path);

test/Driver/swift-version-default.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,26 @@ asdf // expected-error {{use of unresolved identifier}}
1111
jkl
1212
#endif
1313

14+
#if swift(>=3.1)
15+
asdf // expected-error {{use of unresolved identifier}}
16+
#else
17+
jkl
18+
#endif
19+
1420
#if swift(>=4)
1521
aoeu
1622
#else
1723
htn // expected-error {{use of unresolved identifier}}
1824
#endif
25+
26+
#if swift(>=4.1)
27+
aoeu
28+
#else
29+
htn // expected-error {{use of unresolved identifier}}
30+
#endif
31+
32+
#if swift(>=5)
33+
aoeu
34+
#else
35+
htn // expected-error {{use of unresolved identifier}}
36+
#endif

test/Driver/swift-version.swift

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// RUN: %target-swiftc_driver -swift-version 3 %s
21
// RUN: not %target-swiftc_driver -swift-version foo %s 2>&1 | %FileCheck --check-prefix BAD %s
32
// RUN: not %target-swiftc_driver -swift-version 1 %s 2>&1 | %FileCheck --check-prefix BAD %s
43
// RUN: not %target-swiftc_driver -swift-version 2 %s 2>&1 | %FileCheck --check-prefix BAD %s
@@ -9,10 +8,50 @@
98
// RUN: not %target-swiftc_driver -swift-version 3.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_3 %s
109
// RUN: not %target-swiftc_driver -swift-version 4.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_4 %s
1110

11+
// RUN: not %target-swiftc_driver -swift-version 3 -typecheck %s 2>&1 | %FileCheck --check-prefix ERROR_3 %s
12+
// RUN: not %target-swiftc_driver -swift-version 4 -typecheck %s 2>&1 | %FileCheck --check-prefix ERROR_4 %s
13+
1214
// BAD: invalid value
1315
// BAD: note: valid arguments to '-swift-version' are '3', '4'
1416

1517
// FIXIT_3: use major version, as in '-swift-version 3'
1618
// FIXIT_4: use major version, as in '-swift-version 4'
1719

18-
let x = 1
20+
21+
#if swift(>=3)
22+
asdf
23+
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
24+
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
25+
#else
26+
jkl
27+
#endif
28+
29+
#if swift(>=3.1)
30+
asdf
31+
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
32+
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
33+
#else
34+
jkl
35+
#endif
36+
37+
#if swift(>=4)
38+
asdf // ERROR_4: [[@LINE]]:1: error: {{use of unresolved identifier}}
39+
#else
40+
jkl // ERROR_3: [[@LINE]]:1: error: {{use of unresolved identifier}}
41+
#endif
42+
43+
#if swift(>=4.1)
44+
asdf
45+
#else
46+
jkl
47+
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
48+
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
49+
#endif
50+
51+
#if swift(>=5)
52+
asdf
53+
#else
54+
jkl
55+
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
56+
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
57+
#endif

tools/swift-api-digester/swift-api-digester.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3491,15 +3491,19 @@ static int prepareForDump(const char *Main,
34913491
options::ModuleCachePath;
34923492

34933493
if (!options::SwiftVersion.empty()) {
3494-
if (auto Version = version::Version::
3495-
parseVersionString(options::SwiftVersion, SourceLoc(), nullptr)) {
3496-
if (Version.getValue().isValidEffectiveLanguageVersion())
3497-
InitInvok.getLangOptions().EffectiveLanguageVersion = Version.getValue();
3498-
else {
3499-
llvm::errs() << "Unsupported Swift Version.\n";
3500-
return 1;
3494+
using version::Version;
3495+
bool isValid = false;
3496+
if (auto Version = Version::parseVersionString(options::SwiftVersion,
3497+
SourceLoc(), nullptr)) {
3498+
if (auto Effective = Version.getValue().getEffectiveLanguageVersion()) {
3499+
InitInvok.getLangOptions().EffectiveLanguageVersion = *Effective;
3500+
isValid = true;
35013501
}
35023502
}
3503+
if (!isValid) {
3504+
llvm::errs() << "Unsupported Swift Version.\n";
3505+
return 1;
3506+
}
35033507
}
35043508

35053509
if (!options::ResourceDir.empty()) {

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2957,7 +2957,8 @@ int main(int argc, char *argv[]) {
29572957
if (auto swiftVersion =
29582958
version::Version::parseVersionString(options::SwiftVersion,
29592959
SourceLoc(), nullptr)) {
2960-
InitInvok.getLangOptions().EffectiveLanguageVersion = *swiftVersion;
2960+
if (auto actual = swiftVersion.getValue().getEffectiveLanguageVersion())
2961+
InitInvok.getLangOptions().EffectiveLanguageVersion = actual.getValue();
29612962
}
29622963
}
29632964
InitInvok.getClangImporterOptions().ModuleCachePath =

0 commit comments

Comments
 (0)