[Serialization] When crashing, note if mix-and-match may be to blame.

That is, a Swift 3 target imported into a Swift 4 context or vice
versa. This requires serializing the compatibility mode explicitly,
instead of including it in the textual version string that's only
for debugging.
This commit is contained in:
Jordan Rose
2017-04-07 17:20:35 -07:00
parent 2e8179d43a
commit 7e8d642e8e
10 changed files with 68 additions and 12 deletions

View File

@@ -553,6 +553,10 @@ ERROR(serialization_fatal,Fatal,
"fatal error encountered while reading from module '%0'; "
"please file a bug report with your project and the crash log",
(StringRef))
NOTE(serialization_compatibility_version_mismatch,none,
"compiling as Swift %0, with '%1' built as Swift %2 "
"(this is supported but may expose additional compiler issues)",
(StringRef, StringRef, StringRef))
ERROR(reserved_member_name,none,
"type member may not be named %0, since it would conflict with the"

View File

@@ -72,6 +72,9 @@ class ModuleFile : public LazyMemberLoader {
/// The target the module was built for.
StringRef TargetTriple;
/// The Swift compatibility version in use when this module was built.
StringRef CompatibilityVersion;
/// The data blob containing all of the module's identifiers.
StringRef IdentifierData;

View File

@@ -443,6 +443,7 @@ namespace control_block {
BCFixed<16>, // Module format major version
BCFixed<16>, // Module format minor version
BCVBR<8>, // length of "short version string" in the blob
BCVBR<8>, // length of "short compatibility version string" in the blob
BCBlob // misc. version information
>;

View File

@@ -71,6 +71,7 @@ struct ValidationInfo {
StringRef name = {};
StringRef targetTriple = {};
StringRef shortVersion = {};
StringRef compatibilityVersion = {};
size_t bytes = 0;
Status status = Status::Malformed;
};

View File

@@ -344,6 +344,17 @@ static bool skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
void ModuleFile::fatal(llvm::Error error) {
if (FileContext) {
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Name);
if (!CompatibilityVersion.empty()) {
SmallString<16> buffer;
llvm::raw_svector_ostream out(buffer);
out << getContext().LangOpts.EffectiveLanguageVersion;
if (out.str() != CompatibilityVersion) {
getContext().Diags.diagnose(
SourceLoc(), diag::serialization_compatibility_version_mismatch,
out.str(), Name, CompatibilityVersion);
}
}
}
logAllUnhandledErrors(std::move(error), llvm::errs(),

View File

@@ -193,9 +193,20 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
}
}
// This field was added later; be resilient against its absence.
if (scratch.size() > 2) {
// These fields were added later; be resilient against their absence.
switch (scratch.size()) {
default:
// Add new cases here, in descending order.
case 4:
result.compatibilityVersion = blobData.substr(scratch[2]+1, scratch[3]);
LLVM_FALLTHROUGH;
case 3:
result.shortVersion = blobData.slice(0, scratch[2]);
LLVM_FALLTHROUGH;
case 2:
case 1:
case 0:
break;
}
versionSeen = true;
@@ -932,6 +943,7 @@ ModuleFile::ModuleFile(
}
Name = info.name;
TargetTriple = info.targetTriple;
CompatibilityVersion = info.compatibilityVersion;
hasValidControlBlock = true;
break;

View File

@@ -709,10 +709,14 @@ void Serializer::writeHeader(const SerializationOptions &options) {
llvm::raw_svector_ostream versionString(versionStringBuf);
versionString << Version::getCurrentLanguageVersion();
size_t shortVersionStringLength = versionString.tell();
versionString << '/' << version::getSwiftFullVersion(
M->getASTContext().LangOpts.EffectiveLanguageVersion);
versionString << '('
<< M->getASTContext().LangOpts.EffectiveLanguageVersion;
size_t compatibilityVersionStringLength =
versionString.tell() - shortVersionStringLength - 1;
versionString << ")/" << version::getSwiftFullVersion();
Metadata.emit(ScratchRecord,
VERSION_MAJOR, VERSION_MINOR, shortVersionStringLength,
compatibilityVersionStringLength,
versionString.str());
Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str());
@@ -772,7 +776,7 @@ void Serializer::writeDocHeader() {
auto& LangOpts = M->getASTContext().LangOpts;
Metadata.emit(ScratchRecord,
VERSION_MAJOR, VERSION_MINOR,
/*short version string length*/0,
/*short version string length*/0, /*compatibility length*/0,
version::getSwiftFullVersion(
LangOpts.EffectiveLanguageVersion));

View File

@@ -1,4 +1,8 @@
@interface Base
@interface Object
- (nonnull instancetype)init;
@end
@interface Base : Object
#ifndef BAD
- (void)method;
#endif

View File

@@ -0,0 +1,20 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %target-swift-frontend -emit-module -o %t -module-name Lib -I %S/Inputs/custom-modules -swift-version 3 %s
// RUN: not --crash %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules -swift-version 3 -Xcc -DBAD 2>&1 | %FileCheck -check-prefix CHECK-CRASH -check-prefix CHECK-CRASH-3 %s
// RUN: not --crash %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules -swift-version 4 -Xcc -DBAD 2>&1 | %FileCheck -check-prefix CHECK-CRASH -check-prefix CHECK-CRASH-4 %s
// REQUIRES: objc_interop
import Overrides
public class Sub: Base {
public override func method() {}
}
// CHECK-CRASH: error: fatal error encountered while reading from module 'Lib'; please file a bug report with your project and the crash log
// CHECK-CRASH-3-NOT: note
// CHECK-CRASH-4: note: compiling as Swift 4.0, with 'Lib' built as Swift 3.1
// CHECK-CRASH-LABEL: *** DESERIALIZATION FAILURE (please include this section in any bug report) ***
// CHECK-CRASH: could not find 'method()' in parent class
// CHECK-CRASH: While loading members for 'Sub' in module 'Lib'

View File

@@ -3,7 +3,6 @@
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules | %FileCheck %s
// RUN: not --crash %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules -Xcc -DBAD 2>&1 | %FileCheck -check-prefix CHECK-CRASH %s
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -enable-experimental-deserialization-recovery | %FileCheck -check-prefix CHECK-RECOVERY %s
// REQUIRES: objc_interop
@@ -16,12 +15,9 @@ public class Sub: Base {
// CHECK-LABEL: class Sub : Base {
// CHECK-NEXT: func method()
// CHECK-NEXT: init()
// CHECK-NEXT: {{^}$}}
// CHECK-CRASH: error: fatal error encountered while reading from module 'Lib'; please file a bug report with your project and the crash log
// CHECK-CRASH-LABEL: *** DESERIALIZATION FAILURE (please include this section in any bug report) ***
// CHECK-CRASH: could not find 'method()' in parent class
// CHECK-CRASH: While loading members for 'Sub' in module 'Lib'
// CHECK-RECOVERY-LABEL: class Sub : Base {
// CHECK-RECOVERY-NEXT: init()
// CHECK-RECOVERY-NEXT: {{^}$}}