@@ -1547,58 +1547,65 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
1547
1547
}
1548
1548
}
1549
1549
1550
+ bool shouldDiscard = ThrowDest.getThrownError ().Discard ;
1551
+ SILType exnType = exn->getType ().getObjectType ();
1550
1552
SILBasicBlock &throwBB = *ThrowDest.getBlock ();
1551
- if (!throwBB.getArguments ().empty ()) {
1552
- assert (exn);
1553
- assert (!indirectErrorAddr);
1554
-
1555
- auto errorArg = throwBB.getArguments ()[0 ];
1556
-
1557
- // If we don't have an existential box, create one to jump to the throw
1558
- // destination.
1559
- SILType errorArgType = errorArg->getType ();
1560
- if (exn->getType () != errorArgType) {
1561
- SILType existentialBoxType = SILType::getExceptionType (getASTContext ());
1562
- assert (errorArgType == existentialBoxType);
1563
-
1564
- // FIXME: Callers should provide this conformance from places recorded in
1565
- // the AST.
1566
- ProtocolConformanceRef conformances[1 ] = {
1567
- getModule ().getSwiftModule ()->conformsToProtocol (
1568
- exn->getType ().getASTType (), getASTContext ().getErrorDecl ())
1569
- };
1570
- exnMV = emitExistentialErasure (
1571
- loc,
1572
- exn->getType ().getASTType (),
1573
- getTypeLowering (exn->getType ()),
1574
- getTypeLowering (existentialBoxType),
1575
- getASTContext ().AllocateCopy (conformances),
1576
- SGFContext (),
1577
- [&](SGFContext C) -> ManagedValue {
1578
- return ManagedValue::forForwardedRValue (*this , exn);
1579
- });
1580
-
1581
- exn = exnMV.forward (*this );
1582
- }
1583
-
1584
- // A direct error value is passed to the epilog block as a BB argument.
1585
- args.push_back (exn);
1586
- } else if (ThrowDest.getThrownError ().Discard ) {
1587
- assert (!indirectErrorAddr);
1588
- if (exn)
1589
- B.createDestroyAddr (loc, exn);
1590
- } else {
1591
- assert (indirectErrorAddr);
1553
+ SILType destErrorType = indirectErrorAddr
1554
+ ? indirectErrorAddr->getType ().getObjectType ()
1555
+ : !throwBB.getArguments ().empty ()
1556
+ ? throwBB.getArguments ()[0 ]->getType ().getObjectType ()
1557
+ : exnType;
1558
+
1559
+ // If the thrown error type differs from what the throw destination expects,
1560
+ // perform the conversion.
1561
+ // FIXME: Can the AST tell us what to do here?
1562
+ if (exnType != destErrorType && !shouldDiscard) {
1563
+ assert (destErrorType == SILType::getExceptionType (getASTContext ()));
1564
+
1565
+ ProtocolConformanceRef conformances[1 ] = {
1566
+ getModule ().getSwiftModule ()->conformsToProtocol (
1567
+ exn->getType ().getASTType (), getASTContext ().getErrorDecl ())
1568
+ };
1569
+
1570
+ exn = emitExistentialErasure (
1571
+ loc,
1572
+ exnType.getASTType (),
1573
+ getTypeLowering (exnType),
1574
+ getTypeLowering (destErrorType),
1575
+ getASTContext ().AllocateCopy (conformances),
1576
+ SGFContext (),
1577
+ [&](SGFContext C) -> ManagedValue {
1578
+ if (exn->getType ().isAddress ()) {
1579
+ return emitLoad (loc, exn, getTypeLowering (exnType), SGFContext (),
1580
+ IsTake);
1581
+ }
1592
1582
1593
- // FIXME: opaque values
1583
+ return ManagedValue::forForwardedRValue (*this , exn);
1584
+ }).forward (*this );
1585
+ }
1586
+ assert (exn->getType ().getObjectType () == destErrorType);
1594
1587
1595
- // If an error value was provided by the caller, copy it into the
1596
- // indirect error result. Otherwise we assume the indirect error
1597
- // result has been initialized.
1598
- if (exn) {
1588
+ if (indirectErrorAddr) {
1589
+ if (exn->getType ().isAddress ()) {
1599
1590
B.createCopyAddr (loc, exn, indirectErrorAddr,
1600
1591
IsTake, IsInitialization);
1592
+ } else {
1593
+ // An indirect error is written into the destination error address.
1594
+ emitSemanticStore (loc, exn, indirectErrorAddr,
1595
+ getTypeLowering (destErrorType), IsInitialization);
1601
1596
}
1597
+ } else if (!throwBB.getArguments ().empty ()) {
1598
+ // Load if we need to.
1599
+ if (exn->getType ().isAddress ()) {
1600
+ exn = emitLoad (loc, exn, getTypeLowering (exnType), SGFContext (), IsTake)
1601
+ .forward (*this );
1602
+ }
1603
+
1604
+ // A direct error value is passed to the epilog block as a BB argument.
1605
+ args.push_back (exn);
1606
+ } else if (shouldDiscard) {
1607
+ if (exn && exn->getType ().isAddress ())
1608
+ B.createDestroyAddr (loc, exn);
1602
1609
}
1603
1610
1604
1611
// Branch to the cleanup destination.
0 commit comments