Skip to content

Commit 449e5ec

Browse files
committed
[Serialization] Give swiftdocs a stable version
We're committing to this as a forwards-compatible format, and in most cases probably backwards-compatible as well!
1 parent f3ea8bd commit 449e5ec

12 files changed

+87
-9
lines changed

Diff for: include/swift/Serialization/ModuleFile.h

+3
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,9 @@ class ModuleFile
631631
theModule.reset(new ModuleFile(std::move(moduleInputBuffer),
632632
std::move(moduleDocInputBuffer),
633633
isFramework, info, extInfo));
634+
assert(info.status == Status::Valid ||
635+
info.status == theModule->getStatus());
636+
info.status = theModule->getStatus();
634637
return info;
635638
}
636639

Diff for: lib/Serialization/DocFormat.h

+20
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ using llvm::BCVBR;
3333
/// Magic number for serialized documentation files.
3434
const unsigned char SWIFTDOC_SIGNATURE[] = { 0xE2, 0x9C, 0xA8, 0x07 };
3535

36+
/// Serialized swiftdoc format major version number.
37+
///
38+
/// Increment this value when making a backwards-incompatible change, which
39+
/// should be rare. When incrementing this value, reset SWIFTDOC_VERSION_MINOR
40+
/// to 0.
41+
const uint16_t SWIFTDOC_VERSION_MAJOR = 1;
42+
43+
/// Serialized swiftdoc format minor version number.
44+
///
45+
/// Increment this value when making a backwards-compatible change that might
46+
/// be interesting to test for. However, if old swiftdoc files are fully
47+
/// compatible with the new change, you do not need to increment this.
48+
///
49+
/// To ensure that two separate changes don't silently get merged into one
50+
/// in source control, you should also update the comment to briefly
51+
/// describe what change you made. The content of this comment isn't important;
52+
/// it just ensures a conflict if two people change the module format.
53+
/// Don't worry about adhering to the 80-column limit for this line.
54+
const uint16_t SWIFTDOC_VERSION_MINOR = 1; // Last change: skipping 0 for testing purposes
55+
3656
/// The record types within the comment block.
3757
///
3858
/// Be very careful when changing this block; it must remain stable. Adding new

Diff for: lib/Serialization/ModuleFile.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
129129
static ValidationInfo
130130
validateControlBlock(llvm::BitstreamCursor &cursor,
131131
SmallVectorImpl<uint64_t> &scratch,
132+
std::pair<uint16_t, uint16_t> expectedVersion,
132133
ExtendedValidationInfo *extendedInfo) {
133134
// The control block is malformed until we've at least read a major version
134135
// number.
@@ -174,18 +175,18 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
174175
}
175176

176177
uint16_t versionMajor = scratch[0];
177-
if (versionMajor > SWIFTMODULE_VERSION_MAJOR)
178+
if (versionMajor > expectedVersion.first)
178179
result.status = Status::FormatTooNew;
179-
else if (versionMajor < SWIFTMODULE_VERSION_MAJOR)
180+
else if (versionMajor < expectedVersion.first)
180181
result.status = Status::FormatTooOld;
181182
else
182183
result.status = Status::Valid;
183184

184185
// Major version 0 does not have stable minor versions.
185186
if (versionMajor == 0) {
186187
uint16_t versionMinor = scratch[1];
187-
if (versionMinor != SWIFTMODULE_VERSION_MINOR) {
188-
if (versionMinor < SWIFTMODULE_VERSION_MINOR)
188+
if (versionMinor != expectedVersion.second) {
189+
if (versionMinor < expectedVersion.second)
189190
result.status = Status::FormatTooOld;
190191
else
191192
result.status = Status::FormatTooNew;
@@ -263,7 +264,10 @@ ValidationInfo serialization::validateSerializedAST(
263264

264265
if (topLevelEntry.ID == CONTROL_BLOCK_ID) {
265266
cursor.EnterSubBlock(CONTROL_BLOCK_ID);
266-
result = validateControlBlock(cursor, scratch, extendedInfo);
267+
result = validateControlBlock(cursor, scratch,
268+
{SWIFTMODULE_VERSION_MAJOR,
269+
SWIFTMODULE_VERSION_MINOR},
270+
extendedInfo);
267271
if (result.status == Status::Malformed)
268272
return result;
269273
} else {
@@ -1106,7 +1110,10 @@ bool ModuleFile::readModuleDocIfPresent() {
11061110
case CONTROL_BLOCK_ID: {
11071111
docCursor.EnterSubBlock(CONTROL_BLOCK_ID);
11081112

1109-
info = validateControlBlock(docCursor, scratch, /*extendedInfo*/nullptr);
1113+
info = validateControlBlock(docCursor, scratch,
1114+
{SWIFTDOC_VERSION_MAJOR,
1115+
SWIFTDOC_VERSION_MINOR},
1116+
/*extendedInfo*/nullptr);
11101117
if (info.status != Status::Valid)
11111118
return false;
11121119
// Check that the swiftdoc is actually for this module.
@@ -1174,7 +1181,10 @@ ModuleFile::ModuleFile(
11741181
case CONTROL_BLOCK_ID: {
11751182
cursor.EnterSubBlock(CONTROL_BLOCK_ID);
11761183

1177-
info = validateControlBlock(cursor, scratch, extInfo);
1184+
info = validateControlBlock(cursor, scratch,
1185+
{SWIFTMODULE_VERSION_MAJOR,
1186+
SWIFTMODULE_VERSION_MINOR},
1187+
extInfo);
11781188
if (info.status != Status::Valid) {
11791189
error(info.status);
11801190
return;

Diff for: lib/Serialization/SerializeDoc.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,7 @@ void DocSerializer::writeDocHeader() {
472472
control_block::TargetLayout Target(Out);
473473

474474
auto& LangOpts = M->getASTContext().LangOpts;
475-
Metadata.emit(ScratchRecord,
476-
SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR,
475+
Metadata.emit(ScratchRecord, SWIFTDOC_VERSION_MAJOR, SWIFTDOC_VERSION_MINOR,
477476
/*short version string length*/0, /*compatibility length*/0,
478477
version::getSwiftFullVersion(
479478
LangOpts.EffectiveLanguageVersion));
400 Bytes
Binary file not shown.
400 Bytes
Binary file not shown.
400 Bytes
Binary file not shown.
400 Bytes
Binary file not shown.
400 Bytes
Binary file not shown.

Diff for: test/Serialization/load-invalid-doc.swift

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/../Inputs/empty.swift
3+
// RUN: %target-swift-frontend -typecheck -I %t %s
4+
5+
// RUN: touch %t/empty.swiftdoc
6+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
7+
8+
// RUN: echo -n 'a' > %t/empty.swiftdoc
9+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
10+
11+
// RUN: echo -n 'abcd' > %t/empty.swiftdoc
12+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
13+
14+
// RUN: echo -n 'abcde' > %t/empty.swiftdoc
15+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
16+
17+
import empty // expected-error{{malformed module file}}

Diff for: test/Serialization/load-wrong-name-doc.swift

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/../Inputs/empty.swift -module-name empty2
3+
// RUN: %target-swift-frontend -typecheck -I %t %s
4+
5+
// RUN: %target-swift-frontend -emit-module -emit-module-doc -o %t %S/../Inputs/empty.swift
6+
// RUN: mv %t/empty.swiftdoc %t/empty2.swiftdoc
7+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
8+
9+
import empty2 // expected-error{{malformed module file}}

Diff for: test/Serialization/swiftdoc-versions.swift

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/../Inputs/empty.swift
3+
// RUN: %target-swift-frontend -typecheck -I %t %s
4+
5+
// RUN: cp %S/Inputs/swiftdoc-versions/empty-1.0.swiftdoc %t/empty.swiftdoc
6+
// RUN: %target-swift-frontend -typecheck -I %t %s
7+
8+
// RUN: cp %S/Inputs/swiftdoc-versions/empty-1.1.swiftdoc %t/empty.swiftdoc
9+
// RUN: %target-swift-frontend -typecheck -I %t %s
10+
11+
// RUN: cp %S/Inputs/swiftdoc-versions/empty-1.257.swiftdoc %t/empty.swiftdoc
12+
// RUN: %target-swift-frontend -typecheck -I %t %s
13+
14+
// RUN: cp %S/Inputs/swiftdoc-versions/empty-257.1.swiftdoc %t/empty.swiftdoc
15+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
16+
17+
// RUN: cp %S/Inputs/swiftdoc-versions/empty-0.7.swiftdoc %t/empty.swiftdoc
18+
// RUN: %target-swift-frontend -typecheck -I %t %s -verify -show-diagnostics-after-fatal
19+
20+
import empty // expected-error{{malformed module file}}

0 commit comments

Comments
 (0)