mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
"-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
This commit is contained in:
@@ -52,13 +52,16 @@ namespace version {
|
|||||||
/// a: [0 - 999]
|
/// a: [0 - 999]
|
||||||
/// b: [0 - 999]
|
/// b: [0 - 999]
|
||||||
class Version {
|
class Version {
|
||||||
SmallVector<uint64_t, 5> Components;
|
SmallVector<unsigned, 5> Components;
|
||||||
public:
|
public:
|
||||||
/// Create the empty compiler version - this always compares greater
|
/// Create the empty compiler version - this always compares greater
|
||||||
/// or equal to any other CompilerVersion, as in the case of building Swift
|
/// or equal to any other CompilerVersion, as in the case of building Swift
|
||||||
/// from latest sources outside of a build/integration/release context.
|
/// from latest sources outside of a build/integration/release context.
|
||||||
Version() = default;
|
Version() = default;
|
||||||
|
|
||||||
|
/// Create a literal version from a list of components.
|
||||||
|
Version(std::initializer_list<unsigned> Values) : Components(Values) {}
|
||||||
|
|
||||||
/// Create a version from a string in source code.
|
/// Create a version from a string in source code.
|
||||||
///
|
///
|
||||||
/// Must include only groups of digits separated by a dot.
|
/// Must include only groups of digits separated by a dot.
|
||||||
@@ -94,11 +97,15 @@ public:
|
|||||||
/// away any 5th component that might be in this version.
|
/// away any 5th component that might be in this version.
|
||||||
operator clang::VersionTuple() const;
|
operator clang::VersionTuple() const;
|
||||||
|
|
||||||
/// Return whether this version is a valid Swift language version number
|
/// Returns the concrete version to use when \e this version is provided as
|
||||||
/// to set the compiler to using -swift-version; this is not the same as
|
/// an argument to -swift-version.
|
||||||
/// the set of Swift versions that have ever existed, just those that we
|
///
|
||||||
/// are attempting to maintain backward-compatibility support for.
|
/// This is not the same as the set of Swift versions that have ever existed,
|
||||||
bool isValidEffectiveLanguageVersion() const;
|
/// just those that we are attempting to maintain backward-compatibility
|
||||||
|
/// support for. It's also common for valid versions to produce a different
|
||||||
|
/// result; for example "-swift-version 3" at one point instructed the
|
||||||
|
/// compiler to act as if it is version 3.1.
|
||||||
|
Optional<Version> getEffectiveLanguageVersion() const;
|
||||||
|
|
||||||
/// Whether this version is in the Swift 3 family
|
/// Whether this version is in the Swift 3 family
|
||||||
bool isVersion3() const { return !empty() && Components[0] == 3; }
|
bool isVersion3() const { return !empty() && Components[0] == 3; }
|
||||||
@@ -141,6 +148,10 @@ bool operator==(const Version &lhs, const Version &rhs);
|
|||||||
raw_ostream &operator<<(raw_ostream &os, const Version &version);
|
raw_ostream &operator<<(raw_ostream &os, const Version &version);
|
||||||
|
|
||||||
/// Retrieves the numeric {major, minor} Swift version.
|
/// Retrieves the numeric {major, minor} Swift version.
|
||||||
|
///
|
||||||
|
/// Note that this is the underlying version of the language, ignoring any
|
||||||
|
/// -swift-version flags that may have been used in a particular invocation of
|
||||||
|
/// the compiler.
|
||||||
std::pair<unsigned, unsigned> getSwiftNumericVersion();
|
std::pair<unsigned, unsigned> getSwiftNumericVersion();
|
||||||
|
|
||||||
/// Retrieves a string representing the complete Swift version, which includes
|
/// Retrieves a string representing the complete Swift version, which includes
|
||||||
|
|||||||
@@ -242,16 +242,11 @@ Version Version::getCurrentCompilerVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version Version::getCurrentLanguageVersion() {
|
Version Version::getCurrentLanguageVersion() {
|
||||||
#ifndef SWIFT_VERSION_STRING
|
#if SWIFT_VERSION_PATCHLEVEL
|
||||||
#error Swift language version is not set!
|
return {SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR, SWIFT_VERSION_PATCHLEVEL};
|
||||||
|
#else
|
||||||
|
return {SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR};
|
||||||
#endif
|
#endif
|
||||||
auto currentVersion = Version::parseVersionString(
|
|
||||||
SWIFT_VERSION_STRING, SourceLoc(), nullptr);
|
|
||||||
assert(currentVersion.hasValue() &&
|
|
||||||
"Embedded Swift language version couldn't be parsed: '"
|
|
||||||
SWIFT_VERSION_STRING
|
|
||||||
"'");
|
|
||||||
return currentVersion.getValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_ostream &operator<<(raw_ostream &os, const Version &version) {
|
raw_ostream &operator<<(raw_ostream &os, const Version &version) {
|
||||||
@@ -304,18 +299,35 @@ Version::operator clang::VersionTuple() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Version::isValidEffectiveLanguageVersion() const {
|
Optional<Version> Version::getEffectiveLanguageVersion() const {
|
||||||
for (auto verStr : getValidEffectiveVersions()) {
|
switch (size()) {
|
||||||
auto v = parseVersionString(verStr, SourceLoc(), nullptr);
|
case 0:
|
||||||
assert(v.hasValue());
|
return None;
|
||||||
// In this case, use logical-equality _and_ precision-equality. We do not
|
case 1:
|
||||||
// want to permit users requesting effective language versions more precise
|
break;
|
||||||
// than our whitelist (eg. we permit 3 but not 3.0 or 3.0.0), since
|
default:
|
||||||
// accepting such an argument promises more than we're able to deliver.
|
// We do not want to permit users requesting more precise effective language
|
||||||
if (v == *this && v.getValue().size() == size())
|
// versions since accepting such an argument promises more than we're able
|
||||||
return true;
|
// to deliver.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: When we switch to Swift 4 by default, the "3" case should return
|
||||||
|
// a version newer than any released 3.x compiler (probably "3.2"), and the
|
||||||
|
// "4" case should start returning getCurrentLanguageVersion. We should
|
||||||
|
// also check for the presence of SWIFT_VERSION_PATCHLEVEL, and if that's
|
||||||
|
// set apply it to the "3" case, so that Swift 4.0.1 will automatically
|
||||||
|
// have a compatibility mode of 3.2.1.
|
||||||
|
switch (Components[0]) {
|
||||||
|
case 3:
|
||||||
|
static_assert(SWIFT_VERSION_MAJOR == 3,
|
||||||
|
"getCurrentLanguageVersion is no longer correct here");
|
||||||
|
return Version::getCurrentLanguageVersion();
|
||||||
|
case 4:
|
||||||
|
return Version{4, 0};
|
||||||
|
default:
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Version Version::asMajorVersion() const {
|
Version Version::asMajorVersion() const {
|
||||||
|
|||||||
@@ -802,7 +802,7 @@ static void diagnoseSwiftVersion(Optional<version::Version> &vers, Arg *verArg,
|
|||||||
|
|
||||||
// Check for an unneeded minor version, otherwise just list valid versions
|
// Check for an unneeded minor version, otherwise just list valid versions
|
||||||
if (vers.hasValue() && !vers.getValue().empty() &&
|
if (vers.hasValue() && !vers.getValue().empty() &&
|
||||||
vers.getValue().asMajorVersion().isValidEffectiveLanguageVersion()) {
|
vers.getValue().asMajorVersion().getEffectiveLanguageVersion()) {
|
||||||
diags.diagnose(SourceLoc(), diag::note_swift_version_major,
|
diags.diagnose(SourceLoc(), diag::note_swift_version_major,
|
||||||
vers.getValue()[0]);
|
vers.getValue()[0]);
|
||||||
} else {
|
} else {
|
||||||
@@ -822,12 +822,15 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
|||||||
if (auto A = Args.getLastArg(OPT_swift_version)) {
|
if (auto A = Args.getLastArg(OPT_swift_version)) {
|
||||||
auto vers = version::Version::parseVersionString(
|
auto vers = version::Version::parseVersionString(
|
||||||
A->getValue(), SourceLoc(), &Diags);
|
A->getValue(), SourceLoc(), &Diags);
|
||||||
if (vers.hasValue() &&
|
bool isValid = false;
|
||||||
vers.getValue().isValidEffectiveLanguageVersion()) {
|
if (vers.hasValue()) {
|
||||||
Opts.EffectiveLanguageVersion = vers.getValue();
|
if (auto effectiveVers = vers.getValue().getEffectiveLanguageVersion()) {
|
||||||
} else {
|
Opts.EffectiveLanguageVersion = effectiveVers.getValue();
|
||||||
diagnoseSwiftVersion(vers, A, Args, Diags);
|
isValid = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!isValid)
|
||||||
|
diagnoseSwiftVersion(vers, A, Args, Diags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opts.AttachCommentsToDecls |= Args.hasArg(OPT_dump_api_path);
|
Opts.AttachCommentsToDecls |= Args.hasArg(OPT_dump_api_path);
|
||||||
|
|||||||
@@ -11,8 +11,26 @@ asdf // expected-error {{use of unresolved identifier}}
|
|||||||
jkl
|
jkl
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=3.1)
|
||||||
|
asdf // expected-error {{use of unresolved identifier}}
|
||||||
|
#else
|
||||||
|
jkl
|
||||||
|
#endif
|
||||||
|
|
||||||
#if swift(>=4)
|
#if swift(>=4)
|
||||||
aoeu
|
aoeu
|
||||||
#else
|
#else
|
||||||
htn // expected-error {{use of unresolved identifier}}
|
htn // expected-error {{use of unresolved identifier}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=4.1)
|
||||||
|
aoeu
|
||||||
|
#else
|
||||||
|
htn // expected-error {{use of unresolved identifier}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5)
|
||||||
|
aoeu
|
||||||
|
#else
|
||||||
|
htn // expected-error {{use of unresolved identifier}}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// RUN: %target-swiftc_driver -swift-version 3 %s
|
|
||||||
// RUN: not %target-swiftc_driver -swift-version foo %s 2>&1 | %FileCheck --check-prefix BAD %s
|
// RUN: not %target-swiftc_driver -swift-version foo %s 2>&1 | %FileCheck --check-prefix BAD %s
|
||||||
// RUN: not %target-swiftc_driver -swift-version 1 %s 2>&1 | %FileCheck --check-prefix BAD %s
|
// RUN: not %target-swiftc_driver -swift-version 1 %s 2>&1 | %FileCheck --check-prefix BAD %s
|
||||||
// RUN: not %target-swiftc_driver -swift-version 2 %s 2>&1 | %FileCheck --check-prefix BAD %s
|
// RUN: not %target-swiftc_driver -swift-version 2 %s 2>&1 | %FileCheck --check-prefix BAD %s
|
||||||
@@ -9,10 +8,50 @@
|
|||||||
// RUN: not %target-swiftc_driver -swift-version 3.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_3 %s
|
// RUN: not %target-swiftc_driver -swift-version 3.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_3 %s
|
||||||
// RUN: not %target-swiftc_driver -swift-version 4.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_4 %s
|
// RUN: not %target-swiftc_driver -swift-version 4.3 %s 2>&1 | %FileCheck --check-prefix FIXIT_4 %s
|
||||||
|
|
||||||
|
// RUN: not %target-swiftc_driver -swift-version 3 -typecheck %s 2>&1 | %FileCheck --check-prefix ERROR_3 %s
|
||||||
|
// RUN: not %target-swiftc_driver -swift-version 4 -typecheck %s 2>&1 | %FileCheck --check-prefix ERROR_4 %s
|
||||||
|
|
||||||
// BAD: invalid value
|
// BAD: invalid value
|
||||||
// BAD: note: valid arguments to '-swift-version' are '3', '4'
|
// BAD: note: valid arguments to '-swift-version' are '3', '4'
|
||||||
|
|
||||||
// FIXIT_3: use major version, as in '-swift-version 3'
|
// FIXIT_3: use major version, as in '-swift-version 3'
|
||||||
// FIXIT_4: use major version, as in '-swift-version 4'
|
// FIXIT_4: use major version, as in '-swift-version 4'
|
||||||
|
|
||||||
let x = 1
|
|
||||||
|
#if swift(>=3)
|
||||||
|
asdf
|
||||||
|
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
|
||||||
|
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
|
||||||
|
#else
|
||||||
|
jkl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=3.1)
|
||||||
|
asdf
|
||||||
|
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
|
||||||
|
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
|
||||||
|
#else
|
||||||
|
jkl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=4)
|
||||||
|
asdf // ERROR_4: [[@LINE]]:1: error: {{use of unresolved identifier}}
|
||||||
|
#else
|
||||||
|
jkl // ERROR_3: [[@LINE]]:1: error: {{use of unresolved identifier}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=4.1)
|
||||||
|
asdf
|
||||||
|
#else
|
||||||
|
jkl
|
||||||
|
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
|
||||||
|
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5)
|
||||||
|
asdf
|
||||||
|
#else
|
||||||
|
jkl
|
||||||
|
// ERROR_3: [[@LINE-1]]:1: error: {{use of unresolved identifier}}
|
||||||
|
// ERROR_4: [[@LINE-2]]:1: error: {{use of unresolved identifier}}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -3491,15 +3491,19 @@ static int prepareForDump(const char *Main,
|
|||||||
options::ModuleCachePath;
|
options::ModuleCachePath;
|
||||||
|
|
||||||
if (!options::SwiftVersion.empty()) {
|
if (!options::SwiftVersion.empty()) {
|
||||||
if (auto Version = version::Version::
|
using version::Version;
|
||||||
parseVersionString(options::SwiftVersion, SourceLoc(), nullptr)) {
|
bool isValid = false;
|
||||||
if (Version.getValue().isValidEffectiveLanguageVersion())
|
if (auto Version = Version::parseVersionString(options::SwiftVersion,
|
||||||
InitInvok.getLangOptions().EffectiveLanguageVersion = Version.getValue();
|
SourceLoc(), nullptr)) {
|
||||||
else {
|
if (auto Effective = Version.getValue().getEffectiveLanguageVersion()) {
|
||||||
llvm::errs() << "Unsupported Swift Version.\n";
|
InitInvok.getLangOptions().EffectiveLanguageVersion = *Effective;
|
||||||
return 1;
|
isValid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!isValid) {
|
||||||
|
llvm::errs() << "Unsupported Swift Version.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options::ResourceDir.empty()) {
|
if (!options::ResourceDir.empty()) {
|
||||||
|
|||||||
@@ -2957,7 +2957,8 @@ int main(int argc, char *argv[]) {
|
|||||||
if (auto swiftVersion =
|
if (auto swiftVersion =
|
||||||
version::Version::parseVersionString(options::SwiftVersion,
|
version::Version::parseVersionString(options::SwiftVersion,
|
||||||
SourceLoc(), nullptr)) {
|
SourceLoc(), nullptr)) {
|
||||||
InitInvok.getLangOptions().EffectiveLanguageVersion = *swiftVersion;
|
if (auto actual = swiftVersion.getValue().getEffectiveLanguageVersion())
|
||||||
|
InitInvok.getLangOptions().EffectiveLanguageVersion = actual.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InitInvok.getClangImporterOptions().ModuleCachePath =
|
InitInvok.getClangImporterOptions().ModuleCachePath =
|
||||||
|
|||||||
Reference in New Issue
Block a user