Skip to content

Commit 59d1df7

Browse files
committed
[Serialization] Wait after the decl to deserialize custom attrs
With type-wrappers a custom attribute may reference a type and lead to a cycle in deserialization if the target type references the type-wrapper. To avoid this scenario, move deserializing the custom decls from before to after the decl they are attached to. rdar://103425758
1 parent b206c76 commit 59d1df7

File tree

2 files changed

+127
-34
lines changed

2 files changed

+127
-34
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 82 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2740,6 +2740,7 @@ class DeclDeserializer {
27402740

27412741
DeclAttribute *DAttrs = nullptr;
27422742
DeclAttribute **AttrsNext = &DAttrs;
2743+
SmallVector<serialization::BitOffset> customAttrOffsets;
27432744

27442745
Identifier privateDiscriminator;
27452746
unsigned localDiscriminator = 0;
@@ -2828,8 +2829,15 @@ class DeclDeserializer {
28282829

28292830
/// Deserializes records common to all decls from \c MF.DeclTypesCursor (ie.
28302831
/// the invalid flag, attributes, and discriminators)
2832+
///
2833+
/// Reads all attributes except for custom attributes that are skipped and
2834+
/// their offsets added to \c customAttrOffsets.
28312835
llvm::Error deserializeDeclCommon();
28322836

2837+
/// Deserializes the custom attributes from \c MF.DeclTypesCursor, using the
2838+
/// offsets in \c customAttrOffsets.
2839+
llvm::Error deserializeCustomAttrs();
2840+
28332841
Expected<Decl *> getDeclCheckedImpl(
28342842
llvm::function_ref<bool(DeclAttributes)> matchAttributes = nullptr);
28352843

@@ -4776,13 +4784,67 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
47764784
return attr;
47774785
}
47784786

4787+
llvm::Error DeclDeserializer::deserializeCustomAttrs() {
4788+
using namespace decls_block;
4789+
4790+
SmallVector<uint64_t, 64> scratch;
4791+
StringRef blobData;
4792+
for (auto attrOffset : customAttrOffsets) {
4793+
if (auto error =
4794+
MF.diagnoseFatalIfNotSuccess(MF.DeclTypeCursor.JumpToBit(attrOffset)))
4795+
return error;
4796+
4797+
llvm::BitstreamEntry entry =
4798+
MF.fatalIfUnexpected(MF.DeclTypeCursor.advance());
4799+
if (entry.Kind != llvm::BitstreamEntry::Record) {
4800+
// We don't know how to serialize decls represented by sub-blocks.
4801+
return MF.diagnoseFatal();
4802+
}
4803+
4804+
unsigned recordID = MF.fatalIfUnexpected(
4805+
MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
4806+
assert(recordID == decls_block::Custom_DECL_ATTR &&
4807+
"expecting only custom attributes in deserializeCustomAttrs");
4808+
4809+
bool isImplicit;
4810+
bool isArgUnsafe;
4811+
TypeID typeID;
4812+
serialization::decls_block::CustomDeclAttrLayout::readRecord(
4813+
scratch, isImplicit, typeID, isArgUnsafe);
4814+
4815+
Expected<Type> deserialized = MF.getTypeChecked(typeID);
4816+
if (!deserialized) {
4817+
if (deserialized.errorIsA<XRefNonLoadedModuleError>() ||
4818+
MF.allowCompilerErrors()) {
4819+
// A custom attribute defined behind an implementation-only import
4820+
// is safe to drop when it can't be deserialized.
4821+
// rdar://problem/56599179. When allowing errors we're doing a best
4822+
// effort to create a module, so ignore in that case as well.
4823+
consumeError(deserialized.takeError());
4824+
} else
4825+
return deserialized.takeError();
4826+
} else if (!deserialized.get() && MF.allowCompilerErrors()) {
4827+
// Serialized an invalid attribute, just skip it when allowing errors
4828+
} else {
4829+
auto *TE = TypeExpr::createImplicit(deserialized.get(), ctx);
4830+
auto custom = CustomAttr::create(ctx, SourceLoc(), TE, isImplicit);
4831+
custom->setArgIsUnsafe(isArgUnsafe);
4832+
AddAttribute(custom);
4833+
}
4834+
scratch.clear();
4835+
}
4836+
4837+
return llvm::Error::success();
4838+
}
4839+
47794840
llvm::Error DeclDeserializer::deserializeDeclCommon() {
47804841
using namespace decls_block;
47814842

47824843
SmallVector<uint64_t, 64> scratch;
47834844
StringRef blobData;
47844845
while (true) {
47854846
BCOffsetRAII restoreOffset(MF.DeclTypeCursor);
4847+
serialization::BitOffset attrOffset = MF.DeclTypeCursor.GetCurrentBitNo();
47864848
llvm::BitstreamEntry entry =
47874849
MF.fatalIfUnexpected(MF.DeclTypeCursor.advance());
47884850
if (entry.Kind != llvm::BitstreamEntry::Record) {
@@ -5074,33 +5136,10 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
50745136
}
50755137

50765138
case decls_block::Custom_DECL_ATTR: {
5077-
bool isImplicit;
5078-
bool isArgUnsafe;
5079-
TypeID typeID;
5080-
serialization::decls_block::CustomDeclAttrLayout::readRecord(
5081-
scratch, isImplicit, typeID, isArgUnsafe);
5082-
5083-
Expected<Type> deserialized = MF.getTypeChecked(typeID);
5084-
if (!deserialized) {
5085-
if (deserialized.errorIsA<XRefNonLoadedModuleError>() ||
5086-
MF.allowCompilerErrors()) {
5087-
// A custom attribute defined behind an implementation-only import
5088-
// is safe to drop when it can't be deserialized.
5089-
// rdar://problem/56599179. When allowing errors we're doing a best
5090-
// effort to create a module, so ignore in that case as well.
5091-
consumeError(deserialized.takeError());
5092-
skipAttr = true;
5093-
} else
5094-
return deserialized.takeError();
5095-
} else if (!deserialized.get() && MF.allowCompilerErrors()) {
5096-
// Serialized an invalid attribute, just skip it when allowing errors
5097-
skipAttr = true;
5098-
} else {
5099-
auto *TE = TypeExpr::createImplicit(deserialized.get(), ctx);
5100-
auto custom = CustomAttr::create(ctx, SourceLoc(), TE, isImplicit);
5101-
custom->setArgIsUnsafe(isArgUnsafe);
5102-
Attr = custom;
5103-
}
5139+
// Deserialize the custom attributes after the attached decl,
5140+
// skip for now.
5141+
customAttrOffsets.push_back(attrOffset);
5142+
skipAttr = true;
51045143
break;
51055144
}
51065145

@@ -5389,16 +5428,19 @@ DeclDeserializer::getDeclCheckedImpl(
53895428
switch (recordID) {
53905429
#define CASE(RECORD_NAME) \
53915430
case decls_block::RECORD_NAME##Layout::Code: {\
5392-
auto decl = deserialize##RECORD_NAME(scratch, blobData); \
5393-
if (decl) { \
5431+
auto declOrError = deserialize##RECORD_NAME(scratch, blobData); \
5432+
if (declOrError) { \
53945433
/* \
53955434
// Set original declaration and parameter indices in `@differentiable` \
53965435
// attributes. \
53975436
*/ \
53985437
setOriginalDeclarationAndParameterIndicesInDifferentiableAttributes(\
5399-
decl.get(), DAttrs, diffAttrParamIndicesMap); \
5438+
declOrError.get(), DAttrs, diffAttrParamIndicesMap); \
54005439
} \
5401-
return decl; \
5440+
if (!declOrError) \
5441+
return declOrError; \
5442+
declOrOffset = declOrError.get(); \
5443+
break; \
54025444
}
54035445

54045446
CASE(TypeAlias)
@@ -5432,15 +5474,21 @@ DeclDeserializer::getDeclCheckedImpl(
54325474
uint32_t pathLen;
54335475
decls_block::XRefLayout::readRecord(scratch, baseModuleID, pathLen);
54345476
auto resolved = MF.resolveCrossReference(baseModuleID, pathLen);
5435-
if (resolved)
5436-
declOrOffset = resolved.get();
5437-
return resolved;
5477+
if (!resolved)
5478+
return resolved;
5479+
declOrOffset = resolved.get();
5480+
break;
54385481
}
54395482

54405483
default:
54415484
// We don't know how to deserialize this kind of decl.
54425485
MF.fatal(llvm::make_error<InvalidRecordKindError>(recordID));
54435486
}
5487+
5488+
auto attrError = deserializeCustomAttrs();
5489+
if (attrError)
5490+
return std::move(attrError);
5491+
return declOrOffset;
54445492
}
54455493

54465494
/// Translate from the Serialization function type repr enum values to the AST
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/src)
3+
// RUN: %empty-directory(%t/sdk)
4+
// RUN: split-file %s %t/src
5+
6+
// REQUIRES: asserts
7+
8+
// RUN: %target-swift-frontend -emit-module %t/src/PublicModule.swift \
9+
// RUN: -module-name PublicModule -swift-version 5 \
10+
// RUN: -emit-module-path %t/sdk/PublicModule.swiftmodule \
11+
// RUN: -enable-experimental-feature TypeWrappers
12+
13+
// RUN: %target-swift-frontend -typecheck %t/src/Client.swift \
14+
// RUN: -enable-experimental-feature TypeWrappers \
15+
// RUN: -module-name Client -I %t/sdk
16+
17+
//--- PublicModule.swift
18+
@typeWrapper
19+
public struct Wrapper<W: Wrapped, S> {
20+
public init(for: W.Type, storage: S) {}
21+
22+
public subscript<V>(propertyKeyPath _: KeyPath<W, V>, storageKeyPath path: KeyPath<S, V>) -> V {
23+
get { fatalError() }
24+
}
25+
26+
public subscript<V>(propertyKeyPath _: KeyPath<W, V>, storageKeyPath path: WritableKeyPath<S, V>) -> V {
27+
get { fatalError() }
28+
set { }
29+
}
30+
}
31+
32+
@Wrapper
33+
public protocol Wrapped {
34+
init(storageWrapper: Wrapper<Self, $Storage>)
35+
}
36+
37+
//--- Client.swift
38+
import PublicModule
39+
40+
struct Test : Wrapped {
41+
var x: Int = 42
42+
}
43+
44+
let test = Test()
45+
_ = test.$storage

0 commit comments

Comments
 (0)