Skip to content

Commit ea5aaa6

Browse files
authored
Merge pull request #4826 from graydon/SR-2582-swift-version
2 parents 2bfe921 + 8970d44 commit ea5aaa6

File tree

16 files changed

+133
-22
lines changed

16 files changed

+133
-22
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_BASIC_LANGOPTIONS_H
2020

2121
#include "swift/Basic/LLVM.h"
22+
#include "swift/Basic/Version.h"
2223
#include "clang/Basic/VersionTuple.h"
2324
#include "llvm/ADT/ArrayRef.h"
2425
#include "llvm/ADT/SmallVector.h"
@@ -41,6 +42,9 @@ namespace swift {
4142
/// Language features
4243
///
4344

45+
/// \brief User-overridable language version to compile for.
46+
version::Version EffectiveLanguageVersion = version::Version::getCurrentLanguageVersion();
47+
4448
/// \brief Disable API availability checking.
4549
bool DisableAvailabilityChecking = false;
4650

include/swift/Basic/Version.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ class Version {
8989
return Components.empty();
9090
}
9191

92+
/// Return whether this version is a valid Swift language version number
93+
/// to set the compiler to using -swift-version; this is not the same as
94+
/// the set of Swift versions that have ever existed, just those that we
95+
/// are attempting to maintain backward-compatibility support for.
96+
bool isValidEffectiveLanguageVersion() const;
97+
9298
/// Parse a version in the form used by the _compiler_version \#if condition.
9399
static Version parseCompilerVersionString(StringRef VersionString,
94100
SourceLoc Loc,
@@ -113,15 +119,18 @@ class Version {
113119
};
114120

115121
bool operator>=(const Version &lhs, const Version &rhs);
122+
bool operator==(const Version &lhs, const Version &rhs);
116123

117124
raw_ostream &operator<<(raw_ostream &os, const Version &version);
118125

119126
/// Retrieves the numeric {major, minor} Swift version.
120127
std::pair<unsigned, unsigned> getSwiftNumericVersion();
121128

122129
/// Retrieves a string representing the complete Swift version, which includes
123-
/// the Swift version number, the repository version, and the vendor tag.
124-
std::string getSwiftFullVersion();
130+
/// the Swift supported and effective version numbers, the repository version,
131+
/// and the vendor tag.
132+
std::string getSwiftFullVersion(Version effectiveLanguageVersion =
133+
Version::getCurrentLanguageVersion());
125134

126135
} // end namespace version
127136
} // end namespace swift

include/swift/Option/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ def j : JoinedOrSeparate<["-"], "j">, Flags<[DoesNotAffectIncrementalBuild]>,
133133
def sdk : Separate<["-"], "sdk">, Flags<[FrontendOption]>,
134134
HelpText<"Compile against <sdk>">, MetaVarName<"<sdk>">;
135135

136+
def swift_version : Separate<["-"], "swift-version">, Flags<[FrontendOption]>,
137+
HelpText<"Interpret input according to a specific Swift language version number">,
138+
MetaVarName<"<vers>">;
139+
136140
def tools_directory : Separate<["-"], "tools-directory">,
137141
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
138142
HelpText<"Look for external executables (ld, clang, binutils) in <directory>">, MetaVarName<"<directory>">;

lib/Basic/Version.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,24 @@ Version::preprocessorDefinition(StringRef macroName,
285285
return define;
286286
}
287287

288+
bool
289+
Version::isValidEffectiveLanguageVersion() const
290+
{
291+
// Whitelist of backward-compatibility versions that we permit passing as
292+
// -swift-version <vers>
293+
char const *whitelist[] = {
294+
"3",
295+
"3.0",
296+
};
297+
for (auto const i : whitelist) {
298+
auto v = parseVersionString(i, SourceLoc(), nullptr);
299+
assert(v.hasValue());
300+
if (v == *this)
301+
return true;
302+
}
303+
return false;
304+
}
305+
288306
bool operator>=(const class Version &lhs,
289307
const class Version &rhs) {
290308

@@ -304,11 +322,22 @@ bool operator>=(const class Version &lhs,
304322
return lhs.size() >= rhs.size();
305323
}
306324

325+
bool operator==(const class Version &lhs,
326+
const class Version &rhs) {
327+
if (lhs.size() != rhs.size())
328+
return false;
329+
for (size_t i = 0; i < lhs.size(); ++i) {
330+
if (lhs[i] != rhs[i])
331+
return false;
332+
}
333+
return true;
334+
}
335+
307336
std::pair<unsigned, unsigned> getSwiftNumericVersion() {
308337
return { SWIFT_VERSION_MAJOR, SWIFT_VERSION_MINOR };
309338
}
310339

311-
std::string getSwiftFullVersion() {
340+
std::string getSwiftFullVersion(Version effectiveVersion) {
312341
std::string buf;
313342
llvm::raw_string_ostream OS(buf);
314343

@@ -321,6 +350,10 @@ std::string getSwiftFullVersion() {
321350
OS << "-dev";
322351
#endif
323352

353+
if (!(effectiveVersion == Version::getCurrentLanguageVersion())) {
354+
OS << " effective-" << effectiveVersion;
355+
}
356+
324357
#if defined(SWIFT_COMPILER_VERSION)
325358
OS << " (swiftlang-" SWIFT_COMPILER_VERSION;
326359
#if defined(CLANG_COMPILER_VERSION)

lib/ClangImporter/ClangImporter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ getNormalInvocationArguments(std::vector<std::string> &invocationArgStrs,
315315
const llvm::Triple &triple = ctx.LangOpts.Target;
316316
SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
317317

318-
auto languageVersion = swift::version::Version::getCurrentLanguageVersion();
318+
auto languageVersion = ctx.LangOpts.EffectiveLanguageVersion;
319319

320320
// Construct the invocation arguments for the current target.
321321
// Add target-independent options first.
@@ -2670,7 +2670,8 @@ getExtensionMetadata() const {
26702670
metadata.BlockName = "swift.lookup";
26712671
metadata.MajorVersion = SWIFT_LOOKUP_TABLE_VERSION_MAJOR;
26722672
metadata.MinorVersion = SWIFT_LOOKUP_TABLE_VERSION_MINOR;
2673-
metadata.UserInfo = version::getSwiftFullVersion();
2673+
metadata.UserInfo = version::getSwiftFullVersion(
2674+
Impl.SwiftContext.LangOpts.EffectiveLanguageVersion);
26742675
return metadata;
26752676
}
26762677

lib/Driver/Compilation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,12 @@ static void writeCompilationRecord(StringRef path, StringRef argsHash,
193193
};
194194

195195
using compilation_record::TopLevelKey;
196+
// NB: We calculate effective version from getCurrentLanguageVersion()
197+
// here because any -swift-version argument is handled in the
198+
// argsHash that follows.
196199
out << compilation_record::getName(TopLevelKey::Version) << ": \""
197-
<< llvm::yaml::escape(version::getSwiftFullVersion())
200+
<< llvm::yaml::escape(version::getSwiftFullVersion(
201+
swift::version::Version::getCurrentLanguageVersion()))
198202
<< "\"\n";
199203
out << compilation_record::getName(TopLevelKey::Options) << ": \""
200204
<< llvm::yaml::escape(argsHash) << "\"\n";

lib/Driver/Driver.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,14 @@ static bool populateOutOfDateMap(InputInfoMap &map, StringRef argsHashStr,
269269
auto *value = dyn_cast<yaml::ScalarNode>(i->getValue());
270270
if (!value)
271271
return true;
272-
versionValid =
273-
(value->getValue(scratch) == version::getSwiftFullVersion());
272+
273+
// NB: We check aginst
274+
// swift::version::Version::getCurrentLanguageVersion() here because any
275+
// -swift-version argument is handled in the argsHashStr check that
276+
// follows.
277+
versionValid = (value->getValue(scratch)
278+
== version::getSwiftFullVersion(
279+
version::Version::getCurrentLanguageVersion()));
274280

275281
} else if (keyStr == compilation_record::getName(TopLevelKey::Options)) {
276282
auto *value = dyn_cast<yaml::ScalarNode>(i->getValue());
@@ -2007,7 +2013,8 @@ void Driver::printJobs(const Compilation &C) const {
20072013
}
20082014

20092015
void Driver::printVersion(const ToolChain &TC, raw_ostream &OS) const {
2010-
OS << version::getSwiftFullVersion() << '\n';
2016+
OS << version::getSwiftFullVersion(
2017+
version::Version::getCurrentLanguageVersion()) << '\n';
20112018
OS << "Target: " << TC.getTriple().str() << '\n';
20122019
}
20132020

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ static void addCommonFrontendArgs(const ToolChain &TC,
133133
inputArgs.AddLastArg(arguments, options::OPT_warnings_as_errors);
134134
inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ);
135135
inputArgs.AddLastArg(arguments, options::OPT_sanitize_coverage_EQ);
136+
inputArgs.AddLastArg(arguments, options::OPT_swift_version);
136137

137138
// Pass on any build config options
138139
inputArgs.AddAllArgs(arguments, options::OPT_D);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,18 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
765765
const FrontendOptions &FrontendOpts) {
766766
using namespace options;
767767

768+
if (auto A = Args.getLastArg(OPT_swift_version)) {
769+
auto vers = version::Version::parseVersionString(
770+
A->getValue(), SourceLoc(), &Diags);
771+
if (vers.hasValue() &&
772+
vers.getValue().isValidEffectiveLanguageVersion()) {
773+
Opts.EffectiveLanguageVersion = vers.getValue();
774+
} else {
775+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
776+
A->getAsString(Args), A->getValue());
777+
}
778+
}
779+
768780
Opts.AttachCommentsToDecls |= Args.hasArg(OPT_dump_api_path);
769781

770782
Opts.UseMalloc |= Args.hasArg(OPT_use_malloc);

lib/IRGen/IRGen.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,15 @@ class MD5Stream : public llvm::raw_ostream {
274274
/// and options which influence the compilation.
275275
static void getHashOfModule(MD5::MD5Result &Result, IRGenOptions &Opts,
276276
llvm::Module *Module,
277-
llvm::TargetMachine *TargetMachine) {
277+
llvm::TargetMachine *TargetMachine,
278+
version::Version const& effectiveLanguageVersion) {
278279
// Calculate the hash of the whole llvm module.
279280
MD5Stream HashStream;
280281
llvm::WriteBitcodeToFile(Module, HashStream);
281282

282283
// Update the hash with the compiler version. We want to recompile if the
283284
// llvm pipeline of the compiler changed.
284-
HashStream << version::getSwiftFullVersion();
285+
HashStream << version::getSwiftFullVersion(effectiveLanguageVersion);
285286

286287
// Add all options which influence the llvm compilation but are not yet
287288
// reflected in the llvm module itself.
@@ -347,12 +348,14 @@ static bool performLLVM(IRGenOptions &Opts, DiagnosticEngine &Diags,
347348
llvm::GlobalVariable *HashGlobal,
348349
llvm::Module *Module,
349350
llvm::TargetMachine *TargetMachine,
351+
version::Version const& effectiveLanguageVersion,
350352
StringRef OutputFilename) {
351353
if (Opts.UseIncrementalLLVMCodeGen && HashGlobal) {
352354
// Check if we can skip the llvm part of the compilation if we have an
353355
// existing object file which was generated from the same llvm IR.
354356
MD5::MD5Result Result;
355-
getHashOfModule(Result, Opts, Module, TargetMachine);
357+
getHashOfModule(Result, Opts, Module, TargetMachine,
358+
effectiveLanguageVersion);
356359

357360
DEBUG(
358361
if (DiagMutex) DiagMutex->lock();
@@ -663,7 +666,9 @@ static std::unique_ptr<llvm::Module> performIRGeneration(IRGenOptions &Opts,
663666
embedBitcode(IGM.getModule(), Opts);
664667

665668
if (performLLVM(Opts, IGM.Context.Diags, nullptr, IGM.ModuleHash,
666-
IGM.getModule(), IGM.TargetMachine.get(), IGM.OutputFilename))
669+
IGM.getModule(), IGM.TargetMachine.get(),
670+
IGM.Context.LangOpts.EffectiveLanguageVersion,
671+
IGM.OutputFilename))
667672
return nullptr;
668673
return std::unique_ptr<llvm::Module>(IGM.releaseModule());
669674
}
@@ -679,7 +684,9 @@ static void ThreadEntryPoint(IRGenerator *irgen,
679684
);
680685
embedBitcode(IGM->getModule(), irgen->Opts);
681686
performLLVM(irgen->Opts, IGM->Context.Diags, DiagMutex, IGM->ModuleHash,
682-
IGM->getModule(), IGM->TargetMachine.get(), IGM->OutputFilename);
687+
IGM->getModule(), IGM->TargetMachine.get(),
688+
IGM->Context.LangOpts.EffectiveLanguageVersion,
689+
IGM->OutputFilename);
683690
if (IGM->Context.Diags.hadAnyError())
684691
return;
685692
}
@@ -940,7 +947,9 @@ swift::createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer,
940947
ASTSym->setSection(Section);
941948
ASTSym->setAlignment(8);
942949
::performLLVM(Opts, Ctx.Diags, nullptr, nullptr, IGM.getModule(),
943-
IGM.TargetMachine.get(), OutputPath);
950+
IGM.TargetMachine.get(),
951+
Ctx.LangOpts.EffectiveLanguageVersion,
952+
OutputPath);
944953
}
945954

946955
bool swift::performLLVM(IRGenOptions &Opts, ASTContext &Ctx,
@@ -952,7 +961,9 @@ bool swift::performLLVM(IRGenOptions &Opts, ASTContext &Ctx,
952961

953962
embedBitcode(Module, Opts);
954963
if (::performLLVM(Opts, Ctx.Diags, nullptr, nullptr, Module,
955-
TargetMachine.get(), Opts.getSingleOutputFilename()))
964+
TargetMachine.get(),
965+
Ctx.LangOpts.EffectiveLanguageVersion,
966+
Opts.getSingleOutputFilename()))
956967
return true;
957968
return false;
958969
}

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ IRGenDebugInfo::IRGenDebugInfo(const IRGenOptions &Opts,
121121
}
122122

123123
unsigned Lang = llvm::dwarf::DW_LANG_Swift;
124-
std::string Producer = version::getSwiftFullVersion();
124+
std::string Producer = version::getSwiftFullVersion(
125+
IGM.Context.LangOpts.EffectiveLanguageVersion);
125126
bool IsOptimized = Opts.Optimize;
126127
StringRef Flags = Opts.DWARFDebugFlags;
127128
unsigned Major, Minor;

lib/Parse/ParseStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1683,7 +1683,7 @@ Parser::evaluateConditionalCompilationExpr(Expr *condition) {
16831683
if (!versionRequirement.hasValue())
16841684
return ConditionalCompilationExprState::error();
16851685

1686-
auto thisVersion = version::Version::getCurrentLanguageVersion();
1686+
auto thisVersion = Context.LangOpts.EffectiveLanguageVersion;
16871687

16881688
if (!prefix->getName().getBaseName().str().equals(">=")) {
16891689
diagnose(PUE->getFn()->getLoc(),

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2037,7 +2037,8 @@ class ModuleWriter {
20372037
}
20382038

20392039
void writePrologue(raw_ostream &out) {
2040-
out << "// Generated by " << version::getSwiftFullVersion() << "\n"
2040+
out << "// Generated by " << version::getSwiftFullVersion(
2041+
M.getASTContext().LangOpts.EffectiveLanguageVersion) << "\n"
20412042
"#pragma clang diagnostic push\n"
20422043
"\n"
20432044
"#if defined(__has_include) && "

lib/Serialization/Serialization.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,8 @@ void Serializer::writeHeader(const SerializationOptions &options) {
583583
llvm::raw_svector_ostream versionString(versionStringBuf);
584584
versionString << Version::getCurrentLanguageVersion();
585585
size_t shortVersionStringLength = versionString.tell();
586-
versionString << '/' << version::getSwiftFullVersion();
586+
versionString << '/' << version::getSwiftFullVersion(
587+
M->getASTContext().LangOpts.EffectiveLanguageVersion);
587588
Metadata.emit(ScratchRecord,
588589
VERSION_MAJOR, VERSION_MINOR, shortVersionStringLength,
589590
versionString.str());
@@ -626,12 +627,14 @@ void Serializer::writeDocHeader() {
626627
control_block::MetadataLayout Metadata(Out);
627628
control_block::TargetLayout Target(Out);
628629

630+
auto& LangOpts = M->getASTContext().LangOpts;
629631
Metadata.emit(ScratchRecord,
630632
VERSION_MAJOR, VERSION_MINOR,
631633
/*short version string length*/0,
632-
version::getSwiftFullVersion());
634+
version::getSwiftFullVersion(
635+
LangOpts.EffectiveLanguageVersion));
633636

634-
Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str());
637+
Target.emit(ScratchRecord, LangOpts.Target.str());
635638
}
636639
}
637640

test/Driver/swift-version.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-swiftc_driver -swift-version 3 %s
2+
// RUN: %target-swiftc_driver -swift-version 3.0 %s
3+
// RUN: not %target-swiftc_driver -swift-version 1 %s 2>&1 | %FileCheck --check-prefix BAD %s
4+
// RUN: not %target-swiftc_driver -swift-version 2 %s 2>&1 | %FileCheck --check-prefix BAD %s
5+
// RUN: not %target-swiftc_driver -swift-version 2.3 %s 2>&1 | %FileCheck --check-prefix BAD %s
6+
// RUN: not %target-swiftc_driver -swift-version 7 %s 2>&1 | %FileCheck --check-prefix BAD %s
7+
// RUN: not %target-swiftc_driver -swift-version 7.2 %s 2>&1 | %FileCheck --check-prefix BAD %s
8+
9+
// BAD: invalid value
10+
11+
let x = 1
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-parse-verify-swift -swift-version 3
2+
3+
#if swift(>=3)
4+
let w = 1
5+
#else
6+
// This shouldn't emit any diagnostics.
7+
asdf asdf asdf asdf
8+
#endif
9+

0 commit comments

Comments
 (0)