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