@@ -1547,58 +1547,65 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
15471547 }
15481548 }
15491549
1550+ bool shouldDiscard = ThrowDest.getThrownError ().Discard ;
1551+ SILType exnType = exn->getType ().getObjectType ();
15501552 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+ }
15921582
1593- // FIXME: opaque values
1583+ return ManagedValue::forForwardedRValue (*this , exn);
1584+ }).forward (*this );
1585+ }
1586+ assert (exn->getType ().getObjectType () == destErrorType);
15941587
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 ()) {
15991590 B.createCopyAddr (loc, exn, indirectErrorAddr,
16001591 IsTake, IsInitialization);
1592+ } else {
1593+ // An indirect error is written into the destination error address.
1594+ emitSemanticStore (loc, exn, indirectErrorAddr,
1595+ getTypeLowering (destErrorType), IsInitialization);
16011596 }
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);
16021609 }
16031610
16041611 // Branch to the cleanup destination.
0 commit comments