Skip to content

Commit 338825e

Browse files
committed
Fix the emission of r-value pointer conversions to delay the
conversions and extend lifetimes over the call. Apply this logic to string-to-pointer conversions as well as array-to-pointer conversions. Fix the AST verifier to not blow up on optional pointer conversions, and make sure we SILGen them correctly. There's still an AST bug here, but I'll fix that in a follow-up patch.
1 parent f080183 commit 338825e

10 files changed

+853
-229
lines changed

include/swift/SIL/SILType.h

+3
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ class SILType {
521521
/// Get the builtin word type as a SILType;
522522
static SILType getBuiltinWordType(const ASTContext &C);
523523

524+
/// Given a value type, return an optional type wrapping it.
525+
static SILType getOptionalType(SILType valueType);
526+
524527
/// Get the standard exception type.
525528
static SILType getExceptionType(const ASTContext &C);
526529

lib/AST/ASTVerifier.cpp

+42-8
Original file line numberDiff line numberDiff line change
@@ -1361,19 +1361,53 @@ class Verifier : public ASTWalker {
13611361
}
13621362

13631363
void updateExprToPointerWhitelist(Expr *Base, Expr *Arg) {
1364-
auto handleSubExpr = [&](Expr *SubExpr) {
1365-
// if we have an inject into optional, strip it off.
1366-
if (auto *InjectIntoOpt = dyn_cast<InjectIntoOptionalExpr>(SubExpr)) {
1367-
SubExpr = InjectIntoOpt->getSubExpr();
1364+
auto handleSubExpr = [&](Expr *origSubExpr) {
1365+
auto subExpr = origSubExpr;
1366+
unsigned optionalDepth = 0;
1367+
1368+
auto checkIsBindOptional = [&](Expr *expr) {
1369+
for (unsigned depth = optionalDepth; depth; --depth) {
1370+
if (auto bind = dyn_cast<BindOptionalExpr>(expr)) {
1371+
expr = bind->getSubExpr();
1372+
} else {
1373+
Out << "malformed optional pointer conversion\n";
1374+
origSubExpr->print(Out);
1375+
Out << '\n';
1376+
abort();
1377+
}
1378+
}
1379+
};
1380+
1381+
// These outer entities will be interleaved in multi-level optionals.
1382+
while (true) {
1383+
// Look through optional evaluations.
1384+
if (auto *optionalEval = dyn_cast<OptionalEvaluationExpr>(subExpr)) {
1385+
subExpr = optionalEval->getSubExpr();
1386+
optionalDepth++;
1387+
continue;
1388+
}
1389+
1390+
// Look through injections into Optional<Pointer>.
1391+
if (auto *injectIntoOpt = dyn_cast<InjectIntoOptionalExpr>(subExpr)) {
1392+
subExpr = injectIntoOpt->getSubExpr();
1393+
continue;
1394+
}
1395+
1396+
break;
13681397
}
13691398

1370-
if (auto *InOutToPtr = dyn_cast<InOutToPointerExpr>(SubExpr)) {
1371-
WhitelistedInOutToPointerExpr.insert(InOutToPtr);
1399+
// Whitelist inout-to-pointer conversions.
1400+
if (auto *inOutToPtr = dyn_cast<InOutToPointerExpr>(subExpr)) {
1401+
WhitelistedInOutToPointerExpr.insert(inOutToPtr);
1402+
checkIsBindOptional(inOutToPtr->getSubExpr());
13721403
return;
13731404
}
13741405

1375-
if (auto *ArrayToPtr = dyn_cast<ArrayToPointerExpr>(SubExpr)) {
1376-
WhitelistedArrayToPointerExpr.insert(ArrayToPtr);
1406+
// Whitelist array-to-pointer conversions.
1407+
if (auto *arrayToPtr = dyn_cast<ArrayToPointerExpr>(subExpr)) {
1408+
WhitelistedArrayToPointerExpr.insert(arrayToPtr);
1409+
checkIsBindOptional(arrayToPtr->getSubExpr());
1410+
return;
13771411
}
13781412
};
13791413

lib/SIL/SILType.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ SILType SILType::getBuiltinWordType(const ASTContext &C) {
6464
return getPrimitiveObjectType(CanType(BuiltinIntegerType::getWordType(C)));
6565
}
6666

67+
SILType SILType::getOptionalType(SILType type) {
68+
auto &ctx = type.getSwiftRValueType()->getASTContext();
69+
auto optType = BoundGenericEnumType::get(ctx.getOptionalDecl(), Type(),
70+
{ type.getSwiftRValueType() });
71+
return getPrimitiveType(CanType(optType), type.getCategory());
72+
}
73+
6774
bool SILType::isTrivial(SILModule &M) const {
6875
return M.getTypeLowering(*this).isTrivial();
6976
}

lib/SILGen/ManagedValue.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,26 @@ ManagedValue ManagedValue::formalAccessBorrow(SILGenFunction &SGF,
145145
return SGF.emitFormalEvaluationManagedBeginBorrow(loc, getValue());
146146
}
147147

148+
ManagedValue ManagedValue::materialize(SILGenFunction &SGF,
149+
SILLocation loc) const {
150+
auto temporary = SGF.emitTemporaryAllocation(loc, getType());
151+
bool hadCleanup = hasCleanup();
152+
153+
// The temporary memory is +0 if the value was.
154+
if (hadCleanup) {
155+
SGF.B.emitStoreValueOperation(loc, forward(SGF), temporary,
156+
StoreOwnershipQualifier::Init);
157+
158+
// SEMANTIC SIL TODO: This should really be called a temporary LValue.
159+
return ManagedValue::forOwnedAddressRValue(temporary,
160+
SGF.enterDestroyCleanup(temporary));
161+
} else {
162+
auto object = SGF.emitManagedBeginBorrow(loc, getValue());
163+
SGF.emitManagedStoreBorrow(loc, object.getValue(), temporary);
164+
return ManagedValue::forBorrowedAddressRValue(temporary);
165+
}
166+
}
167+
148168
void ManagedValue::print(raw_ostream &os) const {
149169
if (SILValue v = getValue()) {
150170
v->print(os);

lib/SILGen/ManagedValue.h

+4
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ class ManagedValue {
270270
return isLValue() ? *this : ManagedValue::forUnmanaged(getValue());
271271
}
272272

273+
/// Given a scalar value, materialize it into memory with the
274+
/// exact same level of cleanup it had before.
275+
ManagedValue materialize(SILGenFunction &SGF, SILLocation loc) const;
276+
273277
/// Disable the cleanup for this value.
274278
void forwardCleanup(SILGenFunction &SGF) const;
275279

0 commit comments

Comments
 (0)