Skip to content

[6.2] Fix deserialization of lifetime dependencies on ast function types #81917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions include/swift/AST/LifetimeDependence.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,25 @@ class LifetimeDependenceInfo {
|| !conditionallyAddressableParamIndices
|| conditionallyAddressableParamIndices->isDisjointWith(
addressableParamIndices)));

if (CONDITIONAL_ASSERT_enabled()) {
// Ensure inherit/scope/addressable param indices are of the same length
// or 0.
unsigned paramIndicesLength = 0;
if (inheritLifetimeParamIndices) {
paramIndicesLength = inheritLifetimeParamIndices->getCapacity();
}
if (scopeLifetimeParamIndices) {
assert(paramIndicesLength == 0 ||
paramIndicesLength == scopeLifetimeParamIndices->getCapacity());
paramIndicesLength = scopeLifetimeParamIndices->getCapacity();
}
if (addressableParamIndices) {
assert(paramIndicesLength == 0 ||
paramIndicesLength == addressableParamIndices->getCapacity());
paramIndicesLength = addressableParamIndices->getCapacity();
}
}
}

operator bool() const { return !empty(); }
Expand All @@ -254,6 +273,19 @@ class LifetimeDependenceInfo {
return addressableParamIndicesAndImmortal.getPointer() != nullptr;
}

unsigned getParamIndicesLength() const {
if (hasInheritLifetimeParamIndices()) {
return getInheritIndices()->getCapacity();
}
if (hasScopeLifetimeParamIndices()) {
return getScopeIndices()->getCapacity();
}
if (hasAddressableParamIndices()) {
return getAddressableIndices()->getCapacity();
}
return 0;
}

IndexSubset *getInheritIndices() const { return inheritLifetimeParamIndices; }

IndexSubset *getScopeIndices() const { return scopeLifetimeParamIndices; }
Expand Down
30 changes: 14 additions & 16 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3846,7 +3846,7 @@ class DeclDeserializer {
ctor->setParameters(bodyParams);

SmallVector<LifetimeDependenceInfo, 1> lifetimeDependencies;
while (auto info = MF.maybeReadLifetimeDependence(bodyParams->size() + 1)) {
while (auto info = MF.maybeReadLifetimeDependence()) {
assert(info.has_value());
lifetimeDependencies.push_back(*info);
}
Expand Down Expand Up @@ -4448,11 +4448,9 @@ class DeclDeserializer {
ParameterList *paramList;
SET_OR_RETURN_ERROR(paramList, MF.readParameterList());
fn->setParameters(paramList);
auto numParams =
fn->hasImplicitSelfDecl() ? paramList->size() + 1 : paramList->size();

SmallVector<LifetimeDependenceInfo, 1> lifetimeDependencies;
while (auto info = MF.maybeReadLifetimeDependence(numParams)) {
while (auto info = MF.maybeReadLifetimeDependence()) {
assert(info.has_value());
lifetimeDependencies.push_back(*info);
}
Expand Down Expand Up @@ -7411,8 +7409,7 @@ detail::function_deserializer::deserialize(ModuleFile &MF,

SmallVector<LifetimeDependenceInfo, 1> lifetimeDependencies;

while (auto lifetimeDependence =
MF.maybeReadLifetimeDependence(params.size())) {
while (auto lifetimeDependence = MF.maybeReadLifetimeDependence()) {
lifetimeDependencies.push_back(*lifetimeDependence);
}
if (!lifetimeDependencies.empty()) {
Expand Down Expand Up @@ -8062,7 +8059,7 @@ Expected<Type> DESERIALIZE_TYPE(SIL_FUNCTION_TYPE)(

SmallVector<LifetimeDependenceInfo, 1> lifetimeDependencies;

while (auto lifetimeDependence = MF.maybeReadLifetimeDependence(numParams)) {
while (auto lifetimeDependence = MF.maybeReadLifetimeDependence()) {
lifetimeDependencies.push_back(*lifetimeDependence);
}

Expand Down Expand Up @@ -9348,7 +9345,7 @@ bool ModuleFile::maybeReadLifetimeDependenceRecord(
}

std::optional<LifetimeDependenceInfo>
ModuleFile::maybeReadLifetimeDependence(unsigned numParams) {
ModuleFile::maybeReadLifetimeDependence() {
using namespace decls_block;

SmallVector<uint64_t, 8> scratch;
Expand All @@ -9357,28 +9354,29 @@ ModuleFile::maybeReadLifetimeDependence(unsigned numParams) {
}

unsigned targetIndex;
unsigned paramIndicesLength;
bool isImmortal;
bool hasInheritLifetimeParamIndices;
bool hasScopeLifetimeParamIndices;
bool hasAddressableParamIndices;
ArrayRef<uint64_t> lifetimeDependenceData;
LifetimeDependenceLayout::readRecord(
scratch, targetIndex, isImmortal, hasInheritLifetimeParamIndices,
hasScopeLifetimeParamIndices, hasAddressableParamIndices,
lifetimeDependenceData);
scratch, targetIndex, paramIndicesLength, isImmortal,
hasInheritLifetimeParamIndices, hasScopeLifetimeParamIndices,
hasAddressableParamIndices, lifetimeDependenceData);

SmallBitVector inheritLifetimeParamIndices(numParams, false);
SmallBitVector scopeLifetimeParamIndices(numParams, false);
SmallBitVector addressableParamIndices(numParams, false);
SmallBitVector inheritLifetimeParamIndices(paramIndicesLength, false);
SmallBitVector scopeLifetimeParamIndices(paramIndicesLength, false);
SmallBitVector addressableParamIndices(paramIndicesLength, false);

unsigned startIndex = 0;
auto pushData = [&](SmallBitVector &bits) {
for (unsigned i = 0; i < numParams; i++) {
for (unsigned i = 0; i < paramIndicesLength; i++) {
if (lifetimeDependenceData[startIndex + i]) {
bits.set(i);
}
}
startIndex += numParams;
startIndex += paramIndicesLength;
};

if (hasInheritLifetimeParamIndices) {
Expand Down
3 changes: 1 addition & 2 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1105,8 +1105,7 @@ class ModuleFile
bool maybeReadLifetimeDependenceRecord(SmallVectorImpl<uint64_t> &scratch);

// Reads lifetime dependence info from type if present.
std::optional<LifetimeDependenceInfo>
maybeReadLifetimeDependence(unsigned numParams);
std::optional<LifetimeDependenceInfo> maybeReadLifetimeDependence();

// Reads lifetime dependence specifier from decl if present
bool maybeReadLifetimeEntry(SmallVectorImpl<LifetimeEntry> &specifierList,
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 941; // add modifier to @_inheritActorContext
const uint16_t SWIFTMODULE_VERSION_MINOR = 942; // update LifetimeDependenceLayout

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -2317,6 +2317,7 @@ namespace decls_block {
using LifetimeDependenceLayout =
BCRecordLayout<LIFETIME_DEPENDENCE,
BCVBR<4>, // targetIndex
BCVBR<4>, // paramIndicesLength
BCFixed<1>, // isImmortal
BCFixed<1>, // hasInheritLifetimeParamIndices
BCFixed<1>, // hasScopeLifetimeParamIndices
Expand Down
6 changes: 3 additions & 3 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2738,10 +2738,10 @@ void Serializer::writeLifetimeDependencies(

auto abbrCode = DeclTypeAbbrCodes[LifetimeDependenceLayout::Code];
LifetimeDependenceLayout::emitRecord(
Out, ScratchRecord, abbrCode, info.getTargetIndex(), info.isImmortal(),
Out, ScratchRecord, abbrCode, info.getTargetIndex(),
info.getParamIndicesLength(), info.isImmortal(),
info.hasInheritLifetimeParamIndices(),
info.hasScopeLifetimeParamIndices(),
info.hasAddressableParamIndices(),
info.hasScopeLifetimeParamIndices(), info.hasAddressableParamIndices(),
paramIndices);
paramIndices.clear();
}
Expand Down
18 changes: 18 additions & 0 deletions validation-test/Serialization/rdar151768216.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module %s -o %t -enable-experimental-feature LifetimeDependence

// RUN: %target-swift-frontend -emit-sil %t/rdar151768216.swiftmodule \
// RUN: -enable-experimental-feature LifetimeDependence

// REQUIRES: swift_feature_LifetimeDependence

// Ensure no crash
extension Result {
@inlinable
func castError(i: Int, j: Int, k: Int) -> Result<Success, Failure> {
return self.mapError { error in
return error
}
}
}