Skip to content

Commit 2a89d5c

Browse files
committed
Start recovering from missing types in SIL deserialization
Now that @inlinable is a supported feature, we need to handle cases where a function is inlinable but it references some type that imports differently in different Swift versions. To start, handle the case where a SIL function's type is now invalid and therefore the entire function can't be imported. This doesn't open up anything interesting yet, but it's a start. Part of rdar://problem/40899824
1 parent 5459e0d commit 2a89d5c

File tree

9 files changed

+184
-57
lines changed

9 files changed

+184
-57
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,6 @@ void TypeError::anchor() {}
129129
const char ExtensionError::ID = '\0';
130130
void ExtensionError::anchor() {}
131131

132-
LLVM_NODISCARD
133-
static std::unique_ptr<llvm::ErrorInfoBase> takeErrorInfo(llvm::Error error) {
134-
std::unique_ptr<llvm::ErrorInfoBase> result;
135-
llvm::handleAllErrors(std::move(error),
136-
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
137-
result = std::move(info);
138-
});
139-
return result;
140-
}
141-
142-
143132
/// Skips a single record in the bitstream.
144133
///
145134
/// Returns true if the next entry is a record of type \p recordKind.
@@ -4756,27 +4745,42 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
47564745
}
47574746

47584747
auto processParameter = [&](TypeID typeID, uint64_t rawConvention)
4759-
-> Optional<SILParameterInfo> {
4748+
-> llvm::Expected<SILParameterInfo> {
47604749
auto convention = getActualParameterConvention(rawConvention);
4761-
auto type = getType(typeID);
4762-
if (!convention || !type) return None;
4763-
return SILParameterInfo(type->getCanonicalType(), *convention);
4750+
if (!convention) {
4751+
error();
4752+
llvm_unreachable("an error is a fatal exit at this point");
4753+
}
4754+
auto type = getTypeChecked(typeID);
4755+
if (!type)
4756+
return type.takeError();
4757+
return SILParameterInfo(type.get()->getCanonicalType(), *convention);
47644758
};
47654759

47664760
auto processYield = [&](TypeID typeID, uint64_t rawConvention)
4767-
-> Optional<SILYieldInfo> {
4761+
-> llvm::Expected<SILYieldInfo> {
47684762
auto convention = getActualParameterConvention(rawConvention);
4769-
auto type = getType(typeID);
4770-
if (!convention || !type) return None;
4771-
return SILYieldInfo(type->getCanonicalType(), *convention);
4763+
if (!convention) {
4764+
error();
4765+
llvm_unreachable("an error is a fatal exit at this point");
4766+
}
4767+
auto type = getTypeChecked(typeID);
4768+
if (!type)
4769+
return type.takeError();
4770+
return SILYieldInfo(type.get()->getCanonicalType(), *convention);
47724771
};
47734772

47744773
auto processResult = [&](TypeID typeID, uint64_t rawConvention)
4775-
-> Optional<SILResultInfo> {
4774+
-> llvm::Expected<SILResultInfo> {
47764775
auto convention = getActualResultConvention(rawConvention);
4777-
auto type = getType(typeID);
4778-
if (!convention || !type) return None;
4779-
return SILResultInfo(type->getCanonicalType(), *convention);
4776+
if (!convention) {
4777+
error();
4778+
llvm_unreachable("an error is a fatal exit at this point");
4779+
}
4780+
auto type = getTypeChecked(typeID);
4781+
if (!type)
4782+
return type.takeError();
4783+
return SILResultInfo(type.get()->getCanonicalType(), *convention);
47804784
};
47814785

47824786
// Bounds check. FIXME: overflow
@@ -4795,11 +4799,9 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
47954799
auto typeID = variableData[nextVariableDataIndex++];
47964800
auto rawConvention = variableData[nextVariableDataIndex++];
47974801
auto param = processParameter(typeID, rawConvention);
4798-
if (!param) {
4799-
error();
4800-
return nullptr;
4801-
}
4802-
allParams.push_back(*param);
4802+
if (!param)
4803+
return param.takeError();
4804+
allParams.push_back(param.get());
48034805
}
48044806

48054807
// Process the yields.
@@ -4809,11 +4811,9 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
48094811
auto typeID = variableData[nextVariableDataIndex++];
48104812
auto rawConvention = variableData[nextVariableDataIndex++];
48114813
auto yield = processYield(typeID, rawConvention);
4812-
if (!yield) {
4813-
error();
4814-
return nullptr;
4815-
}
4816-
allYields.push_back(*yield);
4814+
if (!yield)
4815+
return yield.takeError();
4816+
allYields.push_back(yield.get());
48174817
}
48184818

48194819
// Process the results.
@@ -4823,23 +4823,20 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
48234823
auto typeID = variableData[nextVariableDataIndex++];
48244824
auto rawConvention = variableData[nextVariableDataIndex++];
48254825
auto result = processResult(typeID, rawConvention);
4826-
if (!result) {
4827-
error();
4828-
return nullptr;
4829-
}
4830-
allResults.push_back(*result);
4826+
if (!result)
4827+
return result.takeError();
4828+
allResults.push_back(result.get());
48314829
}
48324830

48334831
// Process the error result.
48344832
Optional<SILResultInfo> errorResult;
48354833
if (hasErrorResult) {
48364834
auto typeID = variableData[nextVariableDataIndex++];
48374835
auto rawConvention = variableData[nextVariableDataIndex++];
4838-
errorResult = processResult(typeID, rawConvention);
4839-
if (!errorResult) {
4840-
error();
4841-
return nullptr;
4842-
}
4836+
auto maybeErrorResult = processResult(typeID, rawConvention);
4837+
if (!maybeErrorResult)
4838+
return maybeErrorResult.takeError();
4839+
errorResult = maybeErrorResult.get();
48434840
}
48444841

48454842
Optional<ProtocolConformanceRef> witnessMethodConformance;

lib/Serialization/DeserializationErrors.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,41 @@ class ExtensionError : public llvm::ErrorInfo<ExtensionError> {
355355
}
356356
};
357357

358+
class SILEntityError : public llvm::ErrorInfo<SILEntityError> {
359+
friend ErrorInfo;
360+
static const char ID;
361+
void anchor() override;
362+
363+
std::unique_ptr<ErrorInfoBase> underlyingReason;
364+
StringRef name;
365+
public:
366+
SILEntityError(StringRef name, std::unique_ptr<ErrorInfoBase> reason)
367+
: underlyingReason(std::move(reason)), name(name) {}
368+
369+
void log(raw_ostream &OS) const override {
370+
OS << "could not deserialize SIL entity '" << name << "'";
371+
if (underlyingReason) {
372+
OS << ": ";
373+
underlyingReason->log(OS);
374+
}
375+
}
376+
377+
std::error_code convertToErrorCode() const override {
378+
return llvm::inconvertibleErrorCode();
379+
}
380+
};
381+
382+
LLVM_NODISCARD
383+
static inline std::unique_ptr<llvm::ErrorInfoBase>
384+
takeErrorInfo(llvm::Error error) {
385+
std::unique_ptr<llvm::ErrorInfoBase> result;
386+
llvm::handleAllErrors(std::move(error),
387+
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
388+
result = std::move(info);
389+
});
390+
return result;
391+
}
392+
358393
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
359394
const char *Action;
360395
const ModuleFile &MF;

lib/Serialization/DeserializeSIL.cpp

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212

1313
#define DEBUG_TYPE "deserialize"
1414
#include "DeserializeSIL.h"
15+
16+
#include "DeserializationErrors.h"
17+
#include "SILFormat.h"
18+
1519
#include "swift/Basic/Defer.h"
1620
#include "swift/Basic/PrettyStackTrace.h"
1721
#include "swift/AST/GenericSignature.h"
1822
#include "swift/AST/ProtocolConformance.h"
1923
#include "swift/AST/PrettyStackTrace.h"
2024
#include "swift/Serialization/ModuleFile.h"
21-
#include "SILFormat.h"
2225
#include "swift/SIL/SILArgument.h"
2326
#include "swift/SIL/SILBuilder.h"
2427
#include "swift/SIL/SILDebugScope.h"
@@ -38,6 +41,9 @@ using namespace swift::serialization;
3841
using namespace swift::serialization::sil_block;
3942
using namespace llvm::support;
4043

44+
const char SILEntityError::ID = '\0';
45+
void SILEntityError::anchor() {}
46+
4147
STATISTIC(NumDeserializedFunc, "Number of deserialized SIL functions");
4248

4349
static Optional<StringLiteralInst::Encoding>
@@ -339,7 +345,14 @@ SILFunction *SILDeserializer::getFuncForReference(StringRef name,
339345
// Otherwise, look for a function with this name in the module.
340346
auto iter = FuncTable->find(name);
341347
if (iter != FuncTable->end()) {
342-
fn = readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true);
348+
auto maybeFn = readSILFunctionChecked(*iter, nullptr, name,
349+
/*declarationOnly*/ true);
350+
if (maybeFn) {
351+
fn = maybeFn.get();
352+
} else {
353+
// Ignore the failure; we'll synthesize a bogus function instead.
354+
llvm::consumeError(maybeFn.takeError());
355+
}
343356
}
344357
}
345358

@@ -386,6 +399,19 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
386399
StringRef name,
387400
bool declarationOnly,
388401
bool errorIfEmptyBody) {
402+
llvm::Expected<SILFunction *> deserialized =
403+
readSILFunctionChecked(FID, existingFn, name, declarationOnly,
404+
errorIfEmptyBody);
405+
if (!deserialized) {
406+
MF->fatal(deserialized.takeError());
407+
}
408+
return deserialized.get();
409+
}
410+
411+
llvm::Expected<SILFunction *>
412+
SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
413+
StringRef name, bool declarationOnly,
414+
bool errorIfEmptyBody) {
389415
// We can't deserialize function bodies after IRGen lowering passes have
390416
// happened since other definitions in the module will no longer be in
391417
// canonical SIL form.
@@ -444,7 +470,16 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
444470
MF->error();
445471
return nullptr;
446472
}
447-
auto ty = getSILType(MF->getType(funcTyID), SILValueCategory::Object);
473+
auto astType = MF->getTypeChecked(funcTyID);
474+
if (!astType) {
475+
if (!existingFn || errorIfEmptyBody) {
476+
return llvm::make_error<SILEntityError>(
477+
name, takeErrorInfo(astType.takeError()));
478+
}
479+
llvm::consumeError(astType.takeError());
480+
return existingFn;
481+
}
482+
auto ty = getSILType(astType.get(), SILValueCategory::Object);
448483
if (!ty.is<SILFunctionType>()) {
449484
DEBUG(llvm::dbgs() << "not a function type for SILFunction\n");
450485
MF->error();
@@ -2396,14 +2431,21 @@ SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) {
23962431
if (iter == FuncTable->end())
23972432
return nullptr;
23982433

2399-
auto Func = readSILFunction(*iter, InFunc, name, /*declarationOnly*/ false);
2400-
if (Func) {
2434+
auto maybeFunc = readSILFunctionChecked(*iter, InFunc, name,
2435+
/*declarationOnly*/ false);
2436+
if (!maybeFunc) {
2437+
// Ignore the error; treat it as if we didn't have a definition.
2438+
llvm::consumeError(maybeFunc.takeError());
2439+
return nullptr;
2440+
}
2441+
2442+
if (maybeFunc.get()) {
24012443
DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
2402-
Func->dump());
2403-
assert(InFunc->getName() == Func->getName());
2444+
maybeFunc.get()->dump());
2445+
assert(InFunc->getName() == maybeFunc.get()->getName());
24042446
}
24052447

2406-
return Func;
2448+
return maybeFunc.get();
24072449
}
24082450

24092451
/// Check for existence of a function with a given name and required linkage.
@@ -2480,11 +2522,20 @@ SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
24802522
if (iter == FuncTable->end())
24812523
return nullptr;
24822524

2483-
auto Func = readSILFunction(*iter, nullptr, name, declarationOnly);
2484-
if (Func)
2525+
auto maybeFunc = readSILFunctionChecked(*iter, nullptr, name,
2526+
declarationOnly);
2527+
2528+
if (!maybeFunc) {
2529+
// Ignore the error; treat it as if we didn't have a definition.
2530+
llvm::consumeError(maybeFunc.takeError());
2531+
return nullptr;
2532+
}
2533+
2534+
if (maybeFunc.get()) {
24852535
DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
2486-
Func->dump());
2487-
return Func;
2536+
maybeFunc.get()->dump());
2537+
}
2538+
return maybeFunc.get();
24882539
}
24892540

24902541
SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) {
@@ -2580,8 +2631,12 @@ void SILDeserializer::getAllSILFunctions() {
25802631
auto DI = FuncTable->find(*KI);
25812632
assert(DI != FuncTable->end() && "There should never be a key without data.");
25822633

2583-
readSILFunction(*DI, nullptr, *KI, false,
2584-
false/*errorIfEmptyBody*/);
2634+
auto maybeFunc = readSILFunctionChecked(*DI, nullptr, *KI, false,
2635+
false/*errorIfEmptyBody*/);
2636+
if (!maybeFunc) {
2637+
// Ignore the error; treat it as if we didn't have a definition.
2638+
llvm::consumeError(maybeFunc.takeError());
2639+
}
25852640
}
25862641
}
25872642

lib/Serialization/DeserializeSIL.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ namespace swift {
8181
SILFunction *readSILFunction(serialization::DeclID, SILFunction *InFunc,
8282
StringRef Name, bool declarationOnly,
8383
bool errorIfEmptyBody = true);
84+
/// Read a SIL function.
85+
llvm::Expected<SILFunction *>
86+
readSILFunctionChecked(serialization::DeclID, SILFunction *InFunc,
87+
StringRef Name, bool declarationOnly,
88+
bool errorIfEmptyBody = true);
89+
8490
/// Read a SIL basic block within a given SIL function.
8591
SILBasicBlock *readSILBasicBlock(SILFunction *Fn,
8692
SILBasicBlock *Prev,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// struct SoonToBeMissing {
2+
// int value;
3+
// };
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module Types { header "Types.h" }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct SoonToBeMissing {
2+
int value;
3+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module Types { header "Types.h" }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -parse-sil %s -emit-sib -o %t/Library.sib -module-name Library -I %S/Inputs/good-modules -parse-stdlib
3+
// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/good-modules | %FileCheck %s
4+
// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/bad-modules | %FileCheck -check-prefix=CHECK-RECOVERY %s
5+
// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/bad-modules | %FileCheck -check-prefix=CHECK-RECOVERY-NEGATIVE %s
6+
7+
// CHECK-LABEL: sil_stage raw
8+
// CHECK-RECOVERY-LABEL: sil_stage raw
9+
10+
sil_stage raw
11+
import Types
12+
13+
// CHECK-LABEL: sil @missingParam : $@convention(thin) (SoonToBeMissing) -> () {
14+
// CHECK-RECOVERY-NEGATIVE-NOT: sil @missingParam
15+
sil @missingParam : $@convention(thin) (SoonToBeMissing) -> () {
16+
entry(%arg: $SoonToBeMissing):
17+
%9999 = tuple()
18+
return %9999 : $()
19+
}
20+
21+
// CHECK-LABEL: sil @missingResult : $@convention(thin) () -> SoonToBeMissing {
22+
// CHECK-RECOVERY-NEGATIVE-NOT: sil @missingResult
23+
sil @missingResult : $@convention(thin) () -> (SoonToBeMissing) {
24+
entry:
25+
unreachable
26+
}

0 commit comments

Comments
 (0)