Skip to content

Commit 298f2df

Browse files
authored
Merge pull request #67385 from rjmccall/diagnose-impossible-variadics-5.9
[5.9] Diagnose attempts to reabstract variadic function types in unimplementable ways
2 parents 24d21f9 + cd5d671 commit 298f2df

17 files changed

+178
-27
lines changed

include/swift/AST/Attr.def.gyb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ TYPE_ATTR(objc_metatype)
8686
TYPE_ATTR(opened)
8787
TYPE_ATTR(pack_element)
8888
TYPE_ATTR(pseudogeneric)
89+
TYPE_ATTR(unimplementable)
8990
TYPE_ATTR(yields)
9091
TYPE_ATTR(yield_once)
9192
TYPE_ATTR(yield_many)

include/swift/AST/DiagnosticsSIL.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ ERROR(c_function_pointer_from_function_with_context,none,
115115
ERROR(objc_selector_malformed,none,"the type ObjectiveC.Selector is malformed",
116116
())
117117

118+
ERROR(unsupported_variadic_function_abstraction,none,
119+
"cannot fully abstract a value of variadic function type %0 because "
120+
"different contexts will not be able to reliably agree on a calling "
121+
"convention; try wrapping it in a struct",
122+
(Type))
123+
118124
// Capture before declaration diagnostics.
119125
ERROR(capture_before_declaration,none,
120126
"closure captures %0 before it is declared", (Identifier))

include/swift/AST/ExtInfo.h

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,10 @@ class SILExtInfoBuilder {
651651
// If bits are added or removed, then TypeBase::SILFunctionTypeBits
652652
// and NumMaskBits must be updated, and they must match.
653653

654-
// |representation|pseudogeneric| noescape | concurrent | async |differentiability|
655-
// | 0 .. 3 | 4 | 5 | 6 | 7 | 8 .. 10 |
654+
// |representation|pseudogeneric| noescape | concurrent | async
655+
// | 0 .. 3 | 4 | 5 | 6 | 7
656+
// |differentiability|unimplementable|
657+
// | 8 .. 10 | 11 |
656658
//
657659
enum : unsigned {
658660
RepresentationMask = 0xF << 0,
@@ -662,7 +664,8 @@ class SILExtInfoBuilder {
662664
AsyncMask = 1 << 7,
663665
DifferentiabilityMaskOffset = 8,
664666
DifferentiabilityMask = 0x7 << DifferentiabilityMaskOffset,
665-
NumMaskBits = 11
667+
UnimplementableMask = 1 << 11,
668+
NumMaskBits = 12
666669
};
667670

668671
unsigned bits; // Naturally sized for speed.
@@ -677,12 +680,13 @@ class SILExtInfoBuilder {
677680

678681
static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
679682
bool isNoEscape, bool isSendable,
680-
bool isAsync,
683+
bool isAsync, bool isUnimplementable,
681684
DifferentiabilityKind diffKind) {
682685
return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) |
683686
(isNoEscape ? NoEscapeMask : 0) |
684687
(isSendable ? SendableMask : 0) |
685688
(isAsync ? AsyncMask : 0) |
689+
(isUnimplementable ? UnimplementableMask : 0) |
686690
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
687691
DifferentiabilityMask);
688692
}
@@ -692,22 +696,23 @@ class SILExtInfoBuilder {
692696
/// non-pseudogeneric, non-differentiable.
693697
SILExtInfoBuilder()
694698
: SILExtInfoBuilder(makeBits(SILFunctionTypeRepresentation::Thick, false,
695-
false, false, false,
699+
false, false, false, false,
696700
DifferentiabilityKind::NonDifferentiable),
697701
ClangTypeInfo(nullptr)) {}
698702

699703
SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape,
700-
bool isSendable, bool isAsync,
704+
bool isSendable, bool isAsync, bool isUnimplementable,
701705
DifferentiabilityKind diffKind, const clang::Type *type)
702706
: SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape,
703-
isSendable, isAsync, diffKind),
707+
isSendable, isAsync, isUnimplementable,
708+
diffKind),
704709
ClangTypeInfo(type)) {}
705710

706711
// Constructor for polymorphic type.
707712
SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric)
708713
: SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric,
709714
info.isNoEscape(), info.isSendable(),
710-
info.isAsync(),
715+
info.isAsync(), /*unimplementable*/ false,
711716
info.getDifferentiabilityKind()),
712717
info.getClangTypeInfo()) {}
713718

@@ -746,6 +751,10 @@ class SILExtInfoBuilder {
746751
DifferentiabilityKind::NonDifferentiable;
747752
}
748753

754+
constexpr bool isUnimplementable() const {
755+
return bits & UnimplementableMask;
756+
}
757+
749758
/// Get the underlying ClangTypeInfo value.
750759
ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }
751760

@@ -816,6 +825,12 @@ class SILExtInfoBuilder {
816825
clangTypeInfo);
817826
}
818827
[[nodiscard]]
828+
SILExtInfoBuilder withUnimplementable(bool isUnimplementable = true) const {
829+
return SILExtInfoBuilder(isUnimplementable ? (bits | UnimplementableMask)
830+
: (bits & ~UnimplementableMask),
831+
clangTypeInfo);
832+
}
833+
[[nodiscard]]
819834
SILExtInfoBuilder
820835
withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
821836
return SILExtInfoBuilder(
@@ -828,6 +843,7 @@ class SILExtInfoBuilder {
828843
return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical());
829844
}
830845

846+
831847
bool isEqualTo(SILExtInfoBuilder other, bool useClangTypes) const {
832848
return bits == other.bits &&
833849
(useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true);
@@ -873,7 +889,7 @@ class SILExtInfo {
873889
/// A default ExtInfo but with a Thin convention.
874890
static SILExtInfo getThin() {
875891
return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
876-
false, false, false,
892+
false, false, false, false,
877893
DifferentiabilityKind::NonDifferentiable, nullptr)
878894
.build();
879895
}
@@ -901,6 +917,10 @@ class SILExtInfo {
901917

902918
constexpr bool isAsync() const { return builder.isAsync(); }
903919

920+
constexpr bool isUnimplementable() const {
921+
return builder.isUnimplementable();
922+
}
923+
904924
constexpr DifferentiabilityKind getDifferentiabilityKind() const {
905925
return builder.getDifferentiabilityKind();
906926
}
@@ -935,6 +955,10 @@ class SILExtInfo {
935955
return builder.withAsync(isAsync).build();
936956
}
937957

958+
SILExtInfo withUnimplementable(bool isUnimplementable = true) const {
959+
return builder.withUnimplementable(isUnimplementable).build();
960+
}
961+
938962
bool isEqualTo(SILExtInfo other, bool useClangTypes) const {
939963
return builder.isEqualTo(other.builder, useClangTypes);
940964
}

include/swift/AST/Types.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
375375

376376
protected:
377377
enum { NumAFTExtInfoBits = 11 };
378-
enum { NumSILExtInfoBits = 11 };
378+
enum { NumSILExtInfoBits = 12 };
379+
379380
union { uint64_t OpaqueBits;
380381

381382
SWIFT_INLINE_BITFIELD_BASE(TypeBase, bitmax(NumTypeKindBits,8) +
@@ -3558,6 +3559,10 @@ class AnyFunctionType : public TypeBase {
35583559
/// replaced.
35593560
AnyFunctionType *withExtInfo(ExtInfo info) const;
35603561

3562+
bool containsPackExpansionParam() const {
3563+
return containsPackExpansionType(getParams());
3564+
}
3565+
35613566
static bool containsPackExpansionType(ArrayRef<Param> params);
35623567

35633568
static void printParams(ArrayRef<Param> Params, raw_ostream &OS,
@@ -4618,6 +4623,7 @@ class SILFunctionType final
46184623
}
46194624

46204625
bool isSendable() const { return getExtInfo().isSendable(); }
4626+
bool isUnimplementable() const { return getExtInfo().isUnimplementable(); }
46214627
bool isAsync() const { return getExtInfo().isAsync(); }
46224628

46234629
/// Return the array of all the yields.

include/swift/SIL/AbstractionPattern.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,8 @@ class AbstractionPattern {
16251625
getSubstFunctionTypePattern(CanAnyFunctionType substType,
16261626
TypeConverter &TC,
16271627
AbstractionPattern coroutineYieldOrigType,
1628-
CanType coroutineYieldSubstType) const;
1628+
CanType coroutineYieldSubstType,
1629+
bool &unimplementable) const;
16291630

16301631
void dump() const LLVM_ATTRIBUTE_USED;
16311632
void print(raw_ostream &OS) const;

include/swift/SIL/AbstractionPatternGenerators.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@ class FunctionParamGenerator {
136136
return origParamIsExpansion;
137137
}
138138

139+
/// Return whether the current substituted parameter is a pack
140+
/// expansion but the orig function type is opaque. This is
141+
/// unimplementable in our ABI because the calling convention for
142+
/// function types in the most-general abstraction pattern still
143+
/// assumes a fixed arity.
144+
bool isUnimplementablePackExpansion() const {
145+
assert(!isFinished());
146+
return (origFunctionTypeIsOpaque &&
147+
isa<PackExpansionType>(
148+
allSubstParams[substParamIndex].getParameterType()));
149+
}
150+
139151
/// Return the substituted parameters corresponding to the current
140152
/// orig parameter type. If the current orig parameter is not a
141153
/// pack expansion, this will have exactly one element.

lib/AST/ASTDemangler.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,10 @@ Type ASTBuilder::createImplFunctionType(
574574
#undef SIMPLE_CASE
575575
}
576576

577+
// There's no representation of this in the mangling because it can't
578+
// occur in well-formed programs.
579+
bool unimplementable = false;
580+
577581
llvm::SmallVector<SILParameterInfo, 8> funcParams;
578582
llvm::SmallVector<SILYieldInfo, 8> funcYields;
579583
llvm::SmallVector<SILResultInfo, 8> funcResults;
@@ -610,7 +614,8 @@ Type ASTBuilder::createImplFunctionType(
610614
}
611615
auto einfo = SILFunctionType::ExtInfoBuilder(
612616
representation, flags.isPseudogeneric(), !flags.isEscaping(),
613-
flags.isSendable(), flags.isAsync(), diffKind, clangFnType)
617+
flags.isSendable(), flags.isAsync(),
618+
unimplementable, diffKind, clangFnType)
614619
.build();
615620

616621
return SILFunctionType::get(genericSig, einfo, funcCoroutineKind,

lib/AST/ASTPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6496,6 +6496,9 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
64966496
Printer << " ";
64976497
}
64986498

6499+
if (info.isUnimplementable()) {
6500+
Printer.printSimpleAttr("@unimplementable") << " ";
6501+
}
64996502
if (info.isPseudogeneric()) {
65006503
Printer.printSimpleAttr("@pseudogeneric") << " ";
65016504
}

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,9 +1950,10 @@ class SubstFunctionTypePatternVisitor
19501950
SmallVector<Type, 2> substReplacementTypes;
19511951
CanType substYieldType;
19521952
unsigned packExpansionLevel;
1953+
bool &unimplementable;
19531954

1954-
SubstFunctionTypePatternVisitor(TypeConverter &TC)
1955-
: TC(TC), packExpansionLevel(0) {}
1955+
SubstFunctionTypePatternVisitor(TypeConverter &TC, bool &unimplementable)
1956+
: TC(TC), packExpansionLevel(0), unimplementable(unimplementable) {}
19561957

19571958
// Creates and returns a fresh type parameter in the substituted generic
19581959
// signature if `pattern` is a type parameter or opaque archetype. Returns
@@ -2358,7 +2359,10 @@ class SubstFunctionTypePatternVisitor
23582359

23592360
pattern.forEachFunctionParam(func.getParams(), /*ignore self*/ false,
23602361
[&](FunctionParamGenerator &param) {
2361-
if (!param.isOrigPackExpansion()) {
2362+
if (param.isUnimplementablePackExpansion()) {
2363+
unimplementable = true;
2364+
// Just ignore it.
2365+
} else if (!param.isOrigPackExpansion()) {
23622366
auto newParamTy = visit(param.getSubstParams()[0].getParameterType(),
23632367
param.getOrigType());
23642368
addParam(param.getOrigFlags(), newParamTy);
@@ -2401,7 +2405,8 @@ std::tuple<AbstractionPattern, SubstitutionMap, AbstractionPattern>
24012405
AbstractionPattern::getSubstFunctionTypePattern(CanAnyFunctionType substType,
24022406
TypeConverter &TC,
24032407
AbstractionPattern origYieldType,
2404-
CanType substYieldType)
2408+
CanType substYieldType,
2409+
bool &unimplementable)
24052410
const {
24062411
// If this abstraction pattern isn't meaningfully generic, then we don't
24072412
// need to do any transformation.
@@ -2419,7 +2424,7 @@ const {
24192424
: AbstractionPattern::getInvalid());
24202425
}
24212426

2422-
SubstFunctionTypePatternVisitor visitor(TC);
2427+
SubstFunctionTypePatternVisitor visitor(TC, unimplementable);
24232428
auto substTy = visitor.handleUnabstractedFunctionType(substType, *this,
24242429
substYieldType,
24252430
origYieldType);

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,8 +1504,9 @@ class DestructureInputs {
15041504

15051505
void destructure(AbstractionPattern origType,
15061506
CanAnyFunctionType::CanParamArrayRef params,
1507-
SILExtInfoBuilder extInfoBuilder) {
1508-
visitTopLevelParams(origType, params, extInfoBuilder);
1507+
SILExtInfoBuilder extInfoBuilder,
1508+
bool &unimplementable) {
1509+
visitTopLevelParams(origType, params, extInfoBuilder, unimplementable);
15091510
}
15101511

15111512
private:
@@ -1528,7 +1529,8 @@ class DestructureInputs {
15281529
/// is still preserved under opaque abstraction
15291530
void visitTopLevelParams(AbstractionPattern origType,
15301531
CanAnyFunctionType::CanParamArrayRef params,
1531-
SILExtInfoBuilder extInfoBuilder) {
1532+
SILExtInfoBuilder extInfoBuilder,
1533+
bool &unimplementable) {
15321534
// If we're working with an opaque abstraction pattern, we never
15331535
// have to worry about pack expansions, so we can go 1-1 with the
15341536
// substituted parameters.
@@ -1569,6 +1571,31 @@ class DestructureInputs {
15691571
origType.forEachFunctionParam(params.drop_back(hasSelf ? 1 : 0),
15701572
/*ignore final orig param*/ hasSelf,
15711573
[&](FunctionParamGenerator &param) {
1574+
// If the parameter is unimplementable because the orig function
1575+
// type is opaque and the next substituted param is a pack
1576+
// expansion, handle that first.
1577+
if (param.isUnimplementablePackExpansion()) {
1578+
// Record that we have an unimplementable parameter; this will
1579+
// ultimately end up in the function type, and then SILGen
1580+
// is supposed to diagnose any attempt to actually emit or
1581+
// call functions of such types.
1582+
unimplementable = true;
1583+
1584+
// Also, hack up a pack parameter defensively just in case we
1585+
// *do* try to actually use or emit a function with this type.
1586+
auto substParam = param.getSubstParams()[0];
1587+
auto loweredParamTy =
1588+
TC.getLoweredRValueType(expansion, param.getOrigType(),
1589+
substParam.getParameterType());
1590+
SILPackType::ExtInfo extInfo(/*address*/ true);
1591+
auto packTy = SILPackType::get(TC.Context, extInfo, {loweredParamTy});
1592+
1593+
auto origFlags = param.getOrigFlags();
1594+
addPackParameter(packTy, origFlags.getValueOwnership(),
1595+
origFlags.isNoDerivative());
1596+
return;
1597+
}
1598+
15721599
// If the parameter is not a pack expansion, just pull off the
15731600
// next parameter and destructure it in parallel with the abstraction
15741601
// pattern for the type.
@@ -2132,6 +2159,8 @@ static CanSILFunctionType getSILFunctionType(
21322159
llvm::Optional<TypeConverter::GenericContextRAII> contextRAII;
21332160
if (genericSig) contextRAII.emplace(TC, genericSig);
21342161

2162+
bool unimplementable = false;
2163+
21352164
// Per above, only fully honor opaqueness in the abstraction pattern
21362165
// for thick or polymorphic functions. We don't need to worry about
21372166
// non-opaque patterns because the type-checker forbids non-thick
@@ -2262,7 +2291,8 @@ static CanSILFunctionType getSILFunctionType(
22622291
std::tie(origSubstPat, substFunctionTypeSubs, substYieldType)
22632292
= origType.getSubstFunctionTypePattern(substFnInterfaceType, TC,
22642293
coroutineOrigYieldType,
2265-
coroutineSubstYieldType);
2294+
coroutineSubstYieldType,
2295+
unimplementable);
22662296

22672297
// We'll lower the abstraction pattern type against itself, and then apply
22682298
// those substitutions to form the substituted lowered function type.
@@ -2289,7 +2319,7 @@ static CanSILFunctionType getSILFunctionType(
22892319
DestructureInputs destructurer(expansionContext, TC, conventions,
22902320
foreignInfo, inputs);
22912321
destructurer.destructure(origType, substFnInterfaceType.getParams(),
2292-
extInfoBuilder);
2322+
extInfoBuilder, unimplementable);
22932323
}
22942324

22952325
// Destructure the coroutine yields.
@@ -2344,6 +2374,7 @@ static CanSILFunctionType getSILFunctionType(
23442374
.withIsPseudogeneric(pseudogeneric)
23452375
.withConcurrent(isSendable)
23462376
.withAsync(isAsync)
2377+
.withUnimplementable(unimplementable)
23472378
.build();
23482379

23492380
return SILFunctionType::get(genericSig, silExtInfo, coroutineKind,
@@ -2370,12 +2401,15 @@ static CanSILFunctionType getSILFunctionTypeForInitAccessor(
23702401

23712402
// First compute `initialValue` input.
23722403
{
2404+
bool unimplementable = false;
23732405
ForeignInfo foreignInfo;
23742406
DestructureInputs destructurer(context, TC, conventions, foreignInfo,
23752407
inputs);
23762408
destructurer.destructure(
23772409
origType, substAccessorType.getParams(),
2378-
extInfoBuilder.withRepresentation(SILFunctionTypeRepresentation::Thin));
2410+
extInfoBuilder.withRepresentation(SILFunctionTypeRepresentation::Thin),
2411+
unimplementable);
2412+
assert(!unimplementable && "should never have an opaque AP here");
23792413
}
23802414

23812415
// Drop `self` parameter.

0 commit comments

Comments
 (0)