@@ -667,6 +667,8 @@ void swift::conformToCxxOptionalIfNeeded(
667667 assert (decl);
668668 assert (clangDecl);
669669 ASTContext &ctx = decl->getASTContext ();
670+ clang::ASTContext &clangCtx = impl.getClangASTContext ();
671+ clang::Sema &clangSema = impl.getClangSema ();
670672
671673 if (!isStdDecl (clangDecl, {" optional" }))
672674 return ;
@@ -689,6 +691,64 @@ void swift::conformToCxxOptionalIfNeeded(
689691
690692 impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Wrapped" ), pointeeTy);
691693 impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxOptional});
694+
695+ // `std::optional` has a C++ constructor that takes the wrapped value as a
696+ // parameter. Unfortunately this constructor has templated parameter type, so
697+ // it isn't directly usable from Swift. Let's explicitly instantiate a
698+ // constructor with the wrapped value type, and then import it into Swift.
699+
700+ auto valueTypeDecl = lookupNestedClangTypeDecl (clangDecl, " value_type" );
701+ if (!valueTypeDecl)
702+ // `std::optional` without a value_type?!
703+ return ;
704+ auto valueType = clangCtx.getTypeDeclType (valueTypeDecl);
705+
706+ auto constRefValueType =
707+ clangCtx.getLValueReferenceType (valueType.withConst ());
708+ // Create a fake variable with type of the wrapped value.
709+ auto fakeValueVarDecl = clang::VarDecl::Create (
710+ clangCtx, /* DC*/ clangCtx.getTranslationUnitDecl (),
711+ clang::SourceLocation (), clang::SourceLocation (), /* Id*/ nullptr ,
712+ constRefValueType, clangCtx.getTrivialTypeSourceInfo (constRefValueType),
713+ clang::StorageClass::SC_None);
714+ auto fakeValueRefExpr = new (clangCtx) clang::DeclRefExpr (
715+ clangCtx, fakeValueVarDecl, false ,
716+ constRefValueType.getNonReferenceType (), clang::ExprValueKind::VK_LValue,
717+ clang::SourceLocation ());
718+
719+ auto clangDeclTyInfo = clangCtx.getTrivialTypeSourceInfo (
720+ clang::QualType (clangDecl->getTypeForDecl (), 0 ));
721+ SmallVector<clang::Expr *, 1 > constructExprArgs = {fakeValueRefExpr};
722+
723+ // Instantiate the templated constructor that would accept this fake variable.
724+ clang::Sema::SFINAETrap trap (clangSema);
725+ auto constructExprResult = clangSema.BuildCXXTypeConstructExpr (
726+ clangDeclTyInfo, clangDecl->getLocation (), constructExprArgs,
727+ clangDecl->getLocation (), /* ListInitialization*/ false );
728+ if (!constructExprResult.isUsable () || trap.hasErrorOccurred ())
729+ return ;
730+
731+ auto castExpr = dyn_cast_or_null<clang::CastExpr>(constructExprResult.get ());
732+ if (!castExpr)
733+ return ;
734+
735+ // The temporary bind expression will only be present for some non-trivial C++
736+ // types.
737+ auto bindTempExpr =
738+ dyn_cast_or_null<clang::CXXBindTemporaryExpr>(castExpr->getSubExpr ());
739+
740+ auto constructExpr = dyn_cast_or_null<clang::CXXConstructExpr>(
741+ bindTempExpr ? bindTempExpr->getSubExpr () : castExpr->getSubExpr ());
742+ if (!constructExpr)
743+ return ;
744+
745+ auto constructorDecl = constructExpr->getConstructor ();
746+
747+ auto importedConstructor =
748+ impl.importDecl (constructorDecl, impl.CurrentVersion );
749+ if (!importedConstructor)
750+ return ;
751+ decl->addMember (importedConstructor);
692752}
693753
694754void swift::conformToCxxSequenceIfNeeded (
0 commit comments