Skip to content

Commit afb0d50

Browse files
authored
Merge pull request #1847 from swiftwasm/main
[pull] swiftwasm from main
2 parents 0240f08 + d96ea28 commit afb0d50

18 files changed

+332
-94
lines changed

docs/ABI/Mangling.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ mangled in to disambiguate.
600600
impl-function-type ::= type* 'I' FUNC-ATTRIBUTES '_'
601601
impl-function-type ::= type* generic-signature 'I' FUNC-ATTRIBUTES '_'
602602

603-
FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? (PARAM-CONVENTION PARAM-DIFFERENTIABILITY?)* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION RESULT-DIFFERENTIABILITY?)?
603+
FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? ASYNC? (PARAM-CONVENTION PARAM-DIFFERENTIABILITY?)* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION RESULT-DIFFERENTIABILITY?)?
604604

605605
PATTERN-SUBS ::= 's' // has pattern substitutions
606606
INVOCATION-SUB ::= 'I' // has invocation substitutions
@@ -627,6 +627,8 @@ mangled in to disambiguate.
627627
COROUTINE-KIND ::= 'A' // yield-once coroutine
628628
COROUTINE-KIND ::= 'G' // yield-many coroutine
629629

630+
ASYNC ::= 'H' // @async
631+
630632
PARAM-CONVENTION ::= 'i' // indirect in
631633
PARAM-CONVENTION ::= 'c' // indirect in constant
632634
PARAM-CONVENTION ::= 'l' // indirect inout

include/swift/AST/Decl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -5946,7 +5946,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
59465946
/// Returns true if the function is an @asyncHandler.
59475947
bool isAsyncHandler() const;
59485948

5949-
/// Returns true if the function if the signature matches the form of an
5949+
/// Returns true if the function signature matches the form of an
59505950
/// @asyncHandler.
59515951
bool canBeAsyncHandler() const;
59525952

include/swift/Demangling/TypeDecoder.h

+2
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,8 @@ class TypeDecoder {
706706
} else if (text == "@convention(block)") {
707707
flags =
708708
flags.withRepresentation(ImplFunctionRepresentation::Block);
709+
} else if (text == "@async") {
710+
flags = flags.withAsync();
709711
}
710712
} else if (child->getKind() == NodeKind::ImplDifferentiable) {
711713
flags = flags.withDifferentiabilityKind(

include/swift/Reflection/TypeRefBuilder.h

+2
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,8 @@ class TypeRefBuilder {
443443
break;
444444
}
445445

446+
funcFlags = funcFlags.withAsync(flags.isAsync());
447+
446448
auto result = createTupleType({}, "");
447449
return FunctionTypeRef::create(*this, {}, result, funcFlags);
448450
}

lib/AST/ASTMangler.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,11 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
16891689
break;
16901690
}
16911691

1692+
// Asynchronous functions.
1693+
if (fn->isAsync()) {
1694+
OpArgs.push_back('H');
1695+
}
1696+
16921697
auto outerGenericSig = CurGenericSignature;
16931698
CurGenericSignature = fn->getSubstGenericSignature();
16941699

lib/AST/ASTVerifier.cpp

+17-17
Original file line numberDiff line numberDiff line change
@@ -1828,30 +1828,30 @@ class Verifier : public ASTWalker {
18281828
Out << "\n";
18291829
abort();
18301830
}
1831-
1831+
1832+
if (!isa<VarDecl>(E->getMember().getDecl())) {
1833+
Out << "Member reference to a non-VarDecl\n";
1834+
E->dump(Out);
1835+
Out << "\n";
1836+
abort();
1837+
}
1838+
1839+
auto baseType = E->getBase()->getType();
1840+
if (baseType->is<InOutType>()) {
1841+
Out << "Member reference to an inout type\n";
1842+
E->dump(Out);
1843+
Out << "\n";
1844+
abort();
1845+
}
1846+
18321847
// The base of a member reference cannot be an existential type.
1833-
if (E->getBase()->getType()->getWithoutSpecifierType()
1834-
->isExistentialType()) {
1848+
if (baseType->getWithoutSpecifierType()->isExistentialType()) {
18351849
Out << "Member reference into an unopened existential type\n";
18361850
E->dump(Out);
18371851
Out << "\n";
18381852
abort();
18391853
}
18401854

1841-
// The only time the base is allowed to be inout is if we are accessing
1842-
// a computed property or if the base is a protocol or existential.
1843-
if (auto *baseIOT = E->getBase()->getType()->getAs<InOutType>()) {
1844-
if (!baseIOT->getObjectType()->is<ArchetypeType>()) {
1845-
auto *VD = dyn_cast<VarDecl>(E->getMember().getDecl());
1846-
if (!VD || !VD->requiresOpaqueAccessors()) {
1847-
Out << "member_ref_expr on value of inout type\n";
1848-
E->dump(Out);
1849-
Out << "\n";
1850-
abort();
1851-
}
1852-
}
1853-
}
1854-
18551855
// FIXME: Check container/member types through substitutions.
18561856

18571857
verifyCheckedBase(E);

lib/Demangling/Demangler.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,11 @@ NodePointer Demangler::demangleImplFunctionType() {
18291829
if (CoroAttr)
18301830
type->addChild(createNode(Node::Kind::ImplFunctionAttribute, CoroAttr), *this);
18311831

1832+
if (nextIf('H')) {
1833+
type->addChild(createNode(Node::Kind::ImplFunctionAttribute, "@async"),
1834+
*this);
1835+
}
1836+
18321837
addChild(type, GenSig);
18331838

18341839
int NumTypesToAdd = 0;

lib/Demangling/OldDemangler.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,9 @@ class OldDemangler {
21482148
return nullptr;
21492149
}
21502150

2151+
if (Mangled.nextIf('H'))
2152+
addImplFunctionAttribute(type, "@async");
2153+
21512154
// Enter a new generic context if this type is generic.
21522155
// FIXME: replace with std::optional, when we have it.
21532156
bool isPseudogeneric = false;

lib/Demangling/OldRemangler.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,8 @@ void Remangler::mangleImplFunctionAttribute(Node *node) {
12551255
Buffer << "A";
12561256
} else if (text == "@yield_many") {
12571257
Buffer << "G";
1258+
} else if (text == "@async") {
1259+
Buffer << "H";
12581260
} else {
12591261
unreachable("bad impl-function-attribute");
12601262
}

lib/Demangling/Remangler.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,7 @@ void Remangler::mangleImplFunctionType(Node *node) {
15371537
.Case("@convention(witness_method)", 'W')
15381538
.Case("@yield_once", 'A')
15391539
.Case("@yield_many", 'G')
1540+
.Case("@async", 'H')
15401541
.Default(0);
15411542
assert(FuncAttr && "invalid impl function attribute");
15421543
Buffer << FuncAttr;

lib/SIL/Verifier/SILOwnershipVerifier.cpp

+56-15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define DEBUG_TYPE "sil-ownership-verifier"
1414

1515
#include "LinearLifetimeCheckerPrivate.h"
16+
1617
#include "swift/AST/ASTContext.h"
1718
#include "swift/AST/AnyFunctionRef.h"
1819
#include "swift/AST/Decl.h"
@@ -32,16 +33,20 @@
3233
#include "swift/SIL/SILBuiltinVisitor.h"
3334
#include "swift/SIL/SILDebugScope.h"
3435
#include "swift/SIL/SILFunction.h"
36+
#include "swift/SIL/SILInstruction.h"
3537
#include "swift/SIL/SILModule.h"
3638
#include "swift/SIL/SILOpenedArchetypesTracker.h"
3739
#include "swift/SIL/SILVTable.h"
3840
#include "swift/SIL/SILVisitor.h"
3941
#include "swift/SIL/TypeLowering.h"
42+
4043
#include "llvm/ADT/DenseSet.h"
4144
#include "llvm/ADT/PostOrderIterator.h"
45+
#include "llvm/ADT/SmallVector.h"
4246
#include "llvm/ADT/StringSet.h"
4347
#include "llvm/Support/CommandLine.h"
4448
#include "llvm/Support/Debug.h"
49+
4550
#include <algorithm>
4651

4752
using namespace swift;
@@ -130,10 +135,11 @@ class SILValueOwnershipChecker {
130135
bool gatherNonGuaranteedUsers(SmallVectorImpl<Operand *> &lifetimeEndingUsers,
131136
SmallVectorImpl<Operand *> &regularUsers);
132137

133-
bool checkValueWithoutLifetimeEndingUses();
138+
bool checkValueWithoutLifetimeEndingUses(ArrayRef<Operand *> regularUsers);
134139

135140
bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *arg);
136-
bool checkYieldWithoutLifetimeEndingUses(BeginApplyResult *yield);
141+
bool checkYieldWithoutLifetimeEndingUses(BeginApplyResult *yield,
142+
ArrayRef<Operand *> regularUsers);
137143

138144
bool isGuaranteedFunctionArgWithLifetimeEndingUses(
139145
SILFunctionArgument *arg,
@@ -501,25 +507,56 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses(
501507
}
502508

503509
bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses(
504-
BeginApplyResult *yield) {
510+
BeginApplyResult *yield, ArrayRef<Operand *> regularUses) {
505511
switch (yield->getOwnershipKind()) {
506-
case ValueOwnershipKind::Guaranteed:
507512
case ValueOwnershipKind::Unowned:
508513
case ValueOwnershipKind::None:
509514
return true;
510515
case ValueOwnershipKind::Owned:
516+
if (deadEndBlocks.isDeadEnd(yield->getParent()->getParent()))
517+
return true;
518+
519+
return !errorBuilder.handleMalformedSIL([&] {
520+
llvm::errs() << "Owned yield without life ending uses!\n"
521+
<< "Value: " << *yield << '\n';
522+
});
523+
case ValueOwnershipKind::Guaranteed:
524+
// NOTE: If we returned false here, we would catch any error caught below as
525+
// an out of lifetime use of the yielded value. That being said, that would
526+
// be confusing from a code perspective since we would be validating
527+
// something that did not have a /real/ lifetime ending use (one could
528+
// consider the end_apply to be a pseudo-lifetime ending uses) along a code
529+
// path that is explicitly trying to do that.
511530
break;
512531
}
513532

514-
if (deadEndBlocks.isDeadEnd(yield->getParent()->getParent()))
533+
// If we have a guaranteed value, make sure that all uses are before our
534+
// end_yield.
535+
SmallVector<Operand *, 4> coroutineEndUses;
536+
for (auto *use : yield->getParent()->getTokenResult()->getUses()) {
537+
coroutineEndUses.push_back(use);
538+
}
539+
540+
assert(visitedBlocks.empty());
541+
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
542+
auto linearLifetimeResult =
543+
checker.checkValue(yield, coroutineEndUses, regularUses, errorBuilder);
544+
if (linearLifetimeResult.getFoundError()) {
545+
// We return true here even if we find an error since we want to only emit
546+
// this error for the value rather than continue and go down the "has
547+
// consuming use" path. This is to work around any confusion that maybe
548+
// caused by end_apply/abort_apply acting as a pseudo-ending lifetime use.
549+
result = true;
515550
return true;
551+
}
516552

517-
return !errorBuilder.handleMalformedSIL([&] {
518-
llvm::errs() << "Owned yield without life ending uses!\n"
519-
<< "Value: " << *yield << '\n';
520-
});
553+
// Otherwise, we do not set result to have a value and return since all of our
554+
// guaranteed value's uses are appropriate.
555+
return true;
521556
}
522-
bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
557+
558+
bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses(
559+
ArrayRef<Operand *> regularUses) {
523560
LLVM_DEBUG(llvm::dbgs() << "No lifetime ending users?! Bailing early.\n");
524561
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
525562
if (checkFunctionArgWithoutLifetimeEndingUses(arg)) {
@@ -528,9 +565,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
528565
}
529566

530567
if (auto *yield = dyn_cast<BeginApplyResult>(value)) {
531-
if (checkYieldWithoutLifetimeEndingUses(yield)) {
532-
return true;
533-
}
568+
return checkYieldWithoutLifetimeEndingUses(yield, regularUses);
534569
}
535570

536571
// Check if we are a guaranteed subobject. In such a case, we should never
@@ -622,6 +657,7 @@ bool SILValueOwnershipChecker::checkUses() {
622657
// 1. A trivial typed value.
623658
// 2. An address type value.
624659
// 3. A guaranteed function argument.
660+
// 4. A yielded guaranteed value.
625661
//
626662
// In the first two cases, it is easy to see that there is nothing further to
627663
// do but return false.
@@ -630,8 +666,13 @@ bool SILValueOwnershipChecker::checkUses() {
630666
// more. Specifically, we should have /no/ lifetime ending uses of a
631667
// guaranteed function argument, since a guaranteed function argument should
632668
// outlive the current function always.
633-
if (lifetimeEndingUsers.empty() && checkValueWithoutLifetimeEndingUses()) {
634-
return false;
669+
//
670+
// In the case of a yielded guaranteed value, we need to validate that all
671+
// regular uses of the value are within the co
672+
if (lifetimeEndingUsers.empty()) {
673+
if (checkValueWithoutLifetimeEndingUses(regularUsers))
674+
return false;
675+
return true;
635676
}
636677

637678
LLVM_DEBUG(llvm::dbgs() << " Found lifetime ending users! Performing "

lib/Sema/BuilderTransform.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1979,7 +1979,8 @@ void swift::printFunctionBuilderBuildFunction(
19791979
componentTypeString = "<#Component#>";
19801980

19811981
// Render the code.
1982-
ExtraIndentStreamPrinter printer(out, stubIndent.getValueOr(std::string()));
1982+
std::string stubIndentStr = stubIndent.getValueOr(std::string());
1983+
ExtraIndentStreamPrinter printer(out, stubIndentStr);
19831984

19841985
// If we're supposed to provide a full stub, add a newline and the introducer
19851986
// keywords.

0 commit comments

Comments
 (0)