@@ -667,6 +667,8 @@ void swift::conformToCxxOptionalIfNeeded(
667
667
assert (decl);
668
668
assert (clangDecl);
669
669
ASTContext &ctx = decl->getASTContext ();
670
+ clang::ASTContext &clangCtx = impl.getClangASTContext ();
671
+ clang::Sema &clangSema = impl.getClangSema ();
670
672
671
673
if (!isStdDecl (clangDecl, {" optional" }))
672
674
return ;
@@ -689,6 +691,64 @@ void swift::conformToCxxOptionalIfNeeded(
689
691
690
692
impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Wrapped" ), pointeeTy);
691
693
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);
692
752
}
693
753
694
754
void swift::conformToCxxSequenceIfNeeded (
0 commit comments