@@ -122,6 +122,22 @@ static bool isStdDecl(const clang::CXXRecordDecl *clangDecl,
122
122
return llvm::is_contained (names, name);
123
123
}
124
124
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
+
125
141
static clang::TypeDecl *
126
142
getIteratorCategoryDecl (const clang::CXXRecordDecl *clangDecl) {
127
143
clang::IdentifierInfo *iteratorCategoryDeclName =
@@ -1128,4 +1144,94 @@ void swift::conformToCxxFunctionIfNeeded(
1128
1144
decl->addMember (importedConstructor);
1129
1145
1130
1146
// 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});
1131
1237
}
0 commit comments