Skip to content

Commit 8fa0dc5

Browse files
committed
Sema: Protocol requirements taking throwing closures can still be conformance rethrows sources
We meant to reject 'rethrows' requirements here instead.
1 parent 31f2c83 commit 8fa0dc5

File tree

2 files changed

+20
-65
lines changed

2 files changed

+20
-65
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -53,55 +53,6 @@ static bool hasThrowingFunctionClosureParameter(CanType type) {
5353
return false;
5454
}
5555

56-
static FunctionRethrowingKind
57-
getTypeThrowingKind(Type interfaceTy, GenericSignature genericSig) {
58-
if (interfaceTy->isTypeParameter()) {
59-
for (auto proto : genericSig->getRequiredProtocols(interfaceTy)) {
60-
if (proto->isRethrowingProtocol()) {
61-
return FunctionRethrowingKind::ByConformance;
62-
}
63-
}
64-
} else if (auto NTD = interfaceTy->getNominalOrBoundGenericNominal()) {
65-
if (auto genericSig = NTD->getGenericSignature()) {
66-
for (auto req : genericSig->getRequirements()) {
67-
if (req.getKind() == RequirementKind::Conformance) {
68-
if (req.getSecondType()->castTo<ProtocolType>()
69-
->getDecl()
70-
->isRethrowingProtocol()) {
71-
return FunctionRethrowingKind::ByConformance;
72-
}
73-
}
74-
}
75-
}
76-
}
77-
return FunctionRethrowingKind::Invalid;
78-
}
79-
80-
static FunctionRethrowingKind
81-
getParameterThrowingKind(AbstractFunctionDecl *decl,
82-
GenericSignature genericSig) {
83-
FunctionRethrowingKind kind = FunctionRethrowingKind::Invalid;
84-
// check all parameters to determine if any are closures that throw
85-
bool foundThrowingClosure = false;
86-
for (auto param : *decl->getParameters()) {
87-
auto interfaceTy = param->getInterfaceType();
88-
if (hasThrowingFunctionClosureParameter(interfaceTy
89-
->lookThroughAllOptionalTypes()
90-
->getCanonicalType())) {
91-
foundThrowingClosure = true;
92-
}
93-
94-
if (kind == FunctionRethrowingKind::Invalid) {
95-
kind = getTypeThrowingKind(interfaceTy, genericSig);
96-
}
97-
}
98-
if (kind == FunctionRethrowingKind::Invalid &&
99-
foundThrowingClosure) {
100-
return FunctionRethrowingKind::ByClosure;
101-
}
102-
return kind;
103-
}
104-
10556
ProtocolRethrowsRequirementList
10657
ProtocolRethrowsRequirementsRequest::evaluate(Evaluator &evaluator,
10758
ProtocolDecl *decl) const {
@@ -115,25 +66,12 @@ ProtocolRethrowsRequirementsRequest::evaluate(Evaluator &evaluator,
11566
return ProtocolRethrowsRequirementList(ctx.AllocateCopy(found));
11667
}
11768

118-
// check if immediate members of protocol are 'rethrows'
69+
// check if immediate members of protocol are 'throws'
11970
for (auto member : decl->getMembers()) {
12071
auto fnDecl = dyn_cast<AbstractFunctionDecl>(member);
121-
// it must be a function
122-
// it must have a rethrows attribute
123-
// it must not have any parameters that are closures that cause rethrowing
124-
if (!fnDecl ||
125-
!fnDecl->hasThrows()) {
72+
if (!fnDecl || !fnDecl->hasThrows())
12673
continue;
127-
}
12874

129-
GenericSignature genericSig = fnDecl->getGenericSignature();
130-
auto kind = getParameterThrowingKind(fnDecl, genericSig);
131-
// skip closure based rethrowing cases
132-
if (kind == FunctionRethrowingKind::ByClosure) {
133-
continue;
134-
}
135-
// we now have a protocol member that has a rethrows and no closure
136-
// parameters contributing to it's rethrowing-ness
13775
found.push_back(
13876
std::pair<Type, ValueDecl*>(decl->getSelfInterfaceType(), fnDecl));
13977
}

test/attr/attr_rethrows_protocol.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,21 @@ NonThrows().closureAndSelfRethrowing { }
9696
try NonThrows().closureAndSelfRethrowing { () throws -> Void in }
9797

9898
try Throws().closureAndSelfRethrowing { }
99-
try Throws().closureAndSelfRethrowing { () throws -> Void in }
99+
try Throws().closureAndSelfRethrowing { () throws -> Void in }
100+
101+
// Soundness hole
102+
@rethrows protocol ThrowsClosure {
103+
func doIt() throws
104+
func doIt(_: () throws -> ()) throws
105+
}
106+
107+
struct ThrowsClosureWitness : ThrowsClosure {
108+
func doIt() {}
109+
func doIt(_: () throws -> ()) throws {}
110+
}
111+
112+
func rethrowsWithThrowsClosure<T : ThrowsClosure>(_ t: T) rethrows {
113+
try t.doIt() {}
114+
}
115+
116+
try rethrowsWithThrowsClosure(ThrowsClosureWitness())

0 commit comments

Comments
 (0)