Skip to content

Commit 59be37b

Browse files
committed
Forbid C++ function template instantiation with Swift types
At the moment, instantiating C++ function templates with Swift types is not supported. However, some Swift types---notably, Swift classes---have been falling through the conversion logic and causing swiftc crashes. This patch aims to turn those crashes into compiler errors. These issues are due to relying on ClangTypeConverter::convert() to look for and reject types that a function template should not be instantiated with. However, convert() is also used in other contexts with different conversion requirements, where those types should be allowed. Rather than complicate the existing conversion logic, this patch factors out some reusable parts of convert(), and uses them in a new ClangTypeConverter method specifically intended for converting C++ function template arguments during instantiation. In the future, this method can be elaborated to add support for instantiating C++ templates with Swift types is added. rdar://138947983 rdar://138946240 rdar://138944852 rdar://138946844 rdar://138946593 rdar://138945719
1 parent bc8a9e4 commit 59be37b

File tree

2 files changed

+102
-47
lines changed

2 files changed

+102
-47
lines changed

lib/AST/ClangTypeConverter.cpp

Lines changed: 97 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,24 @@ clang::QualType ClangTypeConverter::convertMemberType(NominalTypeDecl *DC,
227227
return convert(memberType);
228228
}
229229

230+
clang::QualType ClangTypeConverter::visitStructType(StructType *type) {
231+
auto importedType = reverseImportedTypeMapping(type);
232+
if (!importedType.isNull())
233+
return importedType;
234+
235+
// We might be looking at a builtin
236+
auto builtinType = reverseBuiltinTypeMapping(type);
237+
if (!builtinType.isNull())
238+
return builtinType;
239+
240+
if (type->isPotentiallyBridgedValueType())
241+
if (auto t = Context.getBridgedToObjC(type->getDecl(), type))
242+
return convert(t);
243+
244+
// Out of ideas, there must've been some error. :(
245+
return clang::QualType();
246+
}
247+
230248
// TODO: It is unfortunate that we parse the name of a public library type
231249
// in order to break it down into a vector component and length that in theory
232250
// we could recover in some other way.
@@ -244,7 +262,8 @@ static clang::QualType getClangVectorType(const clang::ASTContext &ctx,
244262
return ctx.getVectorType(eltTy, numElts, vecKind);
245263
}
246264

247-
clang::QualType ClangTypeConverter::visitStructType(StructType *type) {
265+
clang::QualType
266+
ClangTypeConverter::reverseImportedTypeMapping(StructType *type) {
248267
auto &ctx = ClangASTContext;
249268

250269
auto swiftDecl = type->getDecl();
@@ -281,17 +300,7 @@ clang::QualType ClangTypeConverter::visitStructType(StructType *type) {
281300
}
282301
#include "swift/ClangImporter/SIMDMappedTypes.def"
283302

284-
// We might be looking at a builtin
285-
auto ret = reverseBuiltinTypeMapping(type);
286-
if (!ret.isNull())
287-
return ret;
288-
289-
if (type->isPotentiallyBridgedValueType()) {
290-
if (auto t = Context.getBridgedToObjC(type->getDecl(), type))
291-
return convert(t);
292-
}
293-
294-
// Out of ideas, there must've been some error. :(
303+
// This is not an imported type (according to the name)
295304
return clang::QualType();
296305
}
297306

@@ -834,30 +843,16 @@ clang::QualType ClangTypeConverter::convert(Type type) {
834843
if (it != Cache.end())
835844
return it->second;
836845

837-
// Try to do this without making cache entries for obvious cases.
838846
if (auto existential = type->getAs<ExistentialType>())
839847
type = existential->getConstraintType();
840848

849+
// Try to do this without making cache entries for obvious cases.
841850
if (auto nominal = type->getAs<NominalType>()) {
842851
auto decl = nominal->getDecl();
843852
if (auto clangDecl = decl->getClangDecl()) {
844-
auto &ctx = ClangASTContext;
845-
if (auto clangTypeDecl = dyn_cast<clang::TypeDecl>(clangDecl)) {
846-
auto qualType = ctx.getTypeDeclType(clangTypeDecl);
847-
if (type->isForeignReferenceType()) {
848-
qualType = ctx.getPointerType(qualType);
849-
}
850-
return qualType.getUnqualifiedType();
851-
} else if (auto ifaceDecl = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
852-
auto clangType = ctx.getObjCInterfaceType(ifaceDecl);
853-
return ctx.getObjCObjectPointerType(clangType);
854-
} else if (auto protoDecl = dyn_cast<clang::ObjCProtocolDecl>(clangDecl)){
855-
auto clangType = ctx.getObjCObjectType(
856-
ctx.ObjCBuiltinIdTy,
857-
const_cast<clang::ObjCProtocolDecl **>(&protoDecl),
858-
1);
859-
return ctx.getObjCObjectPointerType(clangType);
860-
}
853+
auto qualType = convertClangDecl(type, clangDecl);
854+
if (!qualType.isNull())
855+
return qualType;
861856
}
862857
}
863858

@@ -867,6 +862,34 @@ clang::QualType ClangTypeConverter::convert(Type type) {
867862
return result;
868863
}
869864

865+
clang::QualType
866+
ClangTypeConverter::convertClangDecl(Type type, const clang::Decl *clangDecl) {
867+
auto &ctx = ClangASTContext;
868+
869+
if (auto clangTypeDecl = dyn_cast<clang::TypeDecl>(clangDecl)) {
870+
auto qualType = ctx.getTypeDeclType(clangTypeDecl);
871+
if (type->isForeignReferenceType())
872+
qualType = ctx.getPointerType(qualType);
873+
874+
return qualType.getUnqualifiedType();
875+
}
876+
877+
if (auto ifaceDecl = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
878+
auto clangType = ctx.getObjCInterfaceType(ifaceDecl);
879+
return ctx.getObjCObjectPointerType(clangType);
880+
}
881+
882+
if (auto protoDecl = dyn_cast<clang::ObjCProtocolDecl>(clangDecl)) {
883+
auto clangType = ctx.getObjCObjectType(
884+
ctx.ObjCBuiltinIdTy, const_cast<clang::ObjCProtocolDecl **>(&protoDecl),
885+
1);
886+
return ctx.getObjCObjectPointerType(clangType);
887+
}
888+
889+
// Unable to convert this ClangDecl; give up
890+
return clang::QualType();
891+
}
892+
870893
void ClangTypeConverter::registerExportedClangDecl(Decl *swiftDecl,
871894
const clang::Decl *clangDecl) {
872895
assert(clangDecl->isCanonicalDecl() &&
@@ -883,6 +906,46 @@ Decl *ClangTypeConverter::getSwiftDeclForExportedClangDecl(
883906
return (it != ReversedExportMap.end() ? it->second : nullptr);
884907
}
885908

909+
clang::QualType ClangTypeConverter::convertTemplateArgument(Type type) {
910+
// C++ function templates can only be instantiated with Clang types and
911+
// a handful of Swift builtin types. These are enumerated here rather than
912+
// delegated to ClangTypeConverter::convert() (which is more general).
913+
914+
if (auto nominal = type->getAs<NominalType>())
915+
if (auto clangDecl = nominal->getDecl()->getClangDecl())
916+
return convertClangDecl(type, clangDecl);
917+
918+
if (auto pointerType = type->getAs<BuiltinRawPointerType>())
919+
return visitBuiltinRawPointerType(pointerType);
920+
921+
if (auto integerType = type->getAs<BuiltinIntegerType>())
922+
return visitBuiltinIntegerType(integerType);
923+
924+
if (auto floatType = type->getAs<BuiltinFloatType>())
925+
return visitBuiltinFloatType(floatType);
926+
927+
if (auto structType = type->getAs<StructType>()) {
928+
// Swift structs are not supported in general, but some foreign types are
929+
// imported as Swift structs. We reverse that mapping here.
930+
auto decl = structType->getDecl();
931+
932+
// Ban ObjCBool type from being substituted into C++ templates (#74790)
933+
if (decl->getName().is("ObjCBool") &&
934+
decl->getModuleContext()->getName() ==
935+
decl->getASTContext().Id_ObjectiveC)
936+
return clang::QualType();
937+
938+
auto importedType = reverseImportedTypeMapping(structType);
939+
if (!importedType.isNull())
940+
return importedType;
941+
942+
return reverseBuiltinTypeMapping(structType);
943+
}
944+
945+
// Most types cannot be used to instantiate C++ function templates; give up.
946+
return clang::QualType();
947+
}
948+
886949
std::unique_ptr<TemplateInstantiationError>
887950
ClangTypeConverter::getClangTemplateArguments(
888951
const clang::TemplateParameterList *templateParams,
@@ -906,25 +969,12 @@ ClangTypeConverter::getClangTemplateArguments(
906969

907970
auto replacement = genericArgs[templateParam->getIndex()];
908971

909-
// Ban ObjCBool type from being substituted into C++ templates.
910-
if (auto nominal = replacement->getAs<NominalType>()) {
911-
if (auto nominalDecl = nominal->getDecl()) {
912-
if (nominalDecl->getName().is("ObjCBool") &&
913-
nominalDecl->getModuleContext()->getName() ==
914-
nominalDecl->getASTContext().Id_ObjectiveC) {
915-
failedTypes.push_back(replacement);
916-
continue;
917-
}
918-
}
919-
}
972+
auto qualType = convertTemplateArgument(replacement);
920973

921-
auto qualType = convert(replacement);
922-
if (qualType.isNull()) {
974+
if (qualType.isNull())
923975
failedTypes.push_back(replacement);
924-
// Find all the types we can't convert.
925-
continue;
926-
}
927-
templateArgs.push_back(clang::TemplateArgument(qualType));
976+
else
977+
templateArgs.push_back(clang::TemplateArgument(qualType));
928978
}
929979
if (failedTypes.empty())
930980
return nullptr;

lib/AST/ClangTypeConverter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,14 @@ class ClangTypeConverter :
104104
clang::QualType convertMemberType(NominalTypeDecl *DC,
105105
StringRef memberName);
106106

107+
clang::QualType convertTemplateArgument(Type type);
108+
109+
clang::QualType convertClangDecl(Type type, const clang::Decl *decl);
110+
107111
void registerExportedClangDecl(Decl *swiftDecl,
108112
const clang::Decl *clangDecl);
109113

114+
clang::QualType reverseImportedTypeMapping(StructType *type);
110115
clang::QualType reverseBuiltinTypeMapping(StructType *type);
111116

112117
friend TypeVisitor<ClangTypeConverter, clang::QualType>;

0 commit comments

Comments
 (0)