Skip to content

Commit 8f820de

Browse files
committed
[serialization] Diagnose loading modules from older Swifts.
...with a better message than the generic "older version of the compiler" one, when we know it's actually a different version of Swift proper. This still uses the same internal module version numbers to check if the module is compatible; the presentation of language versions is a diagnostic thing only. Speaking of module version numbers, this deliberately does NOT increment VERSION_MINOR; it's implemented in a backwards-compatible way. This will only work going forwards, of course; all existing modules don't have a short version string, and I don't feel comfortable assuming all older modules we might encounter are "Swift 2.2". rdar://problem/25680392
1 parent 22cef3e commit 8f820de

File tree

18 files changed

+99
-84
lines changed

18 files changed

+99
-84
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ ERROR(serialization_malformed_module,Fatal,
429429
ERROR(serialization_module_too_new,Fatal,
430430
"module file was created by a newer version of the compiler: %0",
431431
(StringRef))
432+
ERROR(serialization_module_language_version_mismatch,Fatal,
433+
"module compiled with Swift %0 cannot be imported in Swift %1: %2",
434+
(StringRef, StringRef, StringRef))
432435
ERROR(serialization_module_too_old,Fatal,
433436
"module file was created by an older version of the compiler; "
434437
"rebuild %0 and try again: %1",

include/swift/Basic/Version.h

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
#ifndef SWIFT_BASIC_VERSION_H
2020
#define SWIFT_BASIC_VERSION_H
2121

22-
#include <string>
2322

23+
#include "swift/Basic/LLVM.h"
2424
#include "llvm/ADT/Optional.h"
25-
#include "llvm/ADT/StringRef.h"
2625
#include "llvm/ADT/SmallVector.h"
26+
#include "llvm/ADT/StringRef.h"
27+
#include <string>
2728

2829
namespace swift {
2930

@@ -50,7 +51,7 @@ namespace version {
5051
/// a: [0 - 999]
5152
/// b: [0 - 999]
5253
class Version {
53-
llvm::SmallVector<uint64_t, 5> Components;
54+
SmallVector<uint64_t, 5> Components;
5455
public:
5556
/// Create the empty compiler version - this always compares greater
5657
/// or equal to any other CompilerVersion, as in the case of building Swift
@@ -60,11 +61,7 @@ class Version {
6061
/// Create a version from a string in source code.
6162
///
6263
/// Must include only groups of digits separated by a dot.
63-
Version(const llvm::StringRef VersionString, SourceLoc Loc,
64-
DiagnosticEngine *Diags);
65-
66-
/// Return a printable string representation of the version.
67-
std::string str() const;
64+
Version(StringRef VersionString, SourceLoc Loc, DiagnosticEngine *Diags);
6865

6966
/// Return a string to be used as an internal preprocessor define.
7067
///
@@ -91,17 +88,16 @@ class Version {
9188
}
9289

9390
/// Parse a version in the form used by the _compiler_version \#if condition.
94-
static Version parseCompilerVersionString(llvm::StringRef VersionString,
91+
static Version parseCompilerVersionString(StringRef VersionString,
9592
SourceLoc Loc,
9693
DiagnosticEngine *Diags);
9794

9895
/// Parse a generic version string of the format [0-9]+(.[0-9]+)*
9996
///
10097
/// Version components can be any unsigned 64-bit number.
101-
static llvm::Optional<Version> parseVersionString(
102-
llvm::StringRef VersionString,
103-
SourceLoc Loc,
104-
DiagnosticEngine *Diags);
98+
static Optional<Version> parseVersionString(StringRef VersionString,
99+
SourceLoc Loc,
100+
DiagnosticEngine *Diags);
105101

106102
/// Returns a version from the currently defined SWIFT_COMPILER_VERSION.
107103
///
@@ -116,6 +112,8 @@ class Version {
116112

117113
bool operator>=(const Version &lhs, const Version &rhs);
118114

115+
raw_ostream &operator<<(raw_ostream &os, const Version &version);
116+
119117
/// Retrieves the numeric {major, minor} Swift version.
120118
std::pair<unsigned, unsigned> getSwiftNumericVersion();
121119

include/swift/Serialization/ModuleFile.h

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ class ModuleFile : public LazyMemberLoader {
350350
/// Constructs a new module and validates it.
351351
ModuleFile(std::unique_ptr<llvm::MemoryBuffer> moduleInputBuffer,
352352
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
353-
bool isFramework, serialization::ExtendedValidationInfo *extInfo);
353+
bool isFramework, serialization::ValidationInfo &info,
354+
serialization::ExtendedValidationInfo *extInfo);
354355

355356
public:
356357
/// Change the status of the current module. Default argument marks the module
@@ -479,15 +480,16 @@ class ModuleFile : public LazyMemberLoader {
479480
/// \param[out] extInfo Optionally, extra info serialized about the module.
480481
/// \returns Whether the module was successfully loaded, or what went wrong
481482
/// if it was not.
482-
static Status
483+
static serialization::ValidationInfo
483484
load(std::unique_ptr<llvm::MemoryBuffer> moduleInputBuffer,
484485
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
485486
bool isFramework, std::unique_ptr<ModuleFile> &theModule,
486487
serialization::ExtendedValidationInfo *extInfo = nullptr) {
488+
serialization::ValidationInfo info;
487489
theModule.reset(new ModuleFile(std::move(moduleInputBuffer),
488490
std::move(moduleDocInputBuffer),
489-
isFramework, extInfo));
490-
return theModule->getStatus();
491+
isFramework, info, extInfo));
492+
return info;
491493
}
492494

493495
// Out of line to avoid instantiation OnDiskChainedHashTable here.
@@ -597,17 +599,6 @@ class ModuleFile : public LazyMemberLoader {
597599
return ModuleInputBuffer->getBufferIdentifier();
598600
}
599601

600-
/// Returns the module name as stored in the serialized data.
601-
StringRef getModuleName() const {
602-
return Name;
603-
}
604-
605-
/// Returns the target triple the module was compiled for,
606-
/// as stored in the serialized data.
607-
StringRef getTargetTriple() const {
608-
return TargetTriple;
609-
}
610-
611602
/// AST-verify imported decls.
612603
///
613604
/// Has no effect in NDEBUG builds.

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ namespace control_block {
415415
METADATA, // ID
416416
BCFixed<16>, // Module format major version
417417
BCFixed<16>, // Module format minor version
418+
BCVBR<8>, // length of "short version string" in the blob
418419
BCBlob // misc. version information
419420
>;
420421

include/swift/Serialization/Validation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ bool isSerializedAST(StringRef data);
7070
struct ValidationInfo {
7171
StringRef name = {};
7272
StringRef targetTriple = {};
73+
StringRef shortVersion = {};
7374
size_t bytes = 0;
7475
Status status = Status::Malformed;
7576
};

lib/Basic/Version.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,13 @@ Version Version::getCurrentLanguageVersion() {
260260
return currentVersion.getValue();
261261
}
262262

263-
std::string Version::str() const {
264-
std::string VersionString;
265-
llvm::raw_string_ostream OS(VersionString);
266-
for (auto i = Components.begin(); i != Components.end(); i++) {
267-
OS << *i;
268-
if (i != Components.end() - 1)
269-
OS << '.';
270-
}
271-
return OS.str();
263+
raw_ostream &operator<<(raw_ostream &os, const Version &version) {
264+
if (version.empty())
265+
return os;
266+
os << version[0];
267+
for (size_t i = 1, e = version.size(); i != e; ++i)
268+
os << '.' << version[i];
269+
return os;
272270
}
273271

274272
std::string Version::preprocessorDefinition() const {

lib/Serialization/ModuleFile.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
190190
}
191191
}
192192

193+
// This field was added later; be resilient against its absence.
194+
if (scratch.size() > 2) {
195+
result.shortVersion = blobData.slice(0, scratch[2]);
196+
}
197+
193198
versionSeen = true;
194199
break;
195200
}
@@ -743,7 +748,7 @@ static bool isTargetTooNew(const llvm::Triple &moduleTarget,
743748
ModuleFile::ModuleFile(
744749
std::unique_ptr<llvm::MemoryBuffer> moduleInputBuffer,
745750
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
746-
bool isFramework,
751+
bool isFramework, serialization::ValidationInfo &info,
747752
serialization::ExtendedValidationInfo *extInfo)
748753
: ModuleInputBuffer(std::move(moduleInputBuffer)),
749754
ModuleDocInputBuffer(std::move(moduleDocInputBuffer)),
@@ -775,7 +780,7 @@ ModuleFile::ModuleFile(
775780
case CONTROL_BLOCK_ID: {
776781
cursor.EnterSubBlock(CONTROL_BLOCK_ID);
777782

778-
auto info = validateControlBlock(cursor, scratch, extInfo);
783+
info = validateControlBlock(cursor, scratch, extInfo);
779784
if (info.status != Status::Valid) {
780785
error(info.status);
781786
return;

lib/Serialization/Serialization.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/Basic/STLExtras.h"
2727
#include "swift/Basic/SourceManager.h"
2828
#include "swift/Basic/Timer.h"
29+
#include "swift/Basic/Version.h"
2930
#include "swift/ClangImporter/ClangImporter.h"
3031
#include "swift/ClangImporter/ClangModule.h"
3132
#include "swift/Serialization/SerializationOptions.h"
@@ -54,6 +55,7 @@
5455
using namespace swift;
5556
using namespace swift::serialization;
5657
using namespace llvm::support;
58+
using swift::version::Version;
5759
using llvm::BCBlockRAII;
5860

5961
/// Used for static_assert.
@@ -571,15 +573,14 @@ void Serializer::writeHeader(const SerializationOptions &options) {
571573

572574
ModuleName.emit(ScratchRecord, M->getName().str());
573575

574-
// FIXME: put a real version in here.
575-
#ifdef LLVM_VERSION_INFO
576-
# define EXTRA_VERSION_STRING PACKAGE_STRING LLVM_VERSION_INFO
577-
#else
578-
# define EXTRA_VERSION_STRING PACKAGE_STRING
579-
#endif
576+
SmallString<32> versionStringBuf;
577+
llvm::raw_svector_ostream versionString(versionStringBuf);
578+
versionString << Version::getCurrentLanguageVersion();
579+
size_t shortVersionStringLength = versionString.tell();
580+
versionString << '/' << version::getSwiftFullVersion();
580581
Metadata.emit(ScratchRecord,
581-
VERSION_MAJOR, VERSION_MINOR, EXTRA_VERSION_STRING);
582-
#undef EXTRA_VERSION_STRING
582+
VERSION_MAJOR, VERSION_MINOR, shortVersionStringLength,
583+
versionString.str());
583584

584585
Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str());
585586

@@ -619,15 +620,10 @@ void Serializer::writeDocHeader() {
619620
control_block::MetadataLayout Metadata(Out);
620621
control_block::TargetLayout Target(Out);
621622

622-
// FIXME: put a real version in here.
623-
#ifdef LLVM_VERSION_INFO
624-
# define EXTRA_VERSION_STRING PACKAGE_STRING LLVM_VERSION_INFO
625-
#else
626-
# define EXTRA_VERSION_STRING PACKAGE_STRING
627-
#endif
628623
Metadata.emit(ScratchRecord,
629-
VERSION_MAJOR, VERSION_MINOR, EXTRA_VERSION_STRING);
630-
#undef EXTRA_VERSION_STRING
624+
VERSION_MAJOR, VERSION_MINOR,
625+
/*short version string length*/0,
626+
version::getSwiftFullVersion());
631627

632628
Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str());
633629
}

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/DiagnosticsSema.h"
1818
#include "swift/Basic/STLExtras.h"
1919
#include "swift/Basic/SourceManager.h"
20+
#include "swift/Basic/Version.h"
2021
#include "llvm/ADT/SmallString.h"
2122
#include "llvm/Support/MemoryBuffer.h"
2223
#include "llvm/Support/Path.h"
@@ -163,11 +164,12 @@ FileUnit *SerializedModuleLoader::loadAST(
163164

164165
serialization::ExtendedValidationInfo extendedInfo;
165166
std::unique_ptr<ModuleFile> loadedModuleFile;
166-
serialization::Status err = ModuleFile::load(std::move(moduleInputBuffer),
167-
std::move(moduleDocInputBuffer),
168-
isFramework, loadedModuleFile,
169-
&extendedInfo);
170-
if (err == serialization::Status::Valid) {
167+
serialization::ValidationInfo loadInfo =
168+
ModuleFile::load(std::move(moduleInputBuffer),
169+
std::move(moduleDocInputBuffer),
170+
isFramework, loadedModuleFile,
171+
&extendedInfo);
172+
if (loadInfo.status == serialization::Status::Valid) {
171173
Ctx.bumpGeneration();
172174

173175
M.setResilienceStrategy(extendedInfo.getResilienceStrategy());
@@ -180,9 +182,9 @@ FileUnit *SerializedModuleLoader::loadAST(
180182
M.setTestingEnabled();
181183

182184
auto diagLocOrInvalid = diagLoc.getValueOr(SourceLoc());
183-
err = loadedModuleFile->associateWithFileContext(fileUnit,
184-
diagLocOrInvalid);
185-
if (err == serialization::Status::Valid) {
185+
loadInfo.status =
186+
loadedModuleFile->associateWithFileContext(fileUnit, diagLocOrInvalid);
187+
if (loadInfo.status == serialization::Status::Valid) {
186188
LoadedModuleFiles.emplace_back(std::move(loadedModuleFile),
187189
Ctx.getCurrentGeneration());
188190
return fileUnit;
@@ -195,15 +197,36 @@ FileUnit *SerializedModuleLoader::loadAST(
195197
if (!diagLoc)
196198
return nullptr;
197199

198-
switch (loadedModuleFile->getStatus()) {
200+
auto diagnoseDifferentLanguageVersion = [&](StringRef shortVersion) -> bool {
201+
if (shortVersion.empty())
202+
return false;
203+
204+
SmallString<32> versionBuf;
205+
llvm::raw_svector_ostream versionString(versionBuf);
206+
versionString << version::Version::getCurrentLanguageVersion();
207+
if (versionString.str() == shortVersion)
208+
return false;
209+
210+
Ctx.Diags.diagnose(*diagLoc,
211+
diag::serialization_module_language_version_mismatch,
212+
loadInfo.shortVersion, versionString.str(),
213+
moduleBufferID);
214+
return true;
215+
};
216+
217+
switch (loadInfo.status) {
199218
case serialization::Status::Valid:
200219
llvm_unreachable("At this point we know loading has failed");
201220

202221
case serialization::Status::FormatTooNew:
222+
if (diagnoseDifferentLanguageVersion(loadInfo.shortVersion))
223+
break;
203224
Ctx.Diags.diagnose(*diagLoc, diag::serialization_module_too_new,
204225
moduleBufferID);
205226
break;
206227
case serialization::Status::FormatTooOld:
228+
if (diagnoseDifferentLanguageVersion(loadInfo.shortVersion))
229+
break;
207230
Ctx.Diags.diagnose(*diagLoc, diag::serialization_module_too_old,
208231
M.getName(), moduleBufferID);
209232
break;
@@ -288,7 +311,7 @@ FileUnit *SerializedModuleLoader::loadAST(
288311
if (Ctx.LangOpts.DebuggerSupport)
289312
diagKind = diag::serialization_name_mismatch_repl;
290313
Ctx.Diags.diagnose(*diagLoc, diagKind,
291-
loadedModuleFile->getModuleName(), M.getName());
314+
loadInfo.name, M.getName());
292315
break;
293316
}
294317

@@ -299,13 +322,12 @@ FileUnit *SerializedModuleLoader::loadAST(
299322
if (Ctx.LangOpts.DebuggerSupport)
300323
diagKind = diag::serialization_target_incompatible_repl;
301324
Ctx.Diags.diagnose(*diagLoc, diagKind,
302-
loadedModuleFile->getTargetTriple(), moduleBufferID);
325+
loadInfo.targetTriple, moduleBufferID);
303326
break;
304327
}
305328

306329
case serialization::Status::TargetTooNew: {
307-
StringRef moduleTargetTriple = loadedModuleFile->getTargetTriple();
308-
llvm::Triple moduleTarget(llvm::Triple::normalize(moduleTargetTriple));
330+
llvm::Triple moduleTarget(llvm::Triple::normalize(loadInfo.targetTriple));
309331

310332
StringRef osName;
311333
unsigned major, minor, micro;

test/DebugInfo/ASTSection_linker.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// REQUIRES: OS=macosx
1818

1919
// CHECK: Loaded module ASTSection from
20+
// CHECK: - Swift Version: {{.+}}.{{.+}}
2021
// CHECK: - Target: {{.+}}-{{.+}}-{{.+}}
2122
// CHECK: - SDK path: /fake/sdk/path{{$}}
2223
// CHECK: - -Xcc options: -working-directory {{.+}} -DA -DB

0 commit comments

Comments
 (0)