Skip to content

Redo diagnostics for escaping captures and non-escaping parameter call restriction [5.1] #23923

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
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
15 changes: 0 additions & 15 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1379,21 +1379,6 @@ WARNING(attr_availability_nonspecific_platform_unexpected_version,none,
"unexpected version number in '%0' attribute for non-specific platform "
"'*'", (StringRef))

// autoclosure
ERROR(attr_autoclosure_expected_r_paren,PointsToFirstBadToken,
"expected ')' in @autoclosure", ())
ERROR(attr_noescape_conflicts_escaping_autoclosure,none,
"@noescape conflicts with @autoclosure(escaping)", ())
ERROR(attr_noescape_implied_by_autoclosure,none,
"@noescape is implied by @autoclosure and should not be "
"redundantly specified", ())
ERROR(attr_autoclosure_escaping_deprecated,none,
"@autoclosure(escaping) has been removed; use @autoclosure @escaping instead",
())
ERROR(attr_noescape_deprecated,none,
"@noescape is the default and has been removed",
())

// convention
ERROR(convention_attribute_expected_lparen,none,
"expected '(' after 'convention' attribute", ())
Expand Down
27 changes: 27 additions & 0 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,33 @@ ERROR(unsupported_c_function_pointer_conversion,none,
ERROR(objc_selector_malformed,none,"the type ObjectiveC.Selector is malformed",
())

// Invalid escaping capture diagnostics.
ERROR(escaping_inout_capture,none,
"escaping closure captures 'inout' parameter %0", (Identifier))
NOTE(inout_param_defined_here,none,
"parameter %0 is declared 'inout'", (Identifier))
ERROR(escaping_mutable_self_capture,none,
"escaping closure captures mutating 'self' parameter", ())

ERROR(escaping_noescape_param_capture,none,
"escaping closure captures non-escaping parameter %0", (Identifier))
NOTE(noescape_param_defined_here,none,
"parameter %0 is implicitly non-escaping", (Identifier))

ERROR(escaping_noescape_var_capture,none,
"escaping closure captures non-escaping value", ())

NOTE(value_captured_here,none,"captured here", ())

NOTE(value_captured_transitively,none,
"captured indirectly by this call", ())

ERROR(err_noescape_param_call,none,
"passing a %select{|closure which captures a }1non-escaping function "
"parameter %0 to a call to a non-escaping function parameter can allow "
"re-entrant modification of a variable",
(DeclName, unsigned))

// Definite initialization diagnostics.
NOTE(variable_defined_here,none,
"%select{variable|constant}0 defined here", (bool))
Expand Down
31 changes: 0 additions & 31 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,6 @@ ERROR(incorrect_explicit_closure_result,none,
"declared closure result %0 is incompatible with contextual type %1",
(Type, Type))

ERROR(err_noescape_param_call,none,
"passing a %select{|closure which captures a }1non-escaping function "
"parameter %0 to a call to a non-escaping function parameter can allow "
"re-entrant modification of a variable",
(DeclName, unsigned))
ERROR(cannot_call_function_value,none,
"cannot invoke value of function type with argument list '%0'",
(StringRef))
Expand Down Expand Up @@ -2905,21 +2900,6 @@ NOTE(transitive_capture_through_here,none,
"%0, declared here, captures %1",
(Identifier, Identifier))

ERROR(closure_implicit_capture_without_noescape,none,
"escaping closures can only capture inout parameters explicitly by value",
())
ERROR(closure_implicit_capture_mutating_self,none,
"escaping closure cannot capture a mutating self parameter",
())
NOTE(create_mutating_copy_or_capture_self,none,
"create a mutating copy of self, or explicitly capture self for immutability",
())
ERROR(nested_function_with_implicit_capture_argument,none,
"nested function with %select{an |}0implicitly captured inout "
"parameter%select{|s}0 can only be used as a non-escaping argument", (bool))
ERROR(nested_function_escaping_inout_capture,none,
"nested function cannot capture inout parameter and escape", ())

WARNING(recursive_accessor_reference,none,
"attempting to %select{access|modify}1 %0 within its own "
"%select{getter|setter}1", (Identifier, bool))
Expand Down Expand Up @@ -3044,19 +3024,10 @@ WARNING(debug_description_in_string_interpolation_segment,none,
NOTE(silence_debug_description_in_interpolation_segment_call,none,
"use 'String(describing:)' to silence this warning", ())

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

ERROR(closure_noescape_use,none,
"closure use of non-escaping parameter %0 may allow it to escape",
(Identifier))
ERROR(decl_closure_noescape_use,none,
"declaration closing over non-escaping parameter %0 may allow it to escape",
(Identifier))
ERROR(passing_noescape_to_escaping,none,
"passing non-escaping parameter %0 to function expecting an @escaping closure",
(Identifier))
Expand Down Expand Up @@ -3529,8 +3500,6 @@ NOTE(overridden_required_initializer_here,none,
// Functions
ERROR(attribute_requires_function_type,none,
"@%0 attribute only applies to function types", (StringRef))
ERROR(attribute_not_supported,none,
"this attribute is not supported", ())
ERROR(unsupported_convention,none,
"convention '%0' not supported", (StringRef))
ERROR(unreferenced_generic_parameter,none,
Expand Down
8 changes: 6 additions & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -622,10 +622,14 @@ class alignas(1 << TypeAlignInBits) TypeBase {
return getRecursiveProperties().isLValue();
}

/// Is a type with these properties materializable: that is, is it a
/// first-class value type?
/// Is this a first-class value type, meaning it is not an InOutType or a
/// tuple type containing an InOutType?
bool isMaterializable();

/// Is this a non-escaping type, that is, a non-escaping function type or a
/// tuple type containing a non-escaping type?
bool isNoEscape() const;

/// Determine whether the type is dependent on DynamicSelf.
bool hasDynamicSelfType() const {
return getRecursiveProperties().hasDynamicSelf();
Expand Down
2 changes: 0 additions & 2 deletions include/swift/Migrator/FixitFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,6 @@ struct FixitFilter {
Info.ID == diag::where_inside_brackets.ID ||
Info.ID == diag::selector_construction_suggest.ID ||
Info.ID == diag::selector_literal_deprecated_suggest.ID ||
Info.ID == diag::attr_noescape_deprecated.ID ||
Info.ID == diag::attr_autoclosure_escaping_deprecated.ID ||
Info.ID == diag::attr_warn_unused_result_removed.ID ||
Info.ID == diag::any_as_anyobject_fixit.ID ||
Info.ID == diag::deprecated_protocol_composition.ID ||
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ PASS(Devirtualizer, "devirtualizer",
"Indirect Call Devirtualization")
PASS(DiagnoseInfiniteRecursion, "diagnose-infinite-recursion",
"Diagnose Infinitely-Recursive Code")
PASS(DiagnoseInvalidEscapingCaptures, "diagnose-invalid-escaping-captures",
"Diagnose Invalid Escaping Captures")
PASS(DiagnoseStaticExclusivity, "diagnose-static-exclusivity",
"Static Enforcement of Law of Exclusivity")
PASS(DiagnoseUnreachable, "diagnose-unreachable",
Expand Down
18 changes: 18 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3079,6 +3079,24 @@ const DependentMemberType *TypeBase::findUnresolvedDependentMemberType() {
return unresolvedDepMemTy;
}

bool TypeBase::isNoEscape() const {
auto type = getCanonicalType();

if (auto silFuncTy = dyn_cast<SILFunctionType>(type))
return silFuncTy->isNoEscape();

if (auto funcTy = dyn_cast<FunctionType>(type))
return funcTy->isNoEscape();

if (auto tupleTy = dyn_cast<TupleType>(type)) {
for (auto eltTy : tupleTy.getElementTypes())
if (eltTy->isNoEscape())
return true;
}

return false;
}

static Type getConcreteTypeForSuperclassTraversing(Type t) {
if (t->isExistentialType()) {
return t->getExistentialLayout().getSuperclass();
Expand Down
65 changes: 3 additions & 62 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1940,31 +1940,10 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
StringRef Text = Tok.getText();
SourceLoc Loc = consumeToken();

bool isAutoclosureEscaping = false;
SourceRange autoclosureEscapingParenRange;
StringRef conventionName;
StringRef witnessMethodProtocol;

// Handle @autoclosure(escaping)
if (attr == TAK_autoclosure) {
// We need to do a bit of lookahead here to make sure we parse a (weird)
// type like: "@autoclosure (escaping) -> Int" correctly (escaping is the
// name of a type here). We also want to support the case where the
// function type coming up is a typealias, e.g. "@autoclosure (escaping) T".
if (Tok.is(tok::l_paren) && peekToken().getText() == "escaping") {
Parser::BacktrackingScope Backtrack(*this);
consumeToken(tok::l_paren);
consumeToken(tok::identifier);
isAutoclosureEscaping =
Tok.is(tok::r_paren) && peekToken().isNot(tok::arrow);
}

if (isAutoclosureEscaping) {
autoclosureEscapingParenRange.Start = consumeToken(tok::l_paren);
consumeToken(tok::identifier);
autoclosureEscapingParenRange.End = consumeToken(tok::r_paren);
}
} else if (attr == TAK_convention) {
if (attr == TAK_convention) {
SourceLoc LPLoc;
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
if (!justChecking)
Expand Down Expand Up @@ -2027,48 +2006,10 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
switch (attr) {
default: break;
case TAK_autoclosure:
// Handle @autoclosure(escaping)
if (isAutoclosureEscaping) {
// @noescape @autoclosure(escaping) makes no sense.
if (Attributes.has(TAK_noescape)) {
diagnose(Loc, diag::attr_noescape_conflicts_escaping_autoclosure);
} else {
diagnose(Loc, diag::attr_autoclosure_escaping_deprecated)
.fixItReplace(autoclosureEscapingParenRange, " @escaping ");
}
Attributes.setAttr(TAK_escaping, Loc);
} else if (Attributes.has(TAK_noescape) && !isInSILMode()) {
diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
}
break;

case TAK_noescape:
// You can't specify @noescape and @escaping together.
if (Attributes.has(TAK_escaping)) {
diagnose(Loc, diag::attr_escaping_conflicts_noescape);
return false;
}

// @noescape after @autoclosure is redundant.
if (Attributes.has(TAK_autoclosure) && !isInSILMode()) {
diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
}

// @noescape is deprecated and no longer used
// In SIL, the polarity of @escaping is reversed.
// @escaping is the default and @noescape is explicit.
if (!isInSILMode()) {
diagnose(Loc, diag::attr_noescape_deprecated)
.fixItRemove({Attributes.AtLoc, Loc});
}
break;
case TAK_escaping:
// You can't specify @noescape and @escaping together.
if (Attributes.has(TAK_noescape)) {
diagnose(Loc, diag::attr_escaping_conflicts_noescape);
return false;
}
case TAK_noescape:
break;

case TAK_out:
case TAK_in:
case TAK_owned:
Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/Mandatory/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ silopt_register_sources(
DIMemoryUseCollector.cpp
DataflowDiagnostics.cpp
DiagnoseInfiniteRecursion.cpp
DiagnoseInvalidEscapingCaptures.cpp
DiagnoseStaticExclusivity.cpp
DiagnoseUnreachable.cpp
GuaranteedARCOpts.cpp
Expand Down
Loading