Skip to content
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
6 changes: 6 additions & 0 deletions include/swift/AST/AnyFunctionRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ class AnyFunctionRef {
return TheFunction.dyn_cast<AbstractClosureExpr*>();
}

bool isDeferBody() const {
if (auto *fd = dyn_cast_or_null<FuncDecl>(getAbstractFunctionDecl()))
return fd->isDeferBody();
return false;
}

/// Return true if this closure is passed as an argument to a function and is
/// known not to escape from that function. In this case, captures can be
/// more efficient.
Expand Down
58 changes: 14 additions & 44 deletions include/swift/AST/CaptureInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define SWIFT_AST_CAPTURE_INFO_H

#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/AST/TypeAlignments.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerIntPair.h"
Expand Down Expand Up @@ -44,8 +45,9 @@ class CapturedValue {

private:
Storage Value;
SourceLoc Loc;

explicit CapturedValue(Storage V) : Value(V) {}
explicit CapturedValue(Storage V, SourceLoc Loc) : Value(V), Loc(Loc) {}

public:
friend struct llvm::DenseMapInfo<CapturedValue>;
Expand All @@ -61,12 +63,14 @@ class CapturedValue {
IsNoEscape = 1 << 1
};

CapturedValue(llvm::PointerUnion<ValueDecl*, OpaqueValueExpr*> Ptr,
unsigned Flags)
: Value(Ptr, Flags) {}
CapturedValue(ValueDecl *Val, unsigned Flags, SourceLoc Loc)
: Value(Val, Flags), Loc(Loc) {}

CapturedValue(OpaqueValueExpr *Val, unsigned Flags)
: Value(Val, Flags), Loc(SourceLoc()) {}

static CapturedValue getDynamicSelfMetadata() {
return CapturedValue((ValueDecl *)nullptr, 0);
return CapturedValue((ValueDecl *)nullptr, 0, SourceLoc());
}

bool isDirect() const { return Value.getInt() & IsDirect; }
Expand All @@ -80,7 +84,9 @@ class CapturedValue {
CapturedValue mergeFlags(CapturedValue cv) {
assert(Value.getPointer() == cv.Value.getPointer() &&
"merging flags on two different value decls");
return CapturedValue(Value.getPointer(), getFlags() & cv.getFlags());
return CapturedValue(
Storage(Value.getPointer(), getFlags() & cv.getFlags()),
Loc);
}

ValueDecl *getDecl() const {
Expand All @@ -95,49 +101,13 @@ class CapturedValue {
return Value.getPointer().dyn_cast<OpaqueValueExpr *>();
}

unsigned getFlags() const { return Value.getInt(); }

bool operator==(CapturedValue RHS) const {
return Value == RHS.Value;
}

bool operator!=(CapturedValue RHS) const {
return Value != RHS.Value;
}
SourceLoc getLoc() const { return Loc; }

bool operator<(CapturedValue RHS) const {
return Value < RHS.Value;
}
unsigned getFlags() const { return Value.getInt(); }
};

} // end swift namespace

namespace llvm {

template <> struct DenseMapInfo<swift::CapturedValue> {
using CapturedValue = swift::CapturedValue;

using PtrIntPairDenseMapInfo = DenseMapInfo<CapturedValue::Storage>;

static inline swift::CapturedValue getEmptyKey() {
return CapturedValue{PtrIntPairDenseMapInfo::getEmptyKey()};
}

static inline CapturedValue getTombstoneKey() {
return CapturedValue{PtrIntPairDenseMapInfo::getTombstoneKey()};
}

static unsigned getHashValue(const CapturedValue &Val) {
return PtrIntPairDenseMapInfo::getHashValue(Val.Value);
}

static bool isEqual(const CapturedValue &LHS, const CapturedValue &RHS) {
return PtrIntPairDenseMapInfo::isEqual(LHS.Value, RHS.Value);
}
};

} // end llvm namespace

namespace swift {

class DynamicSelfType;
Expand Down
8 changes: 8 additions & 0 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ ERROR(unsupported_c_function_pointer_conversion,none,
ERROR(objc_selector_malformed,none,"the type ObjectiveC.Selector is malformed",
())

// Capture before declaration diagnostics.
ERROR(capture_before_declaration,none,
"closure captures %0 before it is declared", (Identifier))
ERROR(capture_before_declaration_defer,none,
"'defer' block captures %0 before it is declared", (Identifier))
NOTE(captured_value_declared_here,none,
"captured value declared here", ())

// Invalid escaping capture diagnostics.
ERROR(escaping_inout_capture,none,
"escaping closure captures 'inout' parameter %0", (Identifier))
Expand Down
8 changes: 0 additions & 8 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3016,14 +3016,6 @@ ERROR(method_call_in_closure_without_explicit_self,none,
ERROR(implicit_use_of_self_in_closure,none,
"implicit use of 'self' in closure; use 'self.' to make"
" capture semantics explicit", ())
ERROR(capture_before_declaration,none,
"cannot capture %0 before it is declared", (Identifier))
ERROR(transitive_capture_before_declaration,none,
"cannot capture %0, which would use %1 before it is declared",
(Identifier, Identifier))
NOTE(transitive_capture_through_here,none,
"%0, declared here, captures %1",
(Identifier, Identifier))

WARNING(recursive_accessor_reference,none,
"attempting to %select{access|modify}1 %0 within its own "
Expand Down
2 changes: 0 additions & 2 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,6 @@ struct SILConstantInfo {

/// Different ways in which a function can capture context.
enum class CaptureKind {
/// No context arguments are necessary.
None,
/// A local value captured as a mutable box.
Box,
/// A local value captured as a single pointer to storage (formed with
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ ParserResult<Stmt> Parser::parseStmtDefer() {
StaticSpellingKind::None,
/*FuncLoc=*/ SourceLoc(),
name,
/*NameLoc=*/ SourceLoc(),
/*NameLoc=*/ PreviousLoc,
/*Throws=*/ false, /*ThrowsLoc=*/ SourceLoc(),
/*generic params*/ nullptr,
params,
Expand Down
2 changes: 0 additions & 2 deletions lib/SIL/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,8 +773,6 @@ lowerCaptureContextParameters(SILModule &M, AnyFunctionRef function,
expansion);
auto loweredTy = loweredTL.getLoweredType();
switch (Types.getDeclCaptureKind(capture, expansion)) {
case CaptureKind::None:
break;
case CaptureKind::Constant: {
// Constants are captured by value.
ParameterConvention convention;
Expand Down
66 changes: 29 additions & 37 deletions lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,44 +91,36 @@ static bool hasSingletonMetatype(CanType instanceType) {
CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
ResilienceExpansion expansion) {
auto decl = capture.getDecl();
if (auto *var = dyn_cast<VarDecl>(decl)) {
assert(var->hasStorage() &&
"should not have attempted to directly capture this variable");

// If this is a non-address-only stored 'let' constant, we can capture it
// by value. If it is address-only, then we can't load it, so capture it
// by its address (like a var) instead.
if (var->isImmutable() &&
(!SILModuleConventions(M).useLoweredAddresses() ||
!getTypeLowering(var->getType(), expansion).isAddressOnly()))
return CaptureKind::Constant;

// In-out parameters are captured by address.
if (var->isInOut()) {
return CaptureKind::StorageAddress;
}

// Reference storage types can appear in a capture list, which means
// we might allocate boxes to store the captures. However, those boxes
// have the same lifetime as the closure itself, so we must capture
// the box itself and not the payload, even if the closure is noescape,
// otherwise they will be destroyed when the closure is formed.
if (var->getType()->is<ReferenceStorageType>()) {
return CaptureKind::Box;
}

// If we're capturing into a non-escaping closure, we can generally just
// capture the address of the value as no-escape.
return capture.isNoEscape() ?
CaptureKind::StorageAddress : CaptureKind::Box;
auto *var = cast<VarDecl>(decl);
assert(var->hasStorage() &&
"should not have attempted to directly capture this variable");

// If this is a non-address-only stored 'let' constant, we can capture it
// by value. If it is address-only, then we can't load it, so capture it
// by its address (like a var) instead.
if (var->isImmutable() &&
(!SILModuleConventions(M).useLoweredAddresses() ||
!getTypeLowering(var->getType(), expansion).isAddressOnly()))
return CaptureKind::Constant;

// In-out parameters are captured by address.
if (var->isInOut()) {
return CaptureKind::StorageAddress;
}

// "Captured" local types require no context.
if (isa<TypeAliasDecl>(decl) || isa<GenericTypeParamDecl>(decl) ||
isa<AssociatedTypeDecl>(decl))
return CaptureKind::None;

llvm_unreachable("function-like captures should have been lowered away");

// Reference storage types can appear in a capture list, which means
// we might allocate boxes to store the captures. However, those boxes
// have the same lifetime as the closure itself, so we must capture
// the box itself and not the payload, even if the closure is noescape,
// otherwise they will be destroyed when the closure is formed.
if (var->getType()->is<ReferenceStorageType>()) {
return CaptureKind::Box;
}

// If we're capturing into a non-escaping closure, we can generally just
// capture the address of the value as no-escape.
return capture.isNoEscape() ?
CaptureKind::StorageAddress : CaptureKind::Box;
}

using RecursiveProperties = TypeLowering::RecursiveProperties;
Expand Down
Loading