Merge pull request #17589 from eeckstein/disable-static-strings-macos
Temporarily disable generation of static long Strings for macos.
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index e92dd07..e970e58 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -1176,6 +1176,12 @@
///
/// Meaningful for all type-descriptor kinds.
IsReflectable = 2,
+
+ /// Set if the type is a Clang-importer-synthesized related entity. After
+ /// the null terminator for the type name is another null-terminated string
+ /// containing the tag that discriminates the entity from other synthesized
+ /// declarations associated with the same declaration.
+ IsSynthesizedRelatedEntity = 3,
/// Set if the context descriptor is includes metadata for dynamically
/// constructing a class's vtables at metadata instantiation time.
@@ -1208,6 +1214,10 @@
FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTypedef, isCTypedef, setIsCTypedef)
FLAGSET_DEFINE_FLAG_ACCESSORS(IsReflectable, isReflectable, setIsReflectable)
+ FLAGSET_DEFINE_FLAG_ACCESSORS(IsSynthesizedRelatedEntity,
+ isSynthesizedRelatedEntity,
+ setIsSynthesizedRelatedEntity)
+
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
class_hasVTable,
class_setHasVTable)
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index 83670b5..27cb3be 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -36,7 +36,6 @@
NODE(BoundGenericEnum)
NODE(BoundGenericStructure)
NODE(BoundGenericOtherNominalType)
-NODE(BoundGenericTypeAlias)
NODE(BuiltinTypeName)
NODE(CFunctionPointer)
CONTEXT_NODE(Class)
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index 9d64ea2..55ecb4c 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -1136,12 +1136,13 @@
Demangle::NodePointer
buildNominalTypeMangling(ContextDescriptorRef descriptor,
Demangle::NodeFactory &nodeFactory) {
- std::vector<std::pair<Demangle::Node::Kind, std::string>>
+ std::vector<std::pair<Demangle::Node::Kind, Demangle::NodePointer>>
nameComponents;
ContextDescriptorRef parent = descriptor;
while (parent) {
std::string nodeName;
+ std::string relatedTag;
Demangle::Node::Kind nodeKind;
auto getTypeName = [&]() -> bool {
@@ -1149,7 +1150,16 @@
reinterpret_cast<const TargetTypeContextDescriptor<Runtime> *>
(parent.getLocalBuffer());
auto nameAddress = resolveRelativeField(parent, typeBuffer->Name);
- return Reader->readString(RemoteAddress(nameAddress), nodeName);
+ if (!Reader->readString(RemoteAddress(nameAddress), nodeName))
+ return false;
+
+ if (typeBuffer->isSynthesizedRelatedEntity()) {
+ nameAddress += nodeName.size() + 1;
+ if (!Reader->readString(RemoteAddress(nameAddress), relatedTag))
+ return false;
+ }
+
+ return true;
};
bool isTypeContext = false;
@@ -1208,8 +1218,17 @@
else if (typeFlags.isCTypedef())
nodeKind = Demangle::Node::Kind::TypeAlias;
}
+
+ auto nameNode = nodeFactory.createNode(Node::Kind::Identifier,
+ nodeName);
+ if (!relatedTag.empty()) {
+ auto relatedNode =
+ nodeFactory.createNode(Node::Kind::RelatedEntityDeclName, relatedTag);
+ relatedNode->addChild(nameNode, nodeFactory);
+ nameNode = relatedNode;
+ }
- nameComponents.emplace_back(nodeKind, nodeName);
+ nameComponents.emplace_back(nodeKind, nameNode);
parent = readParentContextDescriptor(parent);
}
@@ -1222,13 +1241,11 @@
auto moduleInfo = std::move(nameComponents.back());
nameComponents.pop_back();
auto demangling =
- nodeFactory.createNode(Node::Kind::Module, moduleInfo.second);
+ nodeFactory.createNode(Node::Kind::Module, moduleInfo.second->getText());
for (auto &component : reversed(nameComponents)) {
- auto name = nodeFactory.createNode(Node::Kind::Identifier,
- component.second);
auto parent = nodeFactory.createNode(component.first);
parent->addChild(demangling, nodeFactory);
- parent->addChild(name, nodeFactory);
+ parent->addChild(component.second, nodeFactory);
demangling = parent;
}
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 9689c29..e473285 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -3511,6 +3511,21 @@
llvm::ArrayRef<GenericParamDescriptor> getGenericParams() const;
+ bool isSynthesizedRelatedEntity() const {
+ return getTypeContextDescriptorFlags().isSynthesizedRelatedEntity();
+ }
+
+ /// Return the tag used to discriminate declarations synthesized by the
+ /// Clang importer and give them stable identities.
+ StringRef getSynthesizedDeclRelatedEntityTag() const {
+ if (!isSynthesizedRelatedEntity())
+ return {};
+ // The tag name comes after the null terminator for the name.
+ const char *nameBegin = Name.get();
+ auto *nameEnd = nameBegin + strlen(nameBegin) + 1;
+ return nameEnd;
+ }
+
/// Return the offset of the start of generic arguments in the nominal
/// type's metadata. The returned value is measured in sizeof(void*).
int32_t getGenericArgumentOffset() const;
diff --git a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
index 31e508f..f98e4ba 100644
--- a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
@@ -13,16 +13,17 @@
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_ARCANALYSIS_H
#define SWIFT_SILOPTIMIZER_ANALYSIS_ARCANALYSIS_H
+#include "swift/Basic/LLVM.h"
#include "swift/SIL/SILArgument.h"
-#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILBasicBlock.h"
+#include "swift/SIL/SILValue.h"
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h"
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/TinyPtrVector.h"
namespace swift {
@@ -147,7 +148,8 @@
/// Return true if all the successors of the EpilogueRetainInsts do not have
/// a retain.
- bool isTransitiveSuccessorsRetainFree(llvm::DenseSet<SILBasicBlock *> BBs);
+ bool
+ isTransitiveSuccessorsRetainFree(const llvm::DenseSet<SILBasicBlock *> &BBs);
/// Finds matching releases in the provided block \p BB.
RetainKindValue findMatchingRetainsInBasicBlock(SILBasicBlock *BB, SILValue V);
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index cc88090..0e6cc67 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -739,31 +739,18 @@
auto aliasTy = cast<NameAliasType>(tybase);
// It's not possible to mangle the context of the builtin module.
- // For the DWARF output we want to mangle the type alias + context,
- // unless the type alias references a builtin type.
TypeAliasDecl *decl = aliasTy->getDecl();
if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) {
return appendType(aliasTy->getSinglyDesugaredType());
}
- if (type->isSpecialized()) {
- // Try to mangle the entire name as a substitution.
- if (tryMangleSubstitution(tybase))
- return;
+ // FIXME: We also cannot yet mangle references to typealiases that
+ // involve generics.
+ if (decl->getGenericSignature())
+ return appendSugaredType<NameAliasType>(type);
- appendAnyGenericType(decl);
- bool isFirstArgList = true;
- if (auto *nominalType = type->getAs<NominalType>()) {
- if (nominalType->getParent())
- type = nominalType->getParent();
- }
- appendBoundGenericArgs(type, isFirstArgList);
- appendRetroactiveConformances(type);
- appendOperator("G");
- addSubstitution(type.getPointer());
- return;
- }
-
+ // For the DWARF output we want to mangle the type alias + context,
+ // unless the type alias references a builtin type.
return appendAnyGenericType(decl);
}
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index 7d21b60..9d2fa8d 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -1335,9 +1335,6 @@
case Node::Kind::OtherNominalType:
kind = Node::Kind::BoundGenericOtherNominalType;
break;
- case Node::Kind::TypeAlias:
- kind = Node::Kind::BoundGenericTypeAlias;
- break;
default:
return nullptr;
}
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 866318b..7703600 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -267,7 +267,6 @@
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericOtherNominalType:
- case Node::Kind::BoundGenericTypeAlias:
case Node::Kind::BuiltinTypeName:
case Node::Kind::Class:
case Node::Kind::DependentGenericType:
@@ -1541,7 +1540,6 @@
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericOtherNominalType:
- case Node::Kind::BoundGenericTypeAlias:
printBoundGeneric(Node);
return nullptr;
case Node::Kind::DynamicSelf:
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index 30cad13..4c8562a 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -1875,11 +1875,6 @@
mangleAnyNominalType(node, ctx);
}
-void Remangler::mangleBoundGenericTypeAlias(Node *node) {
- EntityContext ctx;
- mangleAnyNominalType(node, ctx);
-}
-
void Remangler::mangleTypeList(Node *node) {
mangleChildNodes(node); // all types
Out << '_';
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index ee3807f..8219f88 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -463,7 +463,6 @@
case Node::Kind::Enum: return mangleAnyGenericType(node, "O");
case Node::Kind::Class: return mangleAnyGenericType(node, "C");
case Node::Kind::OtherNominalType: return mangleAnyGenericType(node, "XY");
- case Node::Kind::TypeAlias: return mangleAnyGenericType(node, "a");
default:
unreachable("bad nominal type kind");
}
@@ -482,8 +481,7 @@
case Node::Kind::BoundGenericOtherNominalType:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
- case Node::Kind::BoundGenericClass:
- case Node::Kind::BoundGenericTypeAlias: {
+ case Node::Kind::BoundGenericClass: {
NodePointer unboundType = node->getChild(0);
assert(unboundType->getKind() == Node::Kind::Type);
NodePointer nominalType = unboundType->getChild(0);
@@ -595,10 +593,6 @@
mangleAnyNominalType(node);
}
-void Remangler::mangleBoundGenericTypeAlias(Node *node) {
- mangleAnyNominalType(node);
-}
-
void Remangler::mangleBuiltinTypeName(Node *node) {
Buffer << 'B';
StringRef text = node->getText();
@@ -2037,7 +2031,6 @@
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericClass:
case Node::Kind::BoundGenericOtherNominalType:
- case Node::Kind::BoundGenericTypeAlias:
return true;
case Node::Kind::Structure:
@@ -2073,8 +2066,7 @@
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericClass:
- case Node::Kind::BoundGenericOtherNominalType:
- case Node::Kind::BoundGenericTypeAlias: {
+ case Node::Kind::BoundGenericOtherNominalType: {
NodePointer unboundType = node->getChild(0);
assert(unboundType->getKind() == Node::Kind::Type);
NodePointer nominalType = unboundType->getChild(0);
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 975276f..1b9b982 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -4115,6 +4115,9 @@
// layout. Calling isResilient() with this scope will always return false.
ResilienceExpansion
IRGenModule::getResilienceExpansionForLayout(NominalTypeDecl *decl) {
+ if (Types.isCompletelyFragile())
+ return ResilienceExpansion::Minimal;
+
if (isResilient(decl, ResilienceExpansion::Minimal))
return ResilienceExpansion::Maximal;
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index f247427..485a93a 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -481,11 +481,21 @@
}
void addName() {
+ SmallString<32> nameBuf;
StringRef name;
-
+
+ // Use the original name with tag for synthesized decls. The tag comes
+ // after the null terminator for the name.
+ if (auto *synthesizedTypeAttr =
+ Type->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>()) {
+ nameBuf.append(synthesizedTypeAttr->originalTypeName);
+ nameBuf.push_back('\0');
+ nameBuf.append(synthesizedTypeAttr->getManglingName());
+
+ name = nameBuf;
// Try to use the Clang name if there is one.
- if (auto namedClangDecl =
- Mangle::ASTMangler::getClangDeclForMangling(Type)) {
+ } else if (auto namedClangDecl =
+ Mangle::ASTMangler::getClangDeclForMangling(Type)) {
name = namedClangDecl->getName();
} else {
name = Type->getName().str();
@@ -565,22 +575,18 @@
/// Flags to indicate Clang-imported declarations so we mangle them
/// consistently at runtime.
void getClangImportedFlags(TypeContextDescriptorFlags &flags) const {
- auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type);
- if (!clangDecl)
- return;
-
- if (isa<clang::TagDecl>(clangDecl)) {
- flags.setIsCTag(true);
- return;
+ if (Type->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>()) {
+ flags.setIsSynthesizedRelatedEntity(true);
}
- if (isa<clang::TypedefNameDecl>(clangDecl)
- || isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
- flags.setIsCTypedef(true);
- return;
+ if (auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type)) {
+ if (isa<clang::TagDecl>(clangDecl)) {
+ flags.setIsCTag(true);
+ } else if (isa<clang::TypedefNameDecl>(clangDecl)
+ || isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
+ flags.setIsCTypedef(true);
+ }
}
-
- return;
}
// Subclasses should provide:
diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp
index cdeda25..29c67fc 100644
--- a/lib/RemoteAST/RemoteAST.cpp
+++ b/lib/RemoteAST/RemoteAST.cpp
@@ -753,7 +753,17 @@
if (HadError) return;
if (decl == Result) return;
if (!Result) {
- Result = cast<NominalTypeDecl>(decl);
+ // A synthesized type from the Clang importer may resolve to a
+ // compatibility alias.
+ if (auto resultAlias = dyn_cast<TypeAliasDecl>(decl)) {
+ if (resultAlias->isCompatibilityAlias()) {
+ Result = resultAlias->getUnderlyingTypeLoc().getType()
+ ->getAnyNominal();
+ }
+ } else {
+ Result = dyn_cast<NominalTypeDecl>(decl);
+ }
+ HadError |= !Result;
} else {
HadError = true;
Result = nullptr;
diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp
index e6c774a..a29f259 100644
--- a/lib/SIL/Projection.cpp
+++ b/lib/SIL/Projection.cpp
@@ -840,6 +840,24 @@
return Proj->createProjection(B, Loc, Arg);
}
+// Projection tree only supports structs and tuples today.
+static bool isSupportedProjection(const Projection &p) {
+ switch (p.getKind()) {
+ case ProjectionKind::Struct:
+ case ProjectionKind::Tuple:
+ return true;
+ case ProjectionKind::Class:
+ case ProjectionKind::Enum:
+ case ProjectionKind::Box:
+ case ProjectionKind::Upcast:
+ case ProjectionKind::RefCast:
+ case ProjectionKind::BitwiseCast:
+ case ProjectionKind::TailElems:
+ case ProjectionKind::Index:
+ return false;
+ }
+}
+
void
ProjectionTreeNode::
processUsersOfValue(ProjectionTree &Tree,
@@ -863,12 +881,11 @@
continue;
}
- // Check whether the user is such a projection.
auto P = Projection(projectionInst);
- // If we fail to create a projection, add User as a user to this node and
- // continue.
- if (!P.isValid()) {
+ // If we fail to create a projection or this is a type of projection that we
+ // do not support, add User as a user to this node and continue.
+ if (!P.isValid() || !isSupportedProjection(P)) {
DEBUG(llvm::dbgs() << " Failed to create projection. Adding "
"to non projection user!\n");
addNonProjectionUser(Op);
diff --git a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
index c9a3ea2..93e0553 100644
--- a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
@@ -498,22 +498,24 @@
findMatchingRetains(&*BB);
}
-bool
-ConsumedResultToEpilogueRetainMatcher::
-isTransitiveSuccessorsRetainFree(llvm::DenseSet<SILBasicBlock *> BBs) {
+bool ConsumedResultToEpilogueRetainMatcher::isTransitiveSuccessorsRetainFree(
+ const llvm::DenseSet<SILBasicBlock *> &BBs) {
// For every block with retain, we need to check the transitive
// closure of its successors are retain-free.
for (auto &I : EpilogueRetainInsts) {
- auto *CBB = I->getParent();
- for (auto &Succ : CBB->getSuccessors()) {
- if (BBs.find(Succ) != BBs.end())
+ for (auto &Succ : I->getParent()->getSuccessors()) {
+ if (BBs.count(Succ))
continue;
return false;
}
}
+
+ // FIXME: We are iterating over a DenseSet. That can lead to non-determinism
+ // and is in general pretty inefficient since we are iterating over a hash
+ // table.
for (auto CBB : BBs) {
for (auto &Succ : CBB->getSuccessors()) {
- if (BBs.find(Succ) != BBs.end())
+ if (BBs.count(Succ))
continue;
return false;
}
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index decc345..c877936 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -129,17 +129,6 @@
const char ExtensionError::ID = '\0';
void ExtensionError::anchor() {}
-LLVM_NODISCARD
-static std::unique_ptr<llvm::ErrorInfoBase> takeErrorInfo(llvm::Error error) {
- std::unique_ptr<llvm::ErrorInfoBase> result;
- llvm::handleAllErrors(std::move(error),
- [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
- result = std::move(info);
- });
- return result;
-}
-
-
/// Skips a single record in the bitstream.
///
/// Returns true if the next entry is a record of type \p recordKind.
@@ -4816,27 +4805,42 @@
}
auto processParameter = [&](TypeID typeID, uint64_t rawConvention)
- -> Optional<SILParameterInfo> {
+ -> llvm::Expected<SILParameterInfo> {
auto convention = getActualParameterConvention(rawConvention);
- auto type = getType(typeID);
- if (!convention || !type) return None;
- return SILParameterInfo(type->getCanonicalType(), *convention);
+ if (!convention) {
+ error();
+ llvm_unreachable("an error is a fatal exit at this point");
+ }
+ auto type = getTypeChecked(typeID);
+ if (!type)
+ return type.takeError();
+ return SILParameterInfo(type.get()->getCanonicalType(), *convention);
};
auto processYield = [&](TypeID typeID, uint64_t rawConvention)
- -> Optional<SILYieldInfo> {
+ -> llvm::Expected<SILYieldInfo> {
auto convention = getActualParameterConvention(rawConvention);
- auto type = getType(typeID);
- if (!convention || !type) return None;
- return SILYieldInfo(type->getCanonicalType(), *convention);
+ if (!convention) {
+ error();
+ llvm_unreachable("an error is a fatal exit at this point");
+ }
+ auto type = getTypeChecked(typeID);
+ if (!type)
+ return type.takeError();
+ return SILYieldInfo(type.get()->getCanonicalType(), *convention);
};
auto processResult = [&](TypeID typeID, uint64_t rawConvention)
- -> Optional<SILResultInfo> {
+ -> llvm::Expected<SILResultInfo> {
auto convention = getActualResultConvention(rawConvention);
- auto type = getType(typeID);
- if (!convention || !type) return None;
- return SILResultInfo(type->getCanonicalType(), *convention);
+ if (!convention) {
+ error();
+ llvm_unreachable("an error is a fatal exit at this point");
+ }
+ auto type = getTypeChecked(typeID);
+ if (!type)
+ return type.takeError();
+ return SILResultInfo(type.get()->getCanonicalType(), *convention);
};
// Bounds check. FIXME: overflow
@@ -4855,11 +4859,9 @@
auto typeID = variableData[nextVariableDataIndex++];
auto rawConvention = variableData[nextVariableDataIndex++];
auto param = processParameter(typeID, rawConvention);
- if (!param) {
- error();
- return nullptr;
- }
- allParams.push_back(*param);
+ if (!param)
+ return param.takeError();
+ allParams.push_back(param.get());
}
// Process the yields.
@@ -4869,11 +4871,9 @@
auto typeID = variableData[nextVariableDataIndex++];
auto rawConvention = variableData[nextVariableDataIndex++];
auto yield = processYield(typeID, rawConvention);
- if (!yield) {
- error();
- return nullptr;
- }
- allYields.push_back(*yield);
+ if (!yield)
+ return yield.takeError();
+ allYields.push_back(yield.get());
}
// Process the results.
@@ -4883,11 +4883,9 @@
auto typeID = variableData[nextVariableDataIndex++];
auto rawConvention = variableData[nextVariableDataIndex++];
auto result = processResult(typeID, rawConvention);
- if (!result) {
- error();
- return nullptr;
- }
- allResults.push_back(*result);
+ if (!result)
+ return result.takeError();
+ allResults.push_back(result.get());
}
// Process the error result.
@@ -4895,11 +4893,10 @@
if (hasErrorResult) {
auto typeID = variableData[nextVariableDataIndex++];
auto rawConvention = variableData[nextVariableDataIndex++];
- errorResult = processResult(typeID, rawConvention);
- if (!errorResult) {
- error();
- return nullptr;
- }
+ auto maybeErrorResult = processResult(typeID, rawConvention);
+ if (!maybeErrorResult)
+ return maybeErrorResult.takeError();
+ errorResult = maybeErrorResult.get();
}
Optional<ProtocolConformanceRef> witnessMethodConformance;
diff --git a/lib/Serialization/DeserializationErrors.h b/lib/Serialization/DeserializationErrors.h
index 0703ea4..dc0e952 100644
--- a/lib/Serialization/DeserializationErrors.h
+++ b/lib/Serialization/DeserializationErrors.h
@@ -355,6 +355,41 @@
}
};
+class SILEntityError : public llvm::ErrorInfo<SILEntityError> {
+ friend ErrorInfo;
+ static const char ID;
+ void anchor() override;
+
+ std::unique_ptr<ErrorInfoBase> underlyingReason;
+ StringRef name;
+public:
+ SILEntityError(StringRef name, std::unique_ptr<ErrorInfoBase> reason)
+ : underlyingReason(std::move(reason)), name(name) {}
+
+ void log(raw_ostream &OS) const override {
+ OS << "could not deserialize SIL entity '" << name << "'";
+ if (underlyingReason) {
+ OS << ": ";
+ underlyingReason->log(OS);
+ }
+ }
+
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+LLVM_NODISCARD
+static inline std::unique_ptr<llvm::ErrorInfoBase>
+takeErrorInfo(llvm::Error error) {
+ std::unique_ptr<llvm::ErrorInfoBase> result;
+ llvm::handleAllErrors(std::move(error),
+ [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
+ result = std::move(info);
+ });
+ return result;
+}
+
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
const char *Action;
const ModuleFile &MF;
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 1c2ad04..75b8a45 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -12,13 +12,16 @@
#define DEBUG_TYPE "deserialize"
#include "DeserializeSIL.h"
+
+#include "DeserializationErrors.h"
+#include "SILFormat.h"
+
#include "swift/Basic/Defer.h"
#include "swift/Basic/PrettyStackTrace.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/Serialization/ModuleFile.h"
-#include "SILFormat.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILDebugScope.h"
@@ -38,6 +41,9 @@
using namespace swift::serialization::sil_block;
using namespace llvm::support;
+const char SILEntityError::ID = '\0';
+void SILEntityError::anchor() {}
+
STATISTIC(NumDeserializedFunc, "Number of deserialized SIL functions");
static Optional<StringLiteralInst::Encoding>
@@ -340,7 +346,14 @@
// Otherwise, look for a function with this name in the module.
auto iter = FuncTable->find(name);
if (iter != FuncTable->end()) {
- fn = readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true);
+ auto maybeFn = readSILFunctionChecked(*iter, nullptr, name,
+ /*declarationOnly*/ true);
+ if (maybeFn) {
+ fn = maybeFn.get();
+ } else {
+ // Ignore the failure; we'll synthesize a bogus function instead.
+ llvm::consumeError(maybeFn.takeError());
+ }
}
}
@@ -363,7 +376,15 @@
if (iter == FuncTable->end())
return nullptr;
- return readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true);
+ auto maybeFn = readSILFunctionChecked(*iter, nullptr, name,
+ /*declarationOnly*/ true);
+ if (!maybeFn) {
+ // Ignore the failure and just pretend the function doesn't exist
+ llvm::consumeError(maybeFn.takeError());
+ return nullptr;
+ }
+
+ return maybeFn.get();
}
/// Helper function to find a SILGlobalVariable given its name. It first checks
@@ -387,6 +408,19 @@
StringRef name,
bool declarationOnly,
bool errorIfEmptyBody) {
+ llvm::Expected<SILFunction *> deserialized =
+ readSILFunctionChecked(FID, existingFn, name, declarationOnly,
+ errorIfEmptyBody);
+ if (!deserialized) {
+ MF->fatal(deserialized.takeError());
+ }
+ return deserialized.get();
+}
+
+llvm::Expected<SILFunction *>
+SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
+ StringRef name, bool declarationOnly,
+ bool errorIfEmptyBody) {
// We can't deserialize function bodies after IRGen lowering passes have
// happened since other definitions in the module will no longer be in
// canonical SIL form.
@@ -445,7 +479,16 @@
MF->error();
return nullptr;
}
- auto ty = getSILType(MF->getType(funcTyID), SILValueCategory::Object);
+ auto astType = MF->getTypeChecked(funcTyID);
+ if (!astType) {
+ if (!existingFn || errorIfEmptyBody) {
+ return llvm::make_error<SILEntityError>(
+ name, takeErrorInfo(astType.takeError()));
+ }
+ llvm::consumeError(astType.takeError());
+ return existingFn;
+ }
+ auto ty = getSILType(astType.get(), SILValueCategory::Object);
if (!ty.is<SILFunctionType>()) {
DEBUG(llvm::dbgs() << "not a function type for SILFunction\n");
MF->error();
@@ -2433,14 +2476,21 @@
if (iter == FuncTable->end())
return nullptr;
- auto Func = readSILFunction(*iter, InFunc, name, /*declarationOnly*/ false);
- if (Func) {
- DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
- Func->dump());
- assert(InFunc->getName() == Func->getName());
+ auto maybeFunc = readSILFunctionChecked(*iter, InFunc, name,
+ /*declarationOnly*/ false);
+ if (!maybeFunc) {
+ // Ignore the error; treat it as if we didn't have a definition.
+ llvm::consumeError(maybeFunc.takeError());
+ return nullptr;
}
- return Func;
+ if (maybeFunc.get()) {
+ DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
+ maybeFunc.get()->dump());
+ assert(InFunc->getName() == maybeFunc.get()->getName());
+ }
+
+ return maybeFunc.get();
}
/// Check for existence of a function with a given name and required linkage.
@@ -2517,11 +2567,20 @@
if (iter == FuncTable->end())
return nullptr;
- auto Func = readSILFunction(*iter, nullptr, name, declarationOnly);
- if (Func)
+ auto maybeFunc = readSILFunctionChecked(*iter, nullptr, name,
+ declarationOnly);
+
+ if (!maybeFunc) {
+ // Ignore the error; treat it as if we didn't have a definition.
+ llvm::consumeError(maybeFunc.takeError());
+ return nullptr;
+ }
+
+ if (maybeFunc.get()) {
DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
- Func->dump());
- return Func;
+ maybeFunc.get()->dump());
+ }
+ return maybeFunc.get();
}
SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) {
@@ -2617,8 +2676,12 @@
auto DI = FuncTable->find(*KI);
assert(DI != FuncTable->end() && "There should never be a key without data.");
- readSILFunction(*DI, nullptr, *KI, false,
- false/*errorIfEmptyBody*/);
+ auto maybeFunc = readSILFunctionChecked(*DI, nullptr, *KI, false,
+ false/*errorIfEmptyBody*/);
+ if (!maybeFunc) {
+ // Ignore the error; treat it as if we didn't have a definition.
+ llvm::consumeError(maybeFunc.takeError());
+ }
}
}
diff --git a/lib/Serialization/DeserializeSIL.h b/lib/Serialization/DeserializeSIL.h
index 15ea040..b4a4f30 100644
--- a/lib/Serialization/DeserializeSIL.h
+++ b/lib/Serialization/DeserializeSIL.h
@@ -79,6 +79,12 @@
SILFunction *readSILFunction(serialization::DeclID, SILFunction *InFunc,
StringRef Name, bool declarationOnly,
bool errorIfEmptyBody = true);
+ /// Read a SIL function.
+ llvm::Expected<SILFunction *>
+ readSILFunctionChecked(serialization::DeclID, SILFunction *InFunc,
+ StringRef Name, bool declarationOnly,
+ bool errorIfEmptyBody = true);
+
/// Read a SIL basic block within a given SIL function.
SILBasicBlock *readSILBasicBlock(SILFunction *Fn,
SILBasicBlock *Prev,
diff --git a/stdlib/public/runtime/Demangle.cpp b/stdlib/public/runtime/Demangle.cpp
index 4a3f522..21547d7 100644
--- a/stdlib/public/runtime/Demangle.cpp
+++ b/stdlib/public/runtime/Demangle.cpp
@@ -160,8 +160,14 @@
auto typeNode = Dem.createNode(nodeKind);
typeNode->addChild(node, Dem);
- auto identifier = Dem.createNode(Node::Kind::Identifier, name);
- typeNode->addChild(identifier, Dem);
+ auto nameNode = Dem.createNode(Node::Kind::Identifier, name);
+ if (type->isSynthesizedRelatedEntity()) {
+ auto relatedName = Dem.createNode(Node::Kind::RelatedEntityDeclName,
+ type->getSynthesizedDeclRelatedEntityTag());
+ relatedName->addChild(nameNode, Dem);
+ nameNode = relatedName;
+ }
+ typeNode->addChild(nameNode, Dem);
node = typeNode;
// Apply generic arguments if the context is generic.
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index 66be4c1..47c174e 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -1488,7 +1488,20 @@
&& kind <= ContextDescriptorKind::Type_Last) {
auto typeA = cast<TypeContextDescriptor>(a);
auto typeB = cast<TypeContextDescriptor>(b);
- return strcmp(typeA->Name.get(), typeB->Name.get()) == 0;
+ if (strcmp(typeA->Name.get(), typeB->Name.get()) != 0)
+ return false;
+
+ // A synthesized entity has to match the related entity tag too.
+ if (typeA->isSynthesizedRelatedEntity()) {
+ if (!typeB->isSynthesizedRelatedEntity())
+ return false;
+
+ if (typeA->getSynthesizedDeclRelatedEntityTag()
+ != typeB->getSynthesizedDeclRelatedEntityTag())
+ return false;
+ }
+
+ return true;
}
// Otherwise, this runtime doesn't know anything about this context kind.
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index a239b0b..be28b62 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -264,14 +264,31 @@
}
auto nameNode = node->getChild(1);
- if (nameNode->getKind() == Demangle::Node::Kind::PrivateDeclName)
- return false;
-
- if (nameNode->getText() != type->Name.get())
- return false;
- node = node->getChild(0);
- break;
+ // Declarations synthesized by the Clang importer get a small tag
+ // string in addition to their name.
+ if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName){
+ if (nameNode->getText() != type->getSynthesizedDeclRelatedEntityTag())
+ return false;
+
+ nameNode = nameNode->getChild(0);
+ } else if (type->isSynthesizedRelatedEntity()) {
+ return false;
+ }
+
+ // We should only match public or internal declarations with stable
+ // names. The runtime metadata for private declarations would be
+ // anonymized.
+ if (nameNode->getKind() == Demangle::Node::Kind::Identifier) {
+ if (nameNode->getText() != type->Name.get())
+ return false;
+
+ node = node->getChild(0);
+ break;
+ }
+
+ return false;
+
}
// We don't know about this kind of context, or it doesn't have a stable
@@ -1166,7 +1183,7 @@
if (typeInfo == nullptr) {
typeInfo = TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {});
warning(0, "SWIFT RUNTIME BUG: unable to demangle type of field '%*s'. "
- "mangled type name is '%*s'",
+ "mangled type name is '%*s'\n",
(int)name.size(), name.data(),
(int)typeName.size(), typeName.data());
}
@@ -1214,6 +1231,17 @@
return;
}
}
+
+ // If we failed to find the field descriptor metadata for the type, fall
+ // back to returning an empty tuple as a standin.
+ auto typeName = swift_getTypeName(base, /*qualified*/ true);
+ warning(0, "SWIFT RUNTIME BUG: unable to find field metadata for type '%*s'\n",
+ (int)typeName.length, typeName.data);
+ callback("unknown",
+ FieldType()
+ .withType(TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {}))
+ .withIndirect(false)
+ .withWeak(false));
}
#define OVERRIDE_METADATALOOKUP COMPATIBILITY_OVERRIDE
diff --git a/test/ClangImporter/objc_ir.swift b/test/ClangImporter/objc_ir.swift
index ca3a76e..812b8eb 100644
--- a/test/ClangImporter/objc_ir.swift
+++ b/test/ClangImporter/objc_ir.swift
@@ -363,7 +363,5 @@
// CHECK: ![[SWIFT_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$SSo14SwiftNameAliasaD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
-// CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$SSo21SwiftGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
// CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "constr_generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]])
-// CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$SSo27SwiftConstrGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
diff --git a/test/DebugInfo/DumpDeclFromMangledName.swift b/test/DebugInfo/DumpDeclFromMangledName.swift
index 4b8bcef..a81abe3 100644
--- a/test/DebugInfo/DumpDeclFromMangledName.swift
+++ b/test/DebugInfo/DumpDeclFromMangledName.swift
@@ -39,3 +39,56 @@
}
patatino()
+
+class Foo<T> {
+ var x : T
+ init(_ x : T) {
+ self.x = x
+ }
+}
+
+typealias Patatino<T> = Foo<T>
+
+public struct Outer<T> {
+ public struct Inner { }
+ public struct GenericInner<U> { }
+
+ public typealias Foo<U> = Outer<U>.Inner
+
+ public func blah() {
+ let foo: Foo<Int> = Outer<Int>.Inner()
+ }
+}
+
+extension Outer.GenericInner {
+ public typealias Bar = Int
+
+ public func useBar() {
+ let bar: Bar = 7
+ }
+}
+
+protocol P {
+ associatedtype A
+}
+
+protocol Q {
+ associatedtype B: P
+ typealias ProtocolTypeAliasThing = B.A
+}
+
+struct ConformsToP: P {
+ typealias A = Int
+}
+
+struct ConformsToQ: Q {
+ typealias B = ConformsToP
+}
+
+struct Blah {
+ typealias SomeQ = ConformsToQ
+
+ func foo() {
+ let bar: SomeQ.ProtocolTypeAliasThing? = nil
+ }
+}
diff --git a/test/DebugInfo/guard-let.swift b/test/DebugInfo/guard-let.swift
index 2db51a4..ddf4ee3 100644
--- a/test/DebugInfo/guard-let.swift
+++ b/test/DebugInfo/guard-let.swift
@@ -21,9 +21,13 @@
use(val)
}
-// With large type optimizations the string is passed indirectly on i386 so
-// there is no shadow copy happening.
+// With large type optimizations the string is passed indirectly on the
+// following architectures so there is no shadow copy happening. As this
+// tests that we're emitting the DI correctly, we can skip running on them.
// UNSUPPORTED: CPU=i386
+// UNSUPPORTED: CPU=armv7
+// UNSUPPORTED: CPU=armv7s
+// UNSUPPORTED: CPU=armv7k
public func g(_ s : String?)
{
diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt
index a007915..830e783 100644
--- a/test/Demangle/Inputs/manglings.txt
+++ b/test/Demangle/Inputs/manglings.txt
@@ -310,5 +310,4 @@
_$S3BBBBi0602365061_ ---> _$S3BBBBi0602365061_
_$S3BBBBv0602365061_ ---> _$S3BBBBv0602365061_
_T0lxxxmmmTk ---> _T0lxxxmmmTk
-$S4blah8PatatinoaySiGD -> blah.Patatino<Swift.Int>
diff --git a/test/IRGen/enum_resilience_objc.swift b/test/IRGen/enum_resilience_objc.swift
new file mode 100644
index 0000000..1a582d4
--- /dev/null
+++ b/test/IRGen/enum_resilience_objc.swift
@@ -0,0 +1,25 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience %s | %FileCheck %s -DINT=i%target-ptrsize
+// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience -O %s
+
+// REQUIRES: objc_interop
+
+// Because the enum is resilient we cannot pack the tag into the pointer inside of the resilient payload.
+// CHECK: %T15enum_resilience9ContainerC5Multi33_{{.*}}LLO.0 = type <{ [{{(8|4)}} x i8], [1 x i8] }>
+
+import resilient_struct
+
+public class Container {
+ private enum Multi {
+ case none
+ case some(Container)
+ case data(ResilientRef)
+ }
+ private var e: Multi
+ var i: Int
+ init() {
+ e = .none
+ i = 0
+ }
+}
diff --git a/test/Inputs/resilient_struct.swift b/test/Inputs/resilient_struct.swift
index 01982d4..37b52da 100644
--- a/test/Inputs/resilient_struct.swift
+++ b/test/Inputs/resilient_struct.swift
@@ -77,3 +77,17 @@
self.d = d
}
}
+
+public class Referent {}
+
+public struct ResilientWeakRef {
+ public weak var ref: Referent?
+
+ public init (_ r: Referent) {
+ ref = r
+ }
+}
+
+public struct ResilientRef {
+ public var r: Referent
+}
diff --git a/test/Interpreter/enum_resilience.swift b/test/Interpreter/enum_resilience.swift
index 3db9e03..9c68d42 100644
--- a/test/Interpreter/enum_resilience.swift
+++ b/test/Interpreter/enum_resilience.swift
@@ -436,4 +436,28 @@
expectEqual(Base.self, ResilientMultiPayloadGenericEnumFixedSize<Base>.A.getTypeParameter())
}
+public class Container {
+ private enum Multi {
+ case none
+ case some(Container)
+ case other(ResilientRef)
+ }
+ private var m: Multi
+ var i: Int
+ init() {
+ m = .none
+ i = 0
+ switch self.m {
+ case .none:
+ print("success")
+ case .some(_), .other(_):
+ assert(false, "noooo!")
+ }
+ }
+}
+
+ResilientEnumTestSuite.test("ResilientPrivateEnumMember") {
+ _ = Container()
+}
+
runAllTests()
diff --git a/test/Runtime/Inputs/synthesized_decl_uniqueness.swift b/test/Runtime/Inputs/synthesized_decl_uniqueness.swift
new file mode 100644
index 0000000..5157acc
--- /dev/null
+++ b/test/Runtime/Inputs/synthesized_decl_uniqueness.swift
@@ -0,0 +1,9 @@
+import CoreLocation
+
+public func getCLError() -> Any.Type {
+ return CLError.self
+}
+
+public func getCLErrorCode() -> Any.Type {
+ return CLError.Code.self
+}
diff --git a/test/Runtime/demangleToMetadataObjC.swift b/test/Runtime/demangleToMetadataObjC.swift
index 606f111..11ba20d 100644
--- a/test/Runtime/demangleToMetadataObjC.swift
+++ b/test/Runtime/demangleToMetadataObjC.swift
@@ -5,6 +5,7 @@
import StdlibUnittest
import Foundation
import CoreFoundation
+import CoreLocation
let DemangleToMetadataTests = TestSuite("DemangleToMetadataObjC")
@@ -74,5 +75,15 @@
expectNil(_typeByMangledName("4main3CG4CyAA1DCAA1DCG"))
}
+DemangleToMetadataTests.test("synthesized declarations") {
+ expectEqual(CLError.self, _typeByMangledName("SC7CLErrorLeV")!)
+ expectNil(_typeByMangledName("SC7CLErrorV"))
+ expectEqual(CLError.Code.self, _typeByMangledName("So7CLErrorV")!)
+
+ let error = NSError(domain: NSCocoaErrorDomain, code: 0)
+ let reflectionString = String(reflecting: CLError(_nsError: error))
+ expectTrue(reflectionString.hasPrefix("__C_Synthesized.related decl 'e' for CLError(_nsError:"))
+}
+
runAllTests()
diff --git a/test/Runtime/synthesized_decl_uniqueness.swift b/test/Runtime/synthesized_decl_uniqueness.swift
new file mode 100644
index 0000000..e47aea0
--- /dev/null
+++ b/test/Runtime/synthesized_decl_uniqueness.swift
@@ -0,0 +1,21 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift -parse-as-library -force-single-frontend-invocation %S/Inputs/synthesized_decl_uniqueness.swift -emit-object -o %t/A.o -module-name A -emit-module-path %t/A.swiftmodule
+// RUN: %target-build-swift -parse-as-library -force-single-frontend-invocation %S/Inputs/synthesized_decl_uniqueness.swift -emit-object -o %t/B.o -module-name B -emit-module-path %t/B.swiftmodule
+// RUN: %target-build-swift -I %t %s %t/A.o %t/B.o -o %t/a.out
+// RUN: %target-run %t/a.out
+
+// REQUIRES: executable_test
+// REQUIRES: objc_interop
+
+import StdlibUnittest
+import A
+import B
+
+var tests = TestSuite("metadata identity for synthesized types")
+
+tests.test("synthesized type identity across modules") {
+ expectEqual(A.getCLError(), B.getCLError())
+ expectEqual(A.getCLErrorCode(), B.getCLErrorCode())
+}
+
+runAllTests()
diff --git a/test/SIL/Serialization/Recovery/Inputs/bad-modules/Types.h b/test/SIL/Serialization/Recovery/Inputs/bad-modules/Types.h
new file mode 100644
index 0000000..a735ae9
--- /dev/null
+++ b/test/SIL/Serialization/Recovery/Inputs/bad-modules/Types.h
@@ -0,0 +1,3 @@
+// struct SoonToBeMissing {
+// int value;
+// };
diff --git a/test/SIL/Serialization/Recovery/Inputs/bad-modules/module.modulemap b/test/SIL/Serialization/Recovery/Inputs/bad-modules/module.modulemap
new file mode 100644
index 0000000..b811768
--- /dev/null
+++ b/test/SIL/Serialization/Recovery/Inputs/bad-modules/module.modulemap
@@ -0,0 +1 @@
+module Types { header "Types.h" }
diff --git a/test/SIL/Serialization/Recovery/Inputs/good-modules/Types.h b/test/SIL/Serialization/Recovery/Inputs/good-modules/Types.h
new file mode 100644
index 0000000..4b49807
--- /dev/null
+++ b/test/SIL/Serialization/Recovery/Inputs/good-modules/Types.h
@@ -0,0 +1,3 @@
+struct SoonToBeMissing {
+ int value;
+};
diff --git a/test/SIL/Serialization/Recovery/Inputs/good-modules/module.modulemap b/test/SIL/Serialization/Recovery/Inputs/good-modules/module.modulemap
new file mode 100644
index 0000000..b811768
--- /dev/null
+++ b/test/SIL/Serialization/Recovery/Inputs/good-modules/module.modulemap
@@ -0,0 +1 @@
+module Types { header "Types.h" }
diff --git a/test/SIL/Serialization/Recovery/function.sil b/test/SIL/Serialization/Recovery/function.sil
new file mode 100644
index 0000000..311c1b9
--- /dev/null
+++ b/test/SIL/Serialization/Recovery/function.sil
@@ -0,0 +1,26 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -parse-sil %s -emit-sib -o %t/Library.sib -module-name Library -I %S/Inputs/good-modules -parse-stdlib
+// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/good-modules | %FileCheck %s
+// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/bad-modules | %FileCheck -check-prefix=CHECK-RECOVERY %s
+// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/bad-modules | %FileCheck -check-prefix=CHECK-RECOVERY-NEGATIVE %s
+
+// CHECK-LABEL: sil_stage raw
+// CHECK-RECOVERY-LABEL: sil_stage raw
+
+sil_stage raw
+import Types
+
+// CHECK-LABEL: sil @missingParam : $@convention(thin) (SoonToBeMissing) -> () {
+// CHECK-RECOVERY-NEGATIVE-NOT: sil @missingParam
+sil @missingParam : $@convention(thin) (SoonToBeMissing) -> () {
+entry(%arg: $SoonToBeMissing):
+ %9999 = tuple()
+ return %9999 : $()
+}
+
+// CHECK-LABEL: sil @missingResult : $@convention(thin) () -> SoonToBeMissing {
+// CHECK-RECOVERY-NEGATIVE-NOT: sil @missingResult
+sil @missingResult : $@convention(thin) () -> (SoonToBeMissing) {
+entry:
+ unreachable
+}
diff --git a/validation-test/Serialization/Inputs/custom-modules/module.modulemap b/validation-test/Serialization/Inputs/custom-modules/module.modulemap
new file mode 100644
index 0000000..b8ef16f
--- /dev/null
+++ b/validation-test/Serialization/Inputs/custom-modules/module.modulemap
@@ -0,0 +1 @@
+module rdar40899824Helper { header "rdar40899824Helper.h" }
diff --git a/validation-test/Serialization/Inputs/custom-modules/rdar40899824Helper.h b/validation-test/Serialization/Inputs/custom-modules/rdar40899824Helper.h
new file mode 100644
index 0000000..390ee41
--- /dev/null
+++ b/validation-test/Serialization/Inputs/custom-modules/rdar40899824Helper.h
@@ -0,0 +1,13 @@
+#ifndef BAD
+typedef struct {
+ int value;
+} SoonToBeMissing;
+#endif
+
+@interface Impl
+#ifndef BAD
+- (void)use:(SoonToBeMissing)value;
+#endif
+
+- (void)unrelated;
+@end
diff --git a/validation-test/Serialization/rdar40899824.swift b/validation-test/Serialization/rdar40899824.swift
new file mode 100644
index 0000000..1e793d5
--- /dev/null
+++ b/validation-test/Serialization/rdar40899824.swift
@@ -0,0 +1,38 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift %s -emit-module -o %t/Library.swiftmodule -I %S/Inputs/custom-modules -DLIBRARY -Xfrontend -enable-objc-interop -Xfrontend -disable-objc-attr-requires-foundation-module
+// RUN: %target-swift-frontend %s -I %t -I %S/Inputs/custom-modules -enable-objc-interop -emit-ir > /dev/null
+
+// RUN: %target-swift-frontend %s -I %t -I %S/Inputs/custom-modules -enable-objc-interop -emit-ir -Xcc -DBAD > /dev/null
+// RUN: %target-swift-frontend %s -I %t -I %S/Inputs/custom-modules -enable-objc-interop -emit-ir -Xcc -DBAD -O > /dev/null
+
+#if LIBRARY
+
+import rdar40899824Helper
+
+public protocol Proto: class {
+ func use(_: SoonToBeMissing)
+ func unrelated()
+}
+
+extension Impl: Proto {}
+
+#else // LIBRARY
+
+import Library
+import rdar40899824Helper
+
+func testGeneric<T: Proto>(_ obj: T) {
+ obj.unrelated()
+}
+
+func testExistential(_ obj: Proto) {
+ obj.unrelated()
+}
+
+func test(_ proto: Proto, _ impl: Impl) {
+ impl.unrelated()
+ testGeneric(impl)
+ testExistential(impl)
+}
+
+#endif // LIBRARY