Skip to content

[SILGen] Output a different message for failed IUO force-unwraps #17826

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 3 commits into from
Jul 20, 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
2 changes: 2 additions & 0 deletions lib/SILGen/Conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Conversion {
BridgeToObjC,

/// A bridging conversion to a foreign type following a force.
/// Although it's not reflected in the name, this is always an
/// implicit force cast.
ForceAndBridgeToObjC,

/// A bridging conversion from a foreign type.
Expand Down
25 changes: 20 additions & 5 deletions lib/SILGen/SILGenConvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ auto SILGenFunction::emitSourceLocationArgs(SourceLoc sourceLoc,

ManagedValue
SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
ManagedValue optional) {
ManagedValue optional,
bool isImplicitUnwrap) {
// Generate code to the optional is present, and if not, abort with a message
// (provided by the stdlib).
SILBasicBlock *contBB = createBasicBlock();
Expand Down Expand Up @@ -217,12 +218,19 @@ SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
getASTContext().getDiagnoseUnexpectedNilOptional(nullptr)) {
auto args = emitSourceLocationArgs(loc.getSourceLoc(), loc);

auto i1Ty = SILType::getBuiltinIntegerType(1, getASTContext());
auto isImplicitUnwrapLiteral =
B.createIntegerLiteral(loc, i1Ty, isImplicitUnwrap);
auto isImplicitUnwrapValue =
ManagedValue::forUnmanaged(isImplicitUnwrapLiteral);

emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, SubstitutionMap(),
{
args.filenameStartPointer,
args.filenameLength,
args.filenameIsAscii,
args.line
args.line,
isImplicitUnwrapValue
},
SGFContext());
}
Expand Down Expand Up @@ -268,10 +276,11 @@ SILValue SILGenFunction::emitDoesOptionalHaveValue(SILLocation loc,

ManagedValue SILGenFunction::emitCheckedGetOptionalValueFrom(SILLocation loc,
ManagedValue src,
bool isImplicitUnwrap,
const TypeLowering &optTL,
SGFContext C) {
// TODO: Make this take optTL.
return emitPreconditionOptionalHasValue(loc, src);
return emitPreconditionOptionalHasValue(loc, src, isImplicitUnwrap);
}

ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(
Expand Down Expand Up @@ -1103,7 +1112,9 @@ ManagedValue Conversion::emit(SILGenFunction &SGF, SILLocation loc,
case ForceAndBridgeToObjC: {
auto &tl = SGF.getTypeLowering(value.getType());
auto sourceValueType = getBridgingSourceType().getOptionalObjectType();
value = SGF.emitCheckedGetOptionalValueFrom(loc, value, tl, SGFContext());
value = SGF.emitCheckedGetOptionalValueFrom(loc, value,
/*isImplicitUnwrap*/ true,
tl, SGFContext());
return SGF.emitNativeToBridgedValue(loc, value, sourceValueType,
getBridgingResultType(),
getBridgingLoweredResultType(), C);
Expand Down Expand Up @@ -1438,7 +1449,11 @@ Lowering::emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,

auto value = produceOrigValue(SGF, loc, SGFContext());
auto &optTL = SGF.getTypeLowering(value.getType());
return SGF.emitCheckedGetOptionalValueFrom(loc, value, optTL, C);
// isForceUnwrap is hardcoded true because hint.isForced() is only
// set by implicit force unwraps.
return SGF.emitCheckedGetOptionalValueFrom(loc, value,
/*isForceUnwrap*/ true,
optTL, C);
};

auto getBridgingSourceType = [&] {
Expand Down
10 changes: 7 additions & 3 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5165,7 +5165,9 @@ RValue RValueEmitter::emitForceValue(ForceValueExpr *loc, Expr *E,
// If this is an implicit force of an ImplicitlyUnwrappedOptional,
// and we're emitting into an unbridging conversion, try adjusting the
// context.
if (loc->isImplicit() && loc->isForceOfImplicitlyUnwrappedOptional()) {
bool isImplicitUnwrap = loc->isImplicit() &&
loc->isForceOfImplicitlyUnwrappedOptional();
if (isImplicitUnwrap) {
if (auto conv = C.getAsConversion()) {
if (auto adjusted = conv->getConversion().adjustForInitialForceValue()) {
auto value =
Expand All @@ -5182,7 +5184,7 @@ RValue RValueEmitter::emitForceValue(ForceValueExpr *loc, Expr *E,
const TypeLowering &optTL = SGF.getTypeLowering(E->getType());
ManagedValue opt = SGF.emitRValueAsSingleValue(E);
ManagedValue V =
SGF.emitCheckedGetOptionalValueFrom(loc, opt, optTL, C);
SGF.emitCheckedGetOptionalValueFrom(loc, opt, isImplicitUnwrap, optTL, C);
return RValue(SGF, loc, valueType->getCanonicalType(), V);
}

Expand Down Expand Up @@ -5695,8 +5697,10 @@ void SILGenFunction::emitIgnoredExpr(Expr *E) {

for (auto &FVE : reversed(forceValueExprs)) {
const TypeLowering &optTL = getTypeLowering(FVE->getSubExpr()->getType());
bool isImplicitUnwrap = FVE->isImplicit() &&
FVE->isForceOfImplicitlyUnwrappedOptional();
value = emitCheckedGetOptionalValueFrom(
FVE, value, optTL, SGFContext::AllowImmediatePlusZero);
FVE, value, isImplicitUnwrap, optTL, SGFContext::AllowImmediatePlusZero);
}
return;
}
Expand Down
4 changes: 3 additions & 1 deletion lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,13 +810,15 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
/// _diagnoseUnexpectedNilOptional if the optional has no value. Return the
/// MangedValue resulting from the success case.
ManagedValue emitPreconditionOptionalHasValue(SILLocation loc,
ManagedValue optional);
ManagedValue optional,
bool isImplicitUnwrap);

/// \brief Emit a call to the library intrinsic _getOptionalValue
/// given the address of the optional, which checks that an optional contains
/// some value and either returns the value or traps if there is none.
ManagedValue emitCheckedGetOptionalValueFrom(SILLocation loc,
ManagedValue addr,
bool isImplicitUnwrap,
const TypeLowering &optTL,
SGFContext C);

Expand Down
15 changes: 10 additions & 5 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,19 +688,22 @@ namespace {
/// A physical path component which force-projects the address of
/// the value of an optional l-value.
class ForceOptionalObjectComponent : public PhysicalPathComponent {
bool isImplicitUnwrap;
public:
ForceOptionalObjectComponent(LValueTypeData typeData)
: PhysicalPathComponent(typeData, OptionalObjectKind) {}
ForceOptionalObjectComponent(LValueTypeData typeData,
bool isImplicitUnwrap)
: PhysicalPathComponent(typeData, OptionalObjectKind),
isImplicitUnwrap(isImplicitUnwrap) {}

ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
AccessKind accessKind) && override {
// Assert that the optional value is present and return the projected out
// payload.
return SGF.emitPreconditionOptionalHasValue(loc, base);
return SGF.emitPreconditionOptionalHasValue(loc, base, isImplicitUnwrap);
}

void dump(raw_ostream &OS, unsigned indent) const override {
OS.indent(indent) << "ForceOptionalObjectComponent()\n";
OS.indent(indent) << "ForceOptionalObjectComponent(" << isImplicitUnwrap << ")\n";
}
};

Expand Down Expand Up @@ -3004,7 +3007,9 @@ LValue SILGenLValue::visitForceValueExpr(ForceValueExpr *e,
LValue lv = visitRec(e->getSubExpr(), accessKind,
options.forComputedBaseLValue());
LValueTypeData typeData = getOptionalObjectTypeData(SGF, lv.getTypeData());
lv.add<ForceOptionalObjectComponent>(typeData);
bool isImplicitUnwrap = e->isImplicit() &&
e->isForceOfImplicitlyUnwrappedOptional();
lv.add<ForceOptionalObjectComponent>(typeData, isImplicitUnwrap);
return lv;
}

Expand Down
4 changes: 4 additions & 0 deletions lib/SILGen/SILGenPoly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,11 @@ ManagedValue Transform::transform(ManagedValue v,
// optional or Any, force it.
if (inputIsOptional && !outputIsOptional &&
!outputSubstType->isExistentialType()) {
// isImplicitUnwrap is hardcoded true because the looseness in types of
// @objc witnesses/overrides that we're handling here only allows IUOs,
// not explicit Optionals.
v = SGF.emitCheckedGetOptionalValueFrom(Loc, v,
/*isImplicitUnwrap*/ true,
SGF.getTypeLowering(v.getType()),
SGFContext());

Expand Down
37 changes: 27 additions & 10 deletions stdlib/private/StdlibUnittest/StdlibUnittest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -819,17 +819,17 @@ public func expectNotNil<T>(_ value: T?,
return value
}

public func expectCrashLater() {
public func expectCrashLater(withMessage message: String = "") {
print("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed)")

var stderr = _Stderr()
print("\(_stdlibUnittestStreamPrefix);expectCrash", to: &stderr)
print("\(_stdlibUnittestStreamPrefix);expectCrash;\(message)", to: &stderr)

_seenExpectCrash = true
}

public func expectCrash(executing: () -> Void) -> Never {
expectCrashLater()
public func expectCrash(withMessage message: String = "", executing: () -> Void) -> Never {
expectCrashLater(withMessage: message)
executing()
expectUnreachable()
fatalError()
Expand Down Expand Up @@ -1080,6 +1080,7 @@ struct _ParentProcess {

var stdoutSeenCrashDelimiter = false
var stderrSeenCrashDelimiter = false
var expectingPreCrashMessage = ""
var stdoutEnd = false
var stderrEnd = false
var capturedCrashStdout: [Substring] = []
Expand All @@ -1090,14 +1091,16 @@ struct _ParentProcess {
var line = line[...]
if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage =
line[index..<line.endIndex].split(separator: ";")
line[index..<line.endIndex].split(separator: ";",
omittingEmptySubsequences: false)
switch controlMessage[1] {
case "expectCrash":
if isStdout {
stdoutSeenCrashDelimiter = true
anyExpectFailedInChild = controlMessage[2] == "true"
} else {
stderrSeenCrashDelimiter = true
expectingPreCrashMessage = String(controlMessage[2])
}
case "end":
if isStdout {
Expand All @@ -1114,6 +1117,11 @@ struct _ParentProcess {
return (done: stdoutEnd && stderrEnd, ())
}
}
if !expectingPreCrashMessage.isEmpty
&& findSubstring(line, expectingPreCrashMessage) != nil {
line = "OK: saw expected pre-crash message in \"\(line)\""[...]
expectingPreCrashMessage = ""
}
if isStdout {
if stdoutSeenCrashDelimiter {
capturedCrashStdout.append(line)
Expand All @@ -1122,7 +1130,16 @@ struct _ParentProcess {
if stderrSeenCrashDelimiter {
capturedCrashStderr.append(line)
if findSubstring(line, _crashedPrefix) != nil {
line = "OK: saw expected \"\(line.lowercased())\""[...]
if !expectingPreCrashMessage.isEmpty {
line = """
FAIL: saw expected "\(line.lowercased())", but without \
message "\(expectingPreCrashMessage)" before it
"""[...]
anyExpectFailedInChild = true
}
else {
line = "OK: saw expected \"\(line.lowercased())\""[...]
}
}
}
}
Expand Down Expand Up @@ -1152,8 +1169,8 @@ struct _ParentProcess {
}
return (
anyExpectFailedInChild,
stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status,
capturedCrashStdout, capturedCrashStderr)
stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter,
status, capturedCrashStdout, capturedCrashStderr)
}

// We reached EOF on stdout and stderr and we did not see "end" markers, so
Expand All @@ -1163,8 +1180,8 @@ struct _ParentProcess {
let status = _waitForChild()
return (
anyExpectFailedInChild,
stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status,
capturedCrashStdout, capturedCrashStderr)
stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter,
status, capturedCrashStdout, capturedCrashStderr)
}

internal mutating func _shutdownChild() -> (failed: Bool, Void) {
Expand Down
7 changes: 5 additions & 2 deletions stdlib/public/core/Optional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,12 @@ public // COMPILER_INTRINSIC
func _diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
_filenameLength: Builtin.Word,
_filenameIsASCII: Builtin.Int1,
_line: Builtin.Word) {
_line: Builtin.Word,
_isImplicitUnwrap: Builtin.Int1) {
_preconditionFailure(
"Unexpectedly found nil while unwrapping an Optional value",
Bool(_isImplicitUnwrap)
? "Unexpectedly found nil while implicitly unwrapping an Optional value"
: "Unexpectedly found nil while unwrapping an Optional value",
file: StaticString(_start: _filenameStart,
utf8CodeUnitCount: _filenameLength,
isASCII: _filenameIsASCII),
Expand Down
16 changes: 8 additions & 8 deletions test/SILGen/objc_bridging_peephole.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func testNonNullMethodResult(dummy: DummyClass) {
// CHECK-NEXT: switch_enum [[RESULT]]
//
// CHECK: bb1:
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb2([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
// CHECK: [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
Expand All @@ -86,7 +86,7 @@ func testNonNullMethodResult(dummy: DummyClass) {
// CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK-NEXT: switch_enum [[RESULT]]
// CHECK: bb3:
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb4([[RESULT:%.*]] : @owned $NSString):
// CHECK-NEXT: [[ANYOBJECT:%.*]] = init_existential_ref [[RESULT]] : $NSString : $NSString, $AnyObject
// CHECK-NEXT: [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
Expand All @@ -104,7 +104,7 @@ func testForcedMethodResult(dummy: DummyClass) {
// CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK-NEXT: switch_enum [[RESULT]]
// CHECK: bb1:
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb2([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
// CHECK: [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
Expand Down Expand Up @@ -197,7 +197,7 @@ func testNonNullPropertyValue(dummy: DummyClass) {
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK: switch_enum [[RESULT]]
// CHECK: bb1:
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb2([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
// CHECK: [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
Expand All @@ -208,7 +208,7 @@ func testNonNullPropertyValue(dummy: DummyClass) {
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK: switch_enum [[RESULT]]
// CHECK: bb3:
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb4([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[RESULT]] : $NSString : $NSString, $AnyObject
// CHECK: [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
Expand All @@ -226,7 +226,7 @@ func testForcedPropertyValue(dummy: DummyClass) {
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK: switch_enum [[RESULT]]
// CHECK: bb1:
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb2([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
// CHECK: [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
Expand Down Expand Up @@ -281,7 +281,7 @@ func testNonnullSubscriptGet(object: NonnullSubscript, index: AnyObject) {
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
// CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
// CHECK-NEXT: switch_enum [[RESULT]]
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb{{[0-9]+}}([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
// CHECK: [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
Expand Down Expand Up @@ -326,7 +326,7 @@ func testNullproneSubscriptGet(object: NullproneSubscript, index: AnyObject) {
// CHECK: [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
// CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
// CHECK-NEXT: switch_enum [[RESULT]]
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
// CHECK: function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_line17_isImplicitUnwrapyBp_BwBi1_BwBi1_tF
// CHECK: bb{{[0-9]+}}([[RESULT:%.*]] : @owned $NSString):
// CHECK: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
// CHECK: [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
Expand Down
9 changes: 9 additions & 0 deletions test/SILGen/objc_witnesses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ extension Gizmo : Bells {
// CHECK: [[INIT:%[0-9]+]] = function_ref @$SSo5GizmoC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Int, @thick Gizmo.Type) -> @owned Optional<Gizmo>
// CHECK: [[IUO_RESULT:%[0-9]+]] = apply [[INIT]]([[I]], [[META]]) : $@convention(method) (Int, @thick Gizmo.Type) -> @owned Optional<Gizmo>
// CHECK: switch_enum [[IUO_RESULT]]
// CHECK: bb1:
// CHECK-NEXT: [[FILESTR:%.*]] = string_literal utf8 "
// CHECK-NEXT: [[FILESIZ:%.*]] = integer_literal $Builtin.Word,
// CHECK-NEXT: [[FILEASC:%.*]] = integer_literal $Builtin.Int1,
// CHECK-NEXT: [[LINE:%.*]] = integer_literal $Builtin.Word,
// CHECK-NEXT: [[COLUMN:%.*]] = integer_literal $Builtin.Word,
// CHECK-NEXT: [[IMPLICIT:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK: [[PRECOND:%.*]] = function_ref @$Ss30_diagnoseUnexpectedNilOptional{{[_0-9a-zA-Z]*}}F
// CHECK: apply [[PRECOND]]([[FILESTR]], [[FILESIZ]], [[FILEASC]], [[LINE]], [[IMPLICIT]])
// CHECK: bb2([[UNWRAPPED_RESULT:%.*]] : @owned $Gizmo):
// CHECK: store [[UNWRAPPED_RESULT]] to [init] [[SELF]] : $*Gizmo

Expand Down
Loading