Skip to content

Commit 23557b8

Browse files
authored
Merge pull request #41111 from jckarter/infinite-type-lowering-bailout
SIL: Detect and bail out on infinite aggregates.
2 parents bb2dbfc + fe19399 commit 23557b8

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ enum IsTypeExpansionSensitive_t : bool {
153153
IsTypeExpansionSensitive = true
154154
};
155155

156+
/// Is the type infinitely defined in terms of itself? (Such types can never
157+
/// be concretely instantiated, but may still arise from generic specialization.)
158+
enum IsInfiniteType_t : bool {
159+
IsNotInfiniteType = false,
160+
IsInfiniteType = true,
161+
};
162+
156163
/// Extended type information used by SIL.
157164
class TypeLowering {
158165
public:
@@ -164,6 +171,7 @@ class TypeLowering {
164171
AddressOnlyFlag = 1 << 2,
165172
ResilientFlag = 1 << 3,
166173
TypeExpansionSensitiveFlag = 1 << 4,
174+
InfiniteFlag = 1 << 5,
167175
};
168176

169177
uint8_t Flags;
@@ -224,6 +232,9 @@ class TypeLowering {
224232
return IsTypeExpansionSensitive_t(
225233
(Flags & TypeExpansionSensitiveFlag) != 0);
226234
}
235+
IsInfiniteType_t isInfinite() const {
236+
return IsInfiniteType_t((Flags & InfiniteFlag) != 0);
237+
}
227238

228239
void setNonTrivial() { Flags |= NonTrivialFlag; }
229240
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
@@ -233,6 +244,7 @@ class TypeLowering {
233244
Flags = (Flags & ~TypeExpansionSensitiveFlag) |
234245
(isTypeExpansionSensitive ? TypeExpansionSensitiveFlag : 0);
235246
}
247+
void setInfinite() { Flags |= InfiniteFlag; }
236248
};
237249

238250
private:
@@ -720,6 +732,9 @@ class TypeConverter {
720732

721733
CanGenericSignature CurGenericSignature;
722734

735+
/// Stack of types currently being lowered as part of an aggregate.
736+
llvm::SetVector<CanType> AggregateFieldsBeingLowered;
737+
723738
/// Mapping for types independent on contextual generic parameters.
724739
llvm::DenseMap<CachingTypeKey, const TypeLowering *> LoweredTypes;
725740

@@ -767,6 +782,31 @@ class TypeConverter {
767782
CanGenericSignature getCurGenericSignature() const {
768783
return CurGenericSignature;
769784
}
785+
786+
// RAII type used when lowering nominal aggregate types (structs and enums)
787+
// to catch self-recursion. Although Sema tries to catch direct circularity
788+
// in value type definitions, it can't catch circularity that arises from
789+
// generic substitutions. SIL may however be exposed to these circularities
790+
// at any point by substituting bound generic types either during SILGen or
791+
// after passes that perform generic specialization.
792+
class LowerAggregateTypeRAII {
793+
TypeConverter &TC;
794+
795+
public:
796+
// True if the aggregate about to be lowered is already being lowered,
797+
// indicating a circularity.
798+
const bool IsInfinite;
799+
800+
LowerAggregateTypeRAII(TypeConverter &TC, CanType aggregate)
801+
: TC(TC), IsInfinite(!TC.AggregateFieldsBeingLowered.insert(aggregate))
802+
{}
803+
804+
~LowerAggregateTypeRAII() {
805+
if (!IsInfinite) {
806+
TC.AggregateFieldsBeingLowered.pop_back();
807+
}
808+
}
809+
};
770810

771811
class GenericContextRAII {
772812
TypeConverter &TC;

lib/IRGen/GenStruct.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1285,7 +1285,13 @@ const TypeInfo *TypeConverter::convertStructType(TypeBase *key, CanType type,
12851285
// All resilient structs have the same opaque lowering, since they are
12861286
// indistinguishable as values --- except that we have to track
12871287
// ABI-accessibility.
1288-
if (IGM.isResilient(D, ResilienceExpansion::Maximal)) {
1288+
//
1289+
// Treat infinitely-sized types as resilient as well, since they can never
1290+
// be concretized.
1291+
if (IGM.isResilient(D, ResilienceExpansion::Maximal)
1292+
|| IGM.getSILTypes().getTypeLowering(SILType::getPrimitiveAddressType(type),
1293+
TypeExpansionContext::minimal())
1294+
.getRecursiveProperties().isInfinite()) {
12891295
auto structAccessible =
12901296
IsABIAccessible_t(IGM.getSILModule().isTypeMetadataAccessible(type));
12911297
return &getResilientStructTypeInfo(structAccessible);

lib/SIL/IR/SILType.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ bool SILType::isTrivial(const SILFunction &F) const {
109109
}
110110

111111
bool SILType::isEmpty(const SILFunction &F) const {
112+
// Infinite types are never empty.
113+
if (F.getTypeLowering(*this).getRecursiveProperties().isInfinite()) {
114+
return false;
115+
}
116+
112117
if (auto tupleTy = getAs<TupleType>()) {
113118
// A tuple is empty if it either has no elements or if all elements are
114119
// empty.

lib/SIL/IR/TypeLowering.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,15 @@ namespace {
16911691
auto silType = SILType::getPrimitiveObjectType(type);
16921692
return new (TC) OpaqueValueTypeLowering(silType, properties, Expansion);
16931693
}
1694+
1695+
TypeLowering *handleInfinite(CanType type,
1696+
RecursiveProperties properties) {
1697+
// Infinite types cannot actually be instantiated, so treat them as
1698+
// opaque for code generation purposes.
1699+
properties.setAddressOnly();
1700+
properties.setInfinite();
1701+
return handleAddressOnly(type, properties);
1702+
}
16941703

16951704
#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
16961705
TypeLowering * \
@@ -1784,6 +1793,12 @@ namespace {
17841793

17851794
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
17861795

1796+
// Bail out if the struct layout relies on itself.
1797+
TypeConverter::LowerAggregateTypeRAII loweringStruct(TC, structType);
1798+
if (loweringStruct.IsInfinite) {
1799+
return handleInfinite(structType, properties);
1800+
}
1801+
17871802
if (handleResilience(structType, D, properties))
17881803
return handleAddressOnly(structType, properties);
17891804

@@ -1826,6 +1841,12 @@ namespace {
18261841

18271842
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
18281843

1844+
// Bail out if the enum layout relies on itself.
1845+
TypeConverter::LowerAggregateTypeRAII loweringEnum(TC, enumType);
1846+
if (loweringEnum.IsInfinite) {
1847+
return handleInfinite(enumType, properties);
1848+
}
1849+
18291850
if (handleResilience(enumType, D, properties))
18301851
return handleAddressOnly(enumType, properties);
18311852

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-swift-emit-sil -verify %s
2+
3+
protocol P {
4+
associatedtype A
5+
}
6+
7+
struct S<T: P> {
8+
var s: T.A
9+
}
10+
11+
struct SR: P {
12+
typealias A = S<SR>
13+
}
14+
15+
struct SU<T: P> {
16+
var x: S<T>
17+
}
18+
19+
func foo(x: SU<SR>) -> SU<SR> { return x }
20+
func bar(x: S<SR>) -> S<SR> { return x }
21+
func bas(x: S<SR>) -> S<SR> { return x.s }
22+
23+
enum E<T: P> {
24+
case recursive(T.A)
25+
case blah
26+
}
27+
28+
struct ER: P {
29+
typealias A = E<ER>
30+
}
31+
32+
enum EU<T: P> {
33+
case x(E<T>)
34+
}
35+
36+
func zim(x: EU<ER>) -> EU<ER> { return x }
37+
func zang(x: E<ER>) -> E<ER> { return x }

0 commit comments

Comments
 (0)