@@ -122,6 +122,22 @@ static bool isStdDecl(const clang::CXXRecordDecl *clangDecl,
122122 return llvm::is_contained (names, name);
123123}
124124
125+ static clang::TypeDecl *
126+ lookupNestedClangTypeDecl (const clang::CXXRecordDecl *clangDecl,
127+ StringRef name) {
128+ clang::IdentifierInfo *nestedDeclName =
129+ &clangDecl->getASTContext ().Idents .get (name);
130+ auto nestedDecls = clangDecl->lookup (nestedDeclName);
131+ // If this is a templated typedef, Clang might have instantiated several
132+ // equivalent typedef decls. If they aren't equivalent, Clang has already
133+ // complained about this. Let's assume that they are equivalent. (see
134+ // filterNonConflictingPreviousTypedefDecls in clang/Sema/SemaDecl.cpp)
135+ if (nestedDecls.empty ())
136+ return nullptr ;
137+ auto nestedDecl = nestedDecls.front ();
138+ return dyn_cast_or_null<clang::TypeDecl>(nestedDecl);
139+ }
140+
125141static clang::TypeDecl *
126142getIteratorCategoryDecl (const clang::CXXRecordDecl *clangDecl) {
127143 clang::IdentifierInfo *iteratorCategoryDeclName =
@@ -1128,4 +1144,94 @@ void swift::conformToCxxFunctionIfNeeded(
11281144 decl->addMember (importedConstructor);
11291145
11301146 // TODO: actually conform to some form of CxxFunction protocol
1147+
1148+ }
1149+
1150+ void swift::conformToCxxSpanIfNeeded (ClangImporter::Implementation &impl,
1151+ NominalTypeDecl *decl,
1152+ const clang::CXXRecordDecl *clangDecl) {
1153+ PrettyStackTraceDecl trace (" conforming to CxxSpan" , decl);
1154+
1155+ assert (decl);
1156+ assert (clangDecl);
1157+ ASTContext &ctx = decl->getASTContext ();
1158+ clang::ASTContext &clangCtx = impl.getClangASTContext ();
1159+ clang::Sema &clangSema = impl.getClangSema ();
1160+
1161+ // Only auto-conform types from the C++ standard library. Custom user types
1162+ // might have a similar interface but different semantics.
1163+ if (!isStdDecl (clangDecl, {" span" }))
1164+ return ;
1165+
1166+ auto elementType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
1167+ decl, ctx.getIdentifier (" element_type" ));
1168+ auto sizeType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
1169+ decl, ctx.getIdentifier (" size_type" ));
1170+
1171+ if (!elementType || !sizeType)
1172+ return ;
1173+
1174+ auto constPointerTypeDecl =
1175+ lookupNestedClangTypeDecl (clangDecl, " const_pointer" );
1176+ auto countTypeDecl = lookupNestedClangTypeDecl (clangDecl, " size_type" );
1177+
1178+ if (!constPointerTypeDecl || !countTypeDecl)
1179+ return ;
1180+
1181+ // create fake variable for constPointer (constructor arg 1)
1182+ auto constPointerType = clangCtx.getTypeDeclType (constPointerTypeDecl);
1183+ auto fakeConstPointerVarDecl = clang::VarDecl::Create (
1184+ clangCtx, /* DC*/ clangCtx.getTranslationUnitDecl (),
1185+ clang::SourceLocation (), clang::SourceLocation (), /* Id*/ nullptr ,
1186+ constPointerType, clangCtx.getTrivialTypeSourceInfo (constPointerType),
1187+ clang::StorageClass::SC_None);
1188+
1189+ auto fakeConstPointer = new (clangCtx) clang::DeclRefExpr (
1190+ clangCtx, fakeConstPointerVarDecl, false , constPointerType,
1191+ clang::ExprValueKind::VK_LValue, clang::SourceLocation ());
1192+
1193+ // create fake variable for count (constructor arg 2)
1194+ auto countType = clangCtx.getTypeDeclType (countTypeDecl);
1195+ auto fakeCountVarDecl = clang::VarDecl::Create (
1196+ clangCtx, /* DC*/ clangCtx.getTranslationUnitDecl (),
1197+ clang::SourceLocation (), clang::SourceLocation (), /* Id*/ nullptr ,
1198+ countType, clangCtx.getTrivialTypeSourceInfo (countType),
1199+ clang::StorageClass::SC_None);
1200+
1201+ auto fakeCount = new (clangCtx) clang::DeclRefExpr (
1202+ clangCtx, fakeCountVarDecl, false , countType,
1203+ clang::ExprValueKind::VK_LValue, clang::SourceLocation ());
1204+
1205+ // Use clangSema.BuildCxxTypeConstructExpr to create a CXXTypeConstructExpr,
1206+ // passing constPointer and count
1207+ SmallVector<clang::Expr *, 2 > constructExprArgs = {fakeConstPointer,
1208+ fakeCount};
1209+
1210+ auto clangDeclTyInfo = clangCtx.getTrivialTypeSourceInfo (
1211+ clang::QualType (clangDecl->getTypeForDecl (), 0 ));
1212+
1213+ // Instantiate the templated constructor that would accept this fake variable.
1214+ auto constructExprResult = clangSema.BuildCXXTypeConstructExpr (
1215+ clangDeclTyInfo, clangDecl->getLocation (), constructExprArgs,
1216+ clangDecl->getLocation (), /* ListInitialization*/ false );
1217+ if (!constructExprResult.isUsable ())
1218+ return ;
1219+
1220+ auto constructExpr =
1221+ dyn_cast_or_null<clang::CXXConstructExpr>(constructExprResult.get ());
1222+ if (!constructExpr)
1223+ return ;
1224+
1225+ auto constructorDecl = constructExpr->getConstructor ();
1226+ auto importedConstructor =
1227+ impl.importDecl (constructorDecl, impl.CurrentVersion );
1228+ if (!importedConstructor)
1229+ return ;
1230+ decl->addMember (importedConstructor);
1231+
1232+ impl.addSynthesizedTypealias (decl, ctx.Id_Element ,
1233+ elementType->getUnderlyingType ());
1234+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Size" ),
1235+ sizeType->getUnderlyingType ());
1236+ impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxSpan});
11311237}
0 commit comments