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