Skip to content

Commit 055b3a8

Browse files
committed
Sema: Deterministically order declarations in EmittedMemberRequest
Previously we did this in the SILVTableVisitor, since maintaining a consistent order between translation units is important for correctness. However, we also want the order in which the members themselves are emitted to remain consistent regardless of the order in which members were synthesized. This is in service of reproducible builds.
1 parent c1b0c93 commit 055b3a8

File tree

2 files changed

+75
-75
lines changed

2 files changed

+75
-75
lines changed

include/swift/SIL/SILVTableVisitor.h

+1-70
Original file line numberDiff line numberDiff line change
@@ -18,55 +18,11 @@
1818
#ifndef SWIFT_SIL_SILVTABLEVISITOR_H
1919
#define SWIFT_SIL_SILVTABLEVISITOR_H
2020

21-
#include <string>
22-
2321
#include "swift/AST/Decl.h"
2422
#include "swift/AST/Types.h"
25-
#include "swift/AST/ASTMangler.h"
2623

2724
namespace swift {
2825

29-
// Utility class for deterministically ordering vtable entries for
30-
// synthesized methods.
31-
struct SortedFuncList {
32-
using Entry = std::pair<std::string, AbstractFunctionDecl *>;
33-
SmallVector<Entry, 2> elts;
34-
bool sorted = false;
35-
36-
void add(AbstractFunctionDecl *afd) {
37-
Mangle::ASTMangler mangler;
38-
std::string mangledName;
39-
if (auto *cd = dyn_cast<ConstructorDecl>(afd))
40-
mangledName = mangler.mangleConstructorEntity(cd, 0);
41-
else
42-
mangledName = mangler.mangleEntity(afd);
43-
44-
elts.push_back(std::make_pair(mangledName, afd));
45-
}
46-
47-
bool empty() { return elts.empty(); }
48-
49-
void sort() {
50-
assert(!sorted);
51-
sorted = true;
52-
std::sort(elts.begin(),
53-
elts.end(),
54-
[](const Entry &lhs, const Entry &rhs) -> bool {
55-
return lhs.first < rhs.first;
56-
});
57-
}
58-
59-
decltype(elts)::const_iterator begin() const {
60-
assert(sorted);
61-
return elts.begin();
62-
}
63-
64-
decltype(elts)::const_iterator end() const {
65-
assert(sorted);
66-
return elts.end();
67-
}
68-
};
69-
7026
/// A CRTP class for visiting virtually-dispatched methods of a class.
7127
///
7228
/// You must override these two methods in your subclass:
@@ -192,33 +148,8 @@ template <class T> class SILVTableVisitor {
192148
if (!theClass->hasKnownSwiftImplementation())
193149
return;
194150

195-
// Note that while vtable order is not ABI, we still want it to be
196-
// consistent between translation units.
197-
//
198-
// So, sort synthesized members by their mangled name, since they
199-
// are added lazily during type checking, with the remaining ones
200-
// forced at the end.
201-
SortedFuncList synthesizedMembers;
202-
203-
for (auto member : theClass->getEmittedMembers()) {
204-
if (auto *afd = dyn_cast<AbstractFunctionDecl>(member)) {
205-
if (afd->isSynthesized()) {
206-
synthesizedMembers.add(afd);
207-
continue;
208-
}
209-
}
210-
151+
for (auto member : theClass->getEmittedMembers())
211152
maybeAddMember(member);
212-
}
213-
214-
if (synthesizedMembers.empty())
215-
return;
216-
217-
synthesizedMembers.sort();
218-
219-
for (const auto &pair : synthesizedMembers) {
220-
maybeAddMember(pair.second);
221-
}
222153
}
223154
};
224155

lib/Sema/TypeCheckDecl.cpp

+74-5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "TypeCheckType.h"
2626
#include "MiscDiagnostics.h"
2727
#include "swift/AST/AccessScope.h"
28+
#include "swift/AST/ASTMangler.h"
2829
#include "swift/AST/ASTPrinter.h"
2930
#include "swift/AST/ASTVisitor.h"
3031
#include "swift/AST/ASTWalker.h"
@@ -2417,6 +2418,53 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const {
24172418
return namingPattern;
24182419
}
24192420

2421+
namespace {
2422+
2423+
// Utility class for deterministically ordering vtable entries for
2424+
// synthesized methods.
2425+
struct SortedFuncList {
2426+
using Entry = std::pair<std::string, AbstractFunctionDecl *>;
2427+
SmallVector<Entry, 2> elts;
2428+
bool sorted = false;
2429+
2430+
void add(AbstractFunctionDecl *afd) {
2431+
Mangle::ASTMangler mangler;
2432+
std::string mangledName;
2433+
if (auto *cd = dyn_cast<ConstructorDecl>(afd))
2434+
mangledName = mangler.mangleConstructorEntity(cd, /*allocator=*/false);
2435+
else if (auto *dd = dyn_cast<DestructorDecl>(afd))
2436+
mangledName = mangler.mangleDestructorEntity(dd, /*deallocating=*/false);
2437+
else
2438+
mangledName = mangler.mangleEntity(afd);
2439+
2440+
elts.push_back(std::make_pair(mangledName, afd));
2441+
}
2442+
2443+
bool empty() { return elts.empty(); }
2444+
2445+
void sort() {
2446+
assert(!sorted);
2447+
sorted = true;
2448+
std::sort(elts.begin(),
2449+
elts.end(),
2450+
[](const Entry &lhs, const Entry &rhs) -> bool {
2451+
return lhs.first < rhs.first;
2452+
});
2453+
}
2454+
2455+
decltype(elts)::const_iterator begin() const {
2456+
assert(sorted);
2457+
return elts.begin();
2458+
}
2459+
2460+
decltype(elts)::const_iterator end() const {
2461+
assert(sorted);
2462+
return elts.end();
2463+
}
2464+
};
2465+
2466+
} // end namespace
2467+
24202468
ArrayRef<Decl *>
24212469
EmittedMembersRequest::evaluate(Evaluator &evaluator,
24222470
ClassDecl *CD) const {
@@ -2457,16 +2505,37 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator,
24572505
forceConformance(Context.getProtocol(KnownProtocolKind::Hashable));
24582506
forceConformance(Context.getProtocol(KnownProtocolKind::Differentiable));
24592507

2460-
// The projected storage wrapper ($foo) might have dynamically-dispatched
2461-
// accessors, so force them to be synthesized.
24622508
for (auto *member : CD->getMembers()) {
2463-
if (auto *var = dyn_cast<VarDecl>(member))
2509+
if (auto *var = dyn_cast<VarDecl>(member)) {
2510+
// The projected storage wrapper ($foo) might have dynamically-dispatched
2511+
// accessors, so force them to be synthesized.
24642512
if (var->hasAttachedPropertyWrapper())
24652513
(void) var->getPropertyWrapperBackingProperty();
2514+
}
2515+
}
2516+
2517+
SortedFuncList synthesizedMembers;
2518+
2519+
for (auto *member : CD->getMembers()) {
2520+
if (auto *afd = dyn_cast<AbstractFunctionDecl>(member)) {
2521+
// Add synthesized members to a side table and sort them by their mangled
2522+
// name, since they could have been added to the class in any order.
2523+
if (afd->isSynthesized()) {
2524+
synthesizedMembers.add(afd);
2525+
continue;
2526+
}
2527+
}
2528+
2529+
result.push_back(member);
2530+
}
2531+
2532+
if (!synthesizedMembers.empty()) {
2533+
synthesizedMembers.sort();
2534+
2535+
for (const auto &pair : synthesizedMembers)
2536+
result.push_back(pair.second);
24662537
}
24672538

2468-
auto members = CD->getMembers();
2469-
result.append(members.begin(), members.end());
24702539
return Context.AllocateCopy(result);
24712540
}
24722541

0 commit comments

Comments
 (0)