Skip to content

Commit bcba3cf

Browse files
authored
Merge pull request #36091 from CodaFi/extensionating-circumstances
[5.4] Correct an Incremental Miscompile For Edits to Overloaded Extension Members
2 parents d378e70 + bb58f64 commit bcba3cf

File tree

9 files changed

+94
-5
lines changed

9 files changed

+94
-5
lines changed

include/swift/AST/DeclContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ class IterableDeclContext {
881881
/// available.
882882
Optional<Fingerprint> getBodyFingerprint() const;
883883

884+
bool areTokensHashedForThisBodyInsteadOfInterfaceHash() const;
885+
884886
private:
885887
/// Add a member to the list for iteration purposes, but do not notify the
886888
/// subclass that we have done so.

lib/AST/DeclContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,16 @@ Optional<Fingerprint> IterableDeclContext::getBodyFingerprint() const {
10321032
.fingerprint;
10331033
}
10341034

1035+
bool IterableDeclContext::areTokensHashedForThisBodyInsteadOfInterfaceHash()
1036+
const {
1037+
// Do not keep separate hashes for extension bodies because the dependencies
1038+
// can miss the addition of a member in an extension because there is nothing
1039+
// corresponding to the fingerprinted nominal dependency node.
1040+
if (isa<ExtensionDecl>(this))
1041+
return false;
1042+
return true;
1043+
}
1044+
10351045
/// Return the DeclContext to compare when checking private access in
10361046
/// Swift 4 mode. The context returned is the type declaration if the context
10371047
/// and the type declaration are in the same file, otherwise it is the types

lib/Parse/ParseDecl.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4751,9 +4751,12 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
47514751

47524752
// If we're hashing the type body separately, record the curly braces but
47534753
// nothing inside for the interface hash.
4754-
llvm::SaveAndRestore<Optional<llvm::MD5>> MemberHashingScope{CurrentTokenHash, llvm::MD5()};
4755-
recordTokenHash("{");
4756-
recordTokenHash("}");
4754+
Optional<llvm::SaveAndRestore<Optional<llvm::MD5>>> MemberHashingScope;
4755+
if (IDC->areTokensHashedForThisBodyInsteadOfInterfaceHash()) {
4756+
recordTokenHash("{");
4757+
recordTokenHash("}");
4758+
MemberHashingScope.emplace(CurrentTokenHash, llvm::MD5());
4759+
}
47574760

47584761
std::vector<Decl *> decls;
47594762
ParserStatus Status;
@@ -4785,7 +4788,8 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
47854788
hadError = true;
47864789

47874790
llvm::MD5::MD5Result result;
4788-
CurrentTokenHash->final(result);
4791+
auto declListHash = MemberHashingScope ? *CurrentTokenHash : llvm::MD5();
4792+
declListHash.final(result);
47894793
return std::make_pair(decls, Fingerprint{std::move(result)});
47904794
}
47914795

test/Incremental/Fingerprints/Inputs/extension-adds-member/definesAB-after.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ struct A {
33
struct B {
44
}
55
extension A {
6-
init(_ x: String = "") {}
6+
var x: Int {17}
77
}
88
extension B {
99
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public struct S {
2+
private // commenting out this line works
3+
static func foo(_ i: Int) {print("1: other:2 commented out")}
4+
}
5+
extension S {
6+
// private // commenting out this line fails
7+
static func foo2(_ i: Int) {print("2: other:6 commented out")}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public struct S {
2+
private // commenting out this line works
3+
static func foo(_ i: Int) {print("1: other:2 commented out")}
4+
}
5+
extension S {
6+
private // commenting out this line fails
7+
static func foo2(_ i: Int) {print("2: other:6 commented out")}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extension S {
2+
static func foo<I: SignedInteger>(_ si: I) {
3+
print("1: other:2 not commented out")
4+
}
5+
static func foo2<I: SignedInteger>(_ si: I) {
6+
print("2: other:6 not commented out")
7+
}
8+
}
9+
10+
S.foo(3)
11+
S.foo2(3)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"main.swift": {
3+
"object": "./main.o",
4+
"swift-dependencies": "./main.swiftdeps"
5+
},
6+
"definesS.swift": {
7+
"object": "./definesS.o",
8+
"swift-dependencies": "./definesS.swiftdeps"
9+
},
10+
"": {
11+
"swift-dependencies": "./main~buildrecord.swiftdeps"
12+
}
13+
}
14+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Test per-type-body fingerprints using simple extensions
2+
//
3+
// If the parser is allowed to use a body fingerprint for an extension
4+
// this test will fail because usesA.swift won't be recompiled for the
5+
// last step.
6+
7+
// Establish status quo
8+
9+
// RUN: %empty-directory(%t)
10+
// RUN: cp %S/Inputs/extension-changes-member/* %t
11+
// RUN: cp %t/definesS{-before,}.swift
12+
13+
// Seeing weird failure on CI, so set the mod times
14+
// RUN: touch -t 200101010101 %t/*.swift
15+
16+
// RUN: cd %t && %target-swiftc_driver -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesS.swift -module-name main -output-file-map ofm.json >& %t/output3
17+
18+
// Change one type, only uses of that type get recompiled
19+
20+
// RUN: cp %t/definesS{-after,}.swift
21+
22+
// Seeing weird failure on CI, so ensure that definesS.swift is newer
23+
// RUN: touch -t 200201010101 %t/*
24+
// RUN: touch -t 200101010101 %t/*.swift
25+
// RUN: touch -t 200301010101 %t/definesS.swift
26+
27+
// RUN: cd %t && %target-swiftc_driver -enable-batch-mode -j2 -incremental -driver-show-incremental main.swift definesS.swift -module-name main -output-file-map ofm.json >& %t/output4
28+
29+
// RUN: %FileCheck -check-prefix=CHECK-RECOMPILED-W %s < %t/output4
30+
31+
// CHECK-RECOMPILED-W: {compile: definesS.o <= definesS.swift}
32+
// CHECK-RECOMPILED-W: {compile: main.o <= main.swift}

0 commit comments

Comments
 (0)