Skip to content

Commit e214156

Browse files
committed
Sema: Remove escaping capture diagnostics
I'm about to replace all of this with a SIL pass.
1 parent d96aebd commit e214156

15 files changed

+26
-483
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2900,21 +2900,6 @@ NOTE(transitive_capture_through_here,none,
29002900
"%0, declared here, captures %1",
29012901
(Identifier, Identifier))
29022902

2903-
ERROR(closure_implicit_capture_without_noescape,none,
2904-
"escaping closures can only capture inout parameters explicitly by value",
2905-
())
2906-
ERROR(closure_implicit_capture_mutating_self,none,
2907-
"escaping closure cannot capture a mutating self parameter",
2908-
())
2909-
NOTE(create_mutating_copy_or_capture_self,none,
2910-
"create a mutating copy of self, or explicitly capture self for immutability",
2911-
())
2912-
ERROR(nested_function_with_implicit_capture_argument,none,
2913-
"nested function with %select{an |}0implicitly captured inout "
2914-
"parameter%select{|s}0 can only be used as a non-escaping argument", (bool))
2915-
ERROR(nested_function_escaping_inout_capture,none,
2916-
"nested function cannot capture inout parameter and escape", ())
2917-
29182903
WARNING(recursive_accessor_reference,none,
29192904
"attempting to %select{access|modify}1 %0 within its own "
29202905
"%select{getter|setter}1", (Identifier, bool))
@@ -3039,19 +3024,10 @@ WARNING(debug_description_in_string_interpolation_segment,none,
30393024
NOTE(silence_debug_description_in_interpolation_segment_call,none,
30403025
"use 'String(describing:)' to silence this warning", ())
30413026

3042-
ERROR(invalid_noescape_use,none,
3043-
"non-escaping %select{value|parameter}1 %0 may only be called",
3044-
(Identifier, bool))
30453027
NOTE(noescape_parameter,none,
30463028
"parameter %0 is implicitly non-escaping",
30473029
(Identifier))
30483030

3049-
ERROR(closure_noescape_use,none,
3050-
"closure use of non-escaping parameter %0 may allow it to escape",
3051-
(Identifier))
3052-
ERROR(decl_closure_noescape_use,none,
3053-
"declaration closing over non-escaping parameter %0 may allow it to escape",
3054-
(Identifier))
30553031
ERROR(passing_noescape_to_escaping,none,
30563032
"passing non-escaping parameter %0 to function expecting an @escaping closure",
30573033
(Identifier))

lib/Sema/CSApply.cpp

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7250,46 +7250,6 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
72507250
// Try closing the existential, if there is one.
72517251
closeExistential(result, locator);
72527252

7253-
// Extract all arguments.
7254-
auto *CEA = arg;
7255-
7256-
// The argument is either a ParenExpr or TupleExpr.
7257-
ArrayRef<Expr *> arguments;
7258-
7259-
SmallVector<Expr *, 1> Scratch;
7260-
if (auto *TE = dyn_cast<TupleExpr>(CEA))
7261-
arguments = TE->getElements();
7262-
else if (auto *PE = dyn_cast<ParenExpr>(CEA)) {
7263-
Scratch.push_back(PE->getSubExpr());
7264-
arguments = makeArrayRef(Scratch);
7265-
}
7266-
else {
7267-
Scratch.push_back(apply->getArg());
7268-
arguments = makeArrayRef(Scratch);
7269-
}
7270-
7271-
for (auto arg: arguments) {
7272-
bool isNoEscape = false;
7273-
while (1) {
7274-
if (auto AFT = cs.getType(arg)->getAs<AnyFunctionType>()) {
7275-
isNoEscape = isNoEscape || AFT->isNoEscape();
7276-
}
7277-
7278-
if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))
7279-
arg = conv->getSubExpr();
7280-
else if (auto *PE = dyn_cast<ParenExpr>(arg))
7281-
arg = PE->getSubExpr();
7282-
else
7283-
break;
7284-
}
7285-
if (!isNoEscape) {
7286-
if (auto DRE = dyn_cast<DeclRefExpr>(arg))
7287-
if (auto FD = dyn_cast<FuncDecl>(DRE->getDecl())) {
7288-
tc.addEscapingFunctionAsArgument(FD, apply);
7289-
}
7290-
}
7291-
}
7292-
72937253
if (unwrapResult)
72947254
return forceUnwrapResult(result);
72957255

lib/Sema/MiscDiagnostics.cpp

Lines changed: 4 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
6363
bool isExprStmt) {
6464
class DiagnoseWalker : public ASTWalker {
6565
SmallPtrSet<Expr*, 4> AlreadyDiagnosedMetatypes;
66-
SmallPtrSet<DeclRefExpr*, 4> AlreadyDiagnosedNoEscapes;
6766
SmallPtrSet<DeclRefExpr*, 4> AlreadyDiagnosedBitCasts;
6867

6968
// Keep track of acceptable DiscardAssignmentExpr's.
@@ -84,23 +83,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
8483
DiagnoseWalker(TypeChecker &TC, const DeclContext *DC, bool isExprStmt)
8584
: IsExprStmt(isExprStmt), TC(TC), DC(DC) {}
8685

87-
// Selector for the partial_application_of_function_invalid diagnostic
88-
// message.
89-
struct PartialApplication {
90-
enum : unsigned {
91-
MutatingMethod,
92-
SuperInit,
93-
SelfInit,
94-
};
95-
enum : unsigned {
96-
Error,
97-
CompatibilityWarning,
98-
};
99-
unsigned compatibilityWarning: 1;
100-
unsigned kind : 2;
101-
unsigned level : 29;
102-
};
103-
10486
// Not interested in going outside a basic expression.
10587
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
10688
return { false, S };
@@ -129,9 +111,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
129111
checkUseOfMetaTypeName(Base);
130112
}
131113

132-
// Verify noescape parameter uses.
133-
checkNoEscapeParameterUse(DRE, Parent.getAsExpr(), OperandKind::None);
134-
135114
// Verify warn_unqualified_access uses.
136115
checkUnqualifiedAccessUse(DRE);
137116

@@ -155,12 +134,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
155134
if (auto *IOE = dyn_cast<InOutExpr>(SE->getBase()))
156135
if (IOE->isImplicit())
157136
AcceptableInOutExprs.insert(IOE);
158-
159-
visitIndices(SE, [&](unsigned argIndex, Expr *arg) {
160-
arg = lookThroughArgument(arg);
161-
if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
162-
checkNoEscapeParameterUse(DRE, SE, OperandKind::Argument);
163-
});
164137
}
165138

166139
if (auto *KPE = dyn_cast<KeyPathExpr>(E)) {
@@ -170,21 +143,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
170143
}
171144
}
172145

173-
if (auto *AE = dyn_cast<CollectionExpr>(E)) {
174-
visitCollectionElements(AE, [&](unsigned argIndex, Expr *arg) {
175-
arg = lookThroughArgument(arg);
176-
if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
177-
checkNoEscapeParameterUse(DRE, AE, OperandKind::Argument);
178-
});
179-
}
180-
181-
// Check decl refs in withoutActuallyEscaping blocks.
182-
if (auto MakeEsc = dyn_cast<MakeTemporarilyEscapableExpr>(E)) {
183-
if (auto DRE =
184-
dyn_cast<DeclRefExpr>(MakeEsc->getNonescapingClosureValue()))
185-
checkNoEscapeParameterUse(DRE, MakeEsc, OperandKind::MakeEscapable);
186-
}
187-
188146
// Check function calls, looking through implicit conversions on the
189147
// function and inspecting the arguments directly.
190148
if (auto *Call = dyn_cast<ApplyExpr>(E)) {
@@ -221,7 +179,10 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
221179

222180
ConcreteDeclRef callee;
223181
if (auto *calleeDRE = dyn_cast<DeclRefExpr>(base)) {
224-
checkNoEscapeParameterUse(calleeDRE, Call, OperandKind::Callee);
182+
// This only cares about declarations of noescape function type.
183+
auto AFT = calleeDRE->getType()->getAs<FunctionType>();
184+
if (AFT && AFT->isNoEscape())
185+
checkNoEscapeParameterCall(Call);
225186
checkForSuspiciousBitCasts(calleeDRE, Call);
226187
callee = calleeDRE->getDeclRef();
227188

@@ -267,12 +228,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
267228
unwrapped, operand);
268229
}
269230
}
270-
271-
// Also give special treatment to noescape function arguments.
272-
arg = lookThroughArgument(arg);
273-
274-
if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
275-
checkNoEscapeParameterUse(DRE, Call, OperandKind::Argument);
276231
});
277232
}
278233

@@ -339,25 +294,12 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
339294
}
340295
}
341296

342-
static void visitIndices(SubscriptExpr *subscript,
343-
llvm::function_ref<void(unsigned, Expr*)> fn) {
344-
auto *indexArgs = subscript->getIndex();
345-
argExprVisitArguments(indexArgs, fn);
346-
}
347-
348297
static void visitArguments(ApplyExpr *apply,
349298
llvm::function_ref<void(unsigned, Expr*)> fn) {
350299
auto *arg = apply->getArg();
351300
argExprVisitArguments(arg, fn);
352301
}
353302

354-
static void visitCollectionElements(CollectionExpr *collection,
355-
llvm::function_ref<void(unsigned, Expr*)> fn) {
356-
auto elts = collection->getElements();
357-
for (auto i : indices(elts))
358-
fn(i, elts[i]);
359-
}
360-
361303
static Expr *lookThroughArgument(Expr *arg) {
362304
while (1) {
363305
if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))
@@ -572,61 +514,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
572514
.highlight(problematicArg->getSourceRange());
573515
}
574516

575-
enum class OperandKind {
576-
None,
577-
Callee,
578-
Argument,
579-
MakeEscapable,
580-
};
581-
582-
/// The DRE argument is a reference to a noescape parameter. Verify that
583-
/// its uses are ok.
584-
void checkNoEscapeParameterUse(DeclRefExpr *DRE, Expr *parent,
585-
OperandKind useKind) {
586-
// This only cares about declarations of noescape function type.
587-
auto AFT = DRE->getType()->getAs<FunctionType>();
588-
if (!AFT || !AFT->isNoEscape())
589-
return;
590-
591-
// Only diagnose this once. If we check and accept this use higher up in
592-
// the AST, don't recheck here.
593-
if (!AlreadyDiagnosedNoEscapes.insert(DRE).second)
594-
return;
595-
596-
// The only valid use of the noescape parameter is an immediate call,
597-
// either as the callee or as an argument (in which case, the typechecker
598-
// validates that the noescape bit didn't get stripped off), or as
599-
// a special case, e.g. in the binding of a withoutActuallyEscaping block
600-
// or the argument of a type(of: ...).
601-
if (parent) {
602-
if (auto apply = dyn_cast<ApplyExpr>(parent)) {
603-
if (isa<ParamDecl>(DRE->getDecl()) && useKind == OperandKind::Callee)
604-
checkNoEscapeParameterCall(apply);
605-
return;
606-
} else if (isa<SubscriptExpr>(parent)
607-
&& useKind == OperandKind::Argument) {
608-
return;
609-
} else if (isa<MakeTemporarilyEscapableExpr>(parent)) {
610-
return;
611-
} else if (isa<DynamicTypeExpr>(parent)) {
612-
return;
613-
}
614-
}
615-
616-
TC.diagnose(DRE->getStartLoc(), diag::invalid_noescape_use,
617-
cast<VarDecl>(DRE->getDecl())->getName(),
618-
isa<ParamDecl>(DRE->getDecl()));
619-
620-
// If we're a parameter, emit a helpful fixit to add @escaping
621-
auto paramDecl = dyn_cast<ParamDecl>(DRE->getDecl());
622-
if (paramDecl) {
623-
TC.diagnose(paramDecl->getStartLoc(), diag::noescape_parameter,
624-
paramDecl->getName())
625-
.fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start,
626-
"@escaping ");
627-
}
628-
}
629-
630517
// Diagnose metatype values that don't appear as part of a property,
631518
// method, or constructor reference.
632519
void checkUseOfMetaTypeName(Expr *E) {

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -199,34 +199,6 @@ class FindCapturedVars : public ASTWalker {
199199
|| !isa<VarDecl>(VD)
200200
|| !cast<VarDecl>(VD)->getType()->hasRetainablePointerRepresentation()))
201201
checkType(VD->getInterfaceType(), VD->getLoc());
202-
203-
// If VD is a noescape decl, then the closure we're computing this for
204-
// must also be noescape.
205-
if (AFR.hasType() &&
206-
!AFR.getType()->hasError() &&
207-
VD->hasInterfaceType() &&
208-
VD->getInterfaceType()->is<AnyFunctionType>() &&
209-
VD->getInterfaceType()->castTo<AnyFunctionType>()->isNoEscape() &&
210-
!capture.isNoEscape() &&
211-
// Don't repeatedly diagnose the same thing.
212-
Diagnosed.insert(VD).second) {
213-
214-
// Otherwise, diagnose this as an invalid capture.
215-
bool isDecl = AFR.getAbstractFunctionDecl() != nullptr;
216-
217-
TC.diagnose(Loc, isDecl ? diag::decl_closure_noescape_use
218-
: diag::closure_noescape_use,
219-
VD->getBaseName().getIdentifier());
220-
221-
// If we're a parameter, emit a helpful fixit to add @escaping
222-
auto paramDecl = dyn_cast<ParamDecl>(VD);
223-
if (paramDecl) {
224-
TC.diagnose(paramDecl->getStartLoc(), diag::noescape_parameter,
225-
paramDecl->getName())
226-
.fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start,
227-
"@escaping ");
228-
}
229-
}
230202
}
231203

232204
bool shouldWalkIntoLazyInitializers() override {
@@ -393,24 +365,6 @@ class FindCapturedVars : public ASTWalker {
393365
if (!validateForwardCapture(DRE->getDecl()))
394366
return { false, DRE };
395367

396-
bool isInOut = (isa<ParamDecl>(D) && cast<ParamDecl>(D)->isInOut());
397-
bool isNested = false;
398-
if (auto f = AFR.getAbstractFunctionDecl())
399-
isNested = f->getDeclContext()->isLocalContext();
400-
401-
if (isInOut && !AFR.isKnownNoEscape() && !isNested) {
402-
if (D->getBaseName() == D->getASTContext().Id_self) {
403-
TC.diagnose(DRE->getLoc(),
404-
diag::closure_implicit_capture_mutating_self);
405-
TC.diagnose(DRE->getLoc(),
406-
diag::create_mutating_copy_or_capture_self);
407-
} else {
408-
TC.diagnose(DRE->getLoc(),
409-
diag::closure_implicit_capture_without_noescape);
410-
}
411-
return { false, DRE };
412-
}
413-
414368
// We're going to capture this, compute flags for the capture.
415369
unsigned Flags = 0;
416370

@@ -734,28 +688,6 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
734688
if (AFR.getBody())
735689
AFR.getBody()->walk(finder);
736690

737-
unsigned inoutCount = 0;
738-
for (auto C : Captures) {
739-
if (auto PD = dyn_cast<ParamDecl>(C.getDecl()))
740-
if (PD->isInOut())
741-
inoutCount++;
742-
}
743-
744-
if (inoutCount > 0) {
745-
if (auto e = AFR.getAbstractFunctionDecl()) {
746-
for (auto returnOccurrence : getEscapingFunctionAsReturnValue(e)) {
747-
diagnose(returnOccurrence->getReturnLoc(),
748-
diag::nested_function_escaping_inout_capture);
749-
}
750-
auto occurrences = getEscapingFunctionAsArgument(e);
751-
for (auto occurrence : occurrences) {
752-
diagnose(occurrence->getLoc(),
753-
diag::nested_function_with_implicit_capture_argument,
754-
inoutCount > 1);
755-
}
756-
}
757-
}
758-
759691
if (AFR.hasType() && !AFR.isObjC()) {
760692
finder.checkType(AFR.getType(), getCaptureLoc(AFR));
761693
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,11 +472,7 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
472472
tryDiagnoseUnnecessaryCastOverOptionSet(TC.Context, E, ResultTy,
473473
DC->getParentModule());
474474
}
475-
while (auto ICE = dyn_cast<ImplicitConversionExpr>(E))
476-
E = ICE->getSubExpr();
477-
if (auto DRE = dyn_cast<DeclRefExpr>(E))
478-
if (auto FD = dyn_cast<FuncDecl>(DRE->getDecl()))
479-
TC.addEscapingFunctionAsReturnValue(FD, RS);
475+
480476
return RS;
481477
}
482478

0 commit comments

Comments
 (0)