From e0b0f8bfd589e32e8198e1c056fe471c7d083e1e Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Fri, 31 Jan 2020 08:52:45 -0800 Subject: [PATCH] [5.2] SILGen: Fix withoutActuallyEscaping of 'c' closures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They don't have a context and therefore are not consumed. Fixes a failing assert. * Description: The compiler asserts on code that uses withoutActuallyEscaping on a ā€˜c’ convention closure. * Scope: Compiling source code that uses that combination will assert and fail to compile. In no asserts build the compilation succeeds and generates correct code (i.e the assert failure is inconsequential). The problem existed in previously released version of the compiler. * Testing: A swift regression test was added. * Reviewed: Andrew T Original PR: #29569 rdar://59046275 --- lib/SILGen/SILGenExpr.cpp | 12 ++++++++---- test/SILGen/without_actually_escaping.swift | 13 +++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 83711be6d8ae9..29a3845a05c03 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -5024,13 +5024,17 @@ RValue RValueEmitter::visitMakeTemporarilyEscapableExpr( return visit(E->getSubExpr(), C); }; - // Handle @convention(block). No withoutActuallyEscaping verification yet. - if (silFnTy->getExtInfo().getRepresentation() != - SILFunctionTypeRepresentation::Thick) { + // Handle @convention(block) an @convention(c). No withoutActuallyEscaping + // verification yet. + auto closureRepresentation = silFnTy->getExtInfo().getRepresentation(); + if (closureRepresentation != SILFunctionTypeRepresentation::Thick) { auto escapingClosure = SGF.B.createConvertFunction(E, functionValue, escapingFnTy, /*WithoutActuallyEscaping=*/true); - return visitSubExpr(escapingClosure, true /*isClosureConsumable*/); + bool isBlockConvention = + closureRepresentation == SILFunctionTypeRepresentation::Block; + return visitSubExpr(escapingClosure, + isBlockConvention /*isClosureConsumable*/); } // Convert it to an escaping function value. diff --git a/test/SILGen/without_actually_escaping.swift b/test/SILGen/without_actually_escaping.swift index 2979157df33b5..1d5e1569e627e 100644 --- a/test/SILGen/without_actually_escaping.swift +++ b/test/SILGen/without_actually_escaping.swift @@ -100,3 +100,16 @@ func withoutActuallyEscapingConflict() { modifyAndPerform(&localVar, closure: $0) } } + +// CHECK-LABEL: sil [ossa] @$s25without_actually_escaping0A25ActuallyEscapingCFunction8functionyyyXC_tF +// CHECK: bb0([[ARG:%.*]] : $@convention(c) @noescape () -> ()): +// CHECK: [[E:%.*]] = convert_function [[ARG]] : $@convention(c) @noescape () -> () to [without_actually_escaping] $@convention(c) () -> () +// CHECK: [[F:%.*]] = function_ref @$s25without_actually_escaping0A25ActuallyEscapingCFunction8functionyyyXC_tFyyyXCXEfU_ : $@convention(thin) (@convention(c) () -> ()) -> () +// CHECK: apply [[F]]([[E]]) : $@convention(thin) (@convention(c) () -> ()) -> () +public func withoutActuallyEscapingCFunction(function: (@convention(c) () -> Void)) { + withoutActuallyEscaping(function) { f in + var pointer: UnsafeRawPointer? = nil + pointer = unsafeBitCast(f, to: UnsafeRawPointer.self) + print(pointer) + } +}