Skip to content

Fix static exclusivity verification for withoutActuallyEscaping. #18708

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 2 commits into from
Aug 15, 2018
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
16 changes: 15 additions & 1 deletion docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4714,7 +4714,9 @@ convert_function
````````````````
::

sil-instruction ::= 'convert_function' sil-operand 'to' sil-type
sil-instruction ::= 'convert_function' sil-operand 'to'
('[' 'without_actually_escaping' ']')?
sil-type

%1 = convert_function %0 : $T -> U to $T' -> U'
// %0 must be of a function type $T -> U ABI-compatible with $T' -> U'
Expand Down Expand Up @@ -4744,6 +4746,18 @@ without ``@noescape`` are ABI compatible because they have no context. To
convert from an escaping to a ``@noescape`` thick function type use
``convert_escape_to_noescape``.

With the ``without_actually_escaping`` attribute, the
``convert_function`` may be used to convert a non-escaping closure
into an escaping function type. This attribute must be present
whenever the closure operand has an unboxed capture (via
@inout_aliasable) *and* the resulting function type is escaping. (This
only happens as a result of withoutActuallyEscaping()). If the
attribute is present then the resulting function type must be
escaping, but the operand's function type may or may not be
@noescape. Note that a non-escaping closure may have unboxed captured
even though its SIL function type is "escaping".


convert_escape_to_noescape
```````````````````````````
::
Expand Down
3 changes: 3 additions & 0 deletions include/swift/SIL/InstructionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ SILValue stripBorrow(SILValue V);
/// copies the value of its first operand, possibly changing its type or
/// ownership state, but otherwise having no effect.
///
/// The returned instruction may have additional "incidental" operands;
/// mark_dependence for example.
///
/// This is useful for checking all users of a value to verify that the value is
/// only used in recognizable patterns without otherwise "escaping". These are
/// instructions that the use-visitor can recurse into. Note that the value's
Expand Down
8 changes: 5 additions & 3 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -886,9 +886,11 @@ class SILBuilder {
}

ConvertFunctionInst *createConvertFunction(SILLocation Loc, SILValue Op,
SILType Ty) {
return insert(ConvertFunctionInst::create(
getSILDebugLocation(Loc), Op, Ty, getFunction(), C.OpenedArchetypes));
SILType Ty,
bool WithoutActuallyEscaping) {
return insert(ConvertFunctionInst::create(getSILDebugLocation(Loc), Op, Ty,
getFunction(), C.OpenedArchetypes,
WithoutActuallyEscaping));
}

ConvertEscapeToNoEscapeInst *
Expand Down
8 changes: 4 additions & 4 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1020,10 +1020,10 @@ template<typename ImplClass>
void
SILCloner<ImplClass>::visitConvertFunctionInst(ConvertFunctionInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createConvertFunction(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
getOpType(Inst->getType())));
doPostProcess(
Inst, getBuilder().createConvertFunction(
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()),
getOpType(Inst->getType()), Inst->withoutActuallyEscaping()));
}

template <typename ImplClass>
Expand Down
20 changes: 20 additions & 0 deletions include/swift/SIL/SILFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ class SILFunction
/// serialization.
bool WasDeserializedCanonical = false;

/// True if this is a reabstraction thunk of escaping function type whose
/// single argument is a potentially non-escaping closure. This is an escape
/// hatch to allow non-escaping functions to be stored or passed as an
/// argument with escaping function type. The thunk argument's function type
/// is not necessarily @noescape. The only relevant aspect of the argument is
/// that it may have unboxed capture (i.e. @inout_aliasable parameters).
bool IsWithoutActuallyEscapingThunk = false;

static void
validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
const GenericSpecializationInformation *genericInfo) {
Expand Down Expand Up @@ -385,6 +393,18 @@ class SILFunction
WasDeserializedCanonical = val;
}

/// Returns true if this is a reabstraction thunk of escaping function type
/// whose single argument is a potentially non-escaping closure. i.e. the
/// thunks' function argument may itself have @inout_aliasable parameters.
bool isWithoutActuallyEscapingThunk() const {
return IsWithoutActuallyEscapingThunk;
}

void setWithoutActuallyEscapingThunk(bool val = true) {
assert(!val || isThunk() == IsReabstractionThunk);
IsWithoutActuallyEscapingThunk = val;
}

/// Returns the calling convention used by this entry point.
SILFunctionTypeRepresentation getRepresentation() const {
return getLoweredFunctionType()->getRepresentation();
Expand Down
26 changes: 22 additions & 4 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3957,19 +3957,37 @@ class ConvertFunctionInst final
friend SILBuilder;

ConvertFunctionInst(SILDebugLocation DebugLoc, SILValue Operand,
ArrayRef<SILValue> TypeDependentOperands, SILType Ty)
ArrayRef<SILValue> TypeDependentOperands, SILType Ty,
bool WithoutActuallyEscaping)
: UnaryInstructionWithTypeDependentOperandsBase(
DebugLoc, Operand, TypeDependentOperands, Ty) {
SILInstruction::Bits.ConvertFunctionInst.WithoutActuallyEscaping =
WithoutActuallyEscaping;
assert((Operand->getType().castTo<SILFunctionType>()->isNoEscape() ==
Ty.castTo<SILFunctionType>()->isNoEscape() ||
Ty.castTo<SILFunctionType>()->getRepresentation() !=
SILFunctionType::Representation::Thick) &&
"Change of escapeness is not ABI compatible");
}

static ConvertFunctionInst *
create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty,
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
static ConvertFunctionInst *create(SILDebugLocation DebugLoc,
SILValue Operand, SILType Ty,
SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
bool WithoutActuallyEscaping);

public:
/// Returns `true` if this converts a non-escaping closure into an escaping
/// function type. `True` must be returned whenever the closure operand has an
/// unboxed capture (via @inout_aliasable) *and* the resulting function type
/// is escaping. (This only happens as a result of
/// withoutActuallyEscaping()). If `true` is returned, then the resulting
/// function type must be escaping, but the operand's function type may or may
/// not be @noescape. Note that a non-escaping closure may have unboxed
/// captured even though its SIL function type is "escaping".
bool withoutActuallyEscaping() const {
return SILInstruction::Bits.ConvertFunctionInst.WithoutActuallyEscaping;
}
};

/// ConvertEscapeToNoEscapeInst - Change the type of a escaping function value
Expand Down
3 changes: 2 additions & 1 deletion include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ class alignas(8) SILNode {
IsInvariant : 1
);

UIWTDOB_BITFIELD_EMPTY(ConvertFunctionInst, ConversionInst);
UIWTDOB_BITFIELD(ConvertFunctionInst, ConversionInst, 1,
WithoutActuallyEscaping : 1);
UIWTDOB_BITFIELD_EMPTY(PointerToThinFunctionInst, ConversionInst);
UIWTDOB_BITFIELD_EMPTY(UnconditionalCheckedCastInst, ConversionInst);
UIWTDOB_BITFIELD_EMPTY(UpcastInst, ConversionInst);
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t VERSION_MINOR = 435; // Last change: serialize new-style function parameters
const uint16_t VERSION_MINOR = 436; // Last change: without_actually_escaping.

using DeclIDField = BCFixed<31>;

Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/LoadableByAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2609,7 +2609,8 @@ void LoadableByAddress::recreateConvInstrs() {
case SILInstructionKind::ConvertFunctionInst: {
auto instr = cast<ConvertFunctionInst>(convInstr);
newInstr = convBuilder.createConvertFunction(
instr->getLoc(), instr->getOperand(), newType);
instr->getLoc(), instr->getOperand(), newType,
instr->withoutActuallyEscaping());
break;
}
case SILInstructionKind::ConvertEscapeToNoEscapeInst: {
Expand Down
41 changes: 30 additions & 11 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ static bool parseDeclSILOptional(bool *isTransparent,
Inline_t *inlineStrategy,
OptimizationMode *optimizationMode,
bool *isLet, bool *isWeakLinked,
bool *isWithoutActuallyEscapingThunk,
SmallVectorImpl<std::string> *Semantics,
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs,
ValueDecl **ClangDecl,
Expand Down Expand Up @@ -914,6 +915,9 @@ static bool parseDeclSILOptional(bool *isTransparent,
*isThunk = IsSignatureOptimizedThunk;
else if (isThunk && SP.P.Tok.getText() == "reabstraction_thunk")
*isThunk = IsReabstractionThunk;
else if (isWithoutActuallyEscapingThunk
&& SP.P.Tok.getText() == "without_actually_escaping")
*isWithoutActuallyEscapingThunk = true;
else if (isGlobalInit && SP.P.Tok.getText() == "global_init")
*isGlobalInit = true;
else if (isWeakLinked && SP.P.Tok.getText() == "_weakLinked")
Expand Down Expand Up @@ -2976,6 +2980,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
SourceLoc ToLoc;
bool not_guaranteed = false;
bool escaped = false;
bool without_actually_escaping = false;
if (Opcode == SILInstructionKind::ConvertEscapeToNoEscapeInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
Expand All @@ -2989,17 +2994,26 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
if (parseSILOptional(escaped, *this, "escaped"))
return true;
}
if (parseTypedValueRef(Val, B) ||
parseSILIdentifier(ToToken, ToLoc,
diag::expected_tok_in_sil_instr, "to") ||
parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
if (parseTypedValueRef(Val, B)
|| parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;

if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (Opcode == SILInstructionKind::ConvertFunctionInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
if (attrName.equals("without_actually_escaping"))
without_actually_escaping = true;
else
return true;
}
}
if (parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
return true;

switch (Opcode) {
default: llvm_unreachable("Out of sync with parent switch");
Expand All @@ -3019,7 +3033,8 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
ResultVal = B.createUpcast(InstLoc, Val, Ty);
break;
case SILInstructionKind::ConvertFunctionInst:
ResultVal = B.createConvertFunction(InstLoc, Val, Ty);
ResultVal =
B.createConvertFunction(InstLoc, Val, Ty, without_actually_escaping);
break;
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
ResultVal = B.createConvertEscapeToNoEscape(InstLoc, Val, Ty, escaped,
Expand Down Expand Up @@ -5186,6 +5201,7 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
bool isCanonical = false;
IsThunk_t isThunk = IsNotThunk;
bool isGlobalInit = false, isWeakLinked = false;
bool isWithoutActuallyEscapingThunk = false;
Inline_t inlineStrategy = InlineDefault;
OptimizationMode optimizationMode = OptimizationMode::NotSet;
SmallVector<std::string, 1> Semantics;
Expand All @@ -5196,7 +5212,8 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
parseDeclSILOptional(&isTransparent, &isSerialized, &isCanonical,
&isThunk, &isGlobalInit,
&inlineStrategy, &optimizationMode, nullptr,
&isWeakLinked, &Semantics, &SpecAttrs,
&isWeakLinked, &isWithoutActuallyEscapingThunk,
&Semantics, &SpecAttrs,
&ClangDecl, &MRK, FunctionState) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
Expand Down Expand Up @@ -5224,6 +5241,8 @@ bool SILParserTUState::parseDeclSIL(Parser &P) {
FunctionState.F->setThunk(IsThunk_t(isThunk));
FunctionState.F->setGlobalInit(isGlobalInit);
FunctionState.F->setWeakLinked(isWeakLinked);
FunctionState.F->setWithoutActuallyEscapingThunk(
isWithoutActuallyEscapingThunk);
FunctionState.F->setInlineStrategy(inlineStrategy);
FunctionState.F->setOptimizationMode(optimizationMode);
FunctionState.F->setEffectsKind(MRK);
Expand Down Expand Up @@ -5403,7 +5422,7 @@ bool SILParserTUState::parseSILGlobal(Parser &P) {
if (parseSILLinkage(GlobalLinkage, P) ||
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, &isLet, nullptr, nullptr, nullptr,
nullptr, nullptr, State) ||
nullptr, nullptr, nullptr, State) ||
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) ||
P.parseToken(tok::colon, diag::expected_sil_type))
Expand Down Expand Up @@ -5451,7 +5470,7 @@ bool SILParserTUState::parseSILProperty(Parser &P) {
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, SP))
nullptr, nullptr, nullptr, SP))
return true;

ValueDecl *VD;
Expand Down Expand Up @@ -5519,7 +5538,7 @@ bool SILParserTUState::parseSILVTable(Parser &P) {
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, VTableState))
nullptr, nullptr, nullptr, VTableState))
return true;

// Parse the class name.
Expand Down Expand Up @@ -5869,7 +5888,7 @@ bool SILParserTUState::parseSILWitnessTable(Parser &P) {
IsSerialized_t isSerialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, WitnessState))
nullptr, nullptr, nullptr, WitnessState))
return true;

Scope S(&P, ScopeKind::TopLevel);
Expand Down
11 changes: 5 additions & 6 deletions lib/SIL/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1971,19 +1971,18 @@ PointerToThinFunctionInst::create(SILDebugLocation DebugLoc, SILValue Operand,
TypeDependentOperands, Ty);
}

ConvertFunctionInst *
ConvertFunctionInst::create(SILDebugLocation DebugLoc, SILValue Operand,
SILType Ty, SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes) {
ConvertFunctionInst *ConvertFunctionInst::create(
SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes, bool WithoutActuallyEscaping) {
SILModule &Mod = F.getModule();
SmallVector<SILValue, 8> TypeDependentOperands;
collectTypeDependentOperands(TypeDependentOperands, OpenedArchetypes, F,
Ty.getASTType());
unsigned size =
totalSizeToAlloc<swift::Operand>(1 + TypeDependentOperands.size());
void *Buffer = Mod.allocateInst(size, alignof(ConvertFunctionInst));
auto *CFI = ::new (Buffer)
ConvertFunctionInst(DebugLoc, Operand, TypeDependentOperands, Ty);
auto *CFI = ::new (Buffer) ConvertFunctionInst(
DebugLoc, Operand, TypeDependentOperands, Ty, WithoutActuallyEscaping);
// If we do not have lowered SIL, make sure that are not performing
// ABI-incompatible conversions.
//
Expand Down
7 changes: 6 additions & 1 deletion lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
}

void visitConvertFunctionInst(ConvertFunctionInst *CI) {
printUncheckedConversionInst(CI, CI->getOperand());
*this << getIDAndType(CI->getOperand()) << " to ";
if (CI->withoutActuallyEscaping())
*this << "[without_actually_escaping] ";
*this << CI->getType();
}
void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *CI) {
*this << (CI->isLifetimeGuaranteed() ? "" : "[not_guaranteed] ")
Expand Down Expand Up @@ -2299,6 +2302,8 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
break;
case IsReabstractionThunk: OS << "[reabstraction_thunk] "; break;
}
if (isWithoutActuallyEscapingThunk())
OS << "[without_actually_escaping] ";

if (isGlobalInit())
OS << "[global_init] ";
Expand Down
11 changes: 6 additions & 5 deletions lib/SILGen/SILGenBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,13 @@ ManagedValue SILGenBuilder::createPartialApply(SILLocation loc, SILValue fn,
return getSILGenFunction().emitManagedRValueWithCleanup(result);
}

ManagedValue SILGenBuilder::createConvertFunction(SILLocation loc,
ManagedValue fn,
SILType resultTy) {
ManagedValue
SILGenBuilder::createConvertFunction(SILLocation loc, ManagedValue fn,
SILType resultTy,
bool withoutActuallyEscaping) {
CleanupCloner cloner(*this, fn);
SILValue result =
createConvertFunction(loc, fn.forward(getSILGenFunction()), resultTy);
SILValue result = SILBuilder::createConvertFunction(
loc, fn.forward(getSILGenFunction()), resultTy, withoutActuallyEscaping);
return cloner.clone(result);
}

Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/SILGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@ class SILGenBuilder : public SILBuilder {

using SILBuilder::createConvertFunction;
ManagedValue createConvertFunction(SILLocation loc, ManagedValue fn,
SILType resultTy);
SILType resultTy,
bool WithoutActuallyEscaping = false);

using SILBuilder::createConvertEscapeToNoEscape;
ManagedValue
Expand Down
Loading