Skip to content

[cxx-interop] Fix template parameter printing scheme for const types #79237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions lib/ClangImporter/ClangClassTemplateNamePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct TemplateInstantiationNamePrinter
case clang::BuiltinType::Void:
return "Void";
case clang::BuiltinType::NullPtr:
return "nil";
return "__cxxNullPtrT";

#define MAP_BUILTIN_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
case clang::BuiltinType::CLANG_BUILTIN_KIND: \
Expand Down Expand Up @@ -183,10 +183,18 @@ struct TemplateArgumentPrinter
void VisitTypeTemplateArgument(const clang::TemplateArgument &arg,
llvm::raw_svector_ostream &buffer) {
auto ty = arg.getAsType();

if (ty.isConstQualified())
buffer << "__cxxConst<";
if (ty.isVolatileQualified())
buffer << "__cxxVolatile<";

buffer << typePrinter.Visit(ty.getTypePtr());
if (ty.isConstQualified()) {
buffer << "_const";
}

if (ty.isVolatileQualified())
buffer << ">";
if (ty.isConstQualified())
buffer << ">";
}

void VisitIntegralTemplateArgument(const clang::TemplateArgument &arg,
Expand Down
43 changes: 36 additions & 7 deletions lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,42 @@ func replaceBaseType(_ type: TypeSyntax, _ base: TypeSyntax) -> TypeSyntax {
return base
}

// C++ type qualifiers, `const T` and `volatile T`, are encoded as fake generic
// types, `__cxxConst<T>` and `__cxxVolatile<T>` respectively. Remove those.
func dropQualifierGenerics(_ type: TypeSyntax) -> TypeSyntax {
guard let identifier = type.as(IdentifierTypeSyntax.self) else { return type }
guard let generic = identifier.genericArgumentClause else { return type }
guard let genericArg = generic.arguments.first else { return type }
guard case .type(let argType) = genericArg.argument else { return type }
switch identifier.name.text {
case "__cxxConst", "__cxxVolatile":
return dropQualifierGenerics(argType)
default:
return type
}
}

// The `const` type qualifier used to be encoded as a `_const` suffix on type
// names (though this causes issues for more complex types). We still drop the
// suffix here for backwards compatibility with older textual interfaces.
func dropQualifierSuffix(_ type: TypeSyntax) -> TypeSyntax {
guard let identifier = type.as(IdentifierTypeSyntax.self) else { return type }
let typename = identifier.name.text
if typename.hasSuffix("_const") {
return TypeSyntax(identifier.with(\.name, TokenSyntax.identifier(
String(typename.dropLast("_const".count))
)))
}
return type
}

// The generated type names for template instantiations sometimes contain
// a `_const` suffix for diambiguation purposes. We need to remove that.
func dropConstSuffix(_ typeName: String) -> String {
if typeName.hasSuffix("_const") {
return String(typeName.dropLast("_const".count))
// encoded qualifiers for disambiguation purposes. We need to remove those.
func dropCxxQualifiers(_ type: TypeSyntax) -> TypeSyntax {
if let attributed = type.as(AttributedTypeSyntax.self) {
return dropCxxQualifiers(attributed.baseType)
}
return typeName
return dropQualifierSuffix(dropQualifierGenerics(type))
}

func getPointerMutability(text: String) -> Mutability? {
Expand Down Expand Up @@ -405,7 +434,7 @@ struct CxxSpanThunkBuilder: ParamPointerBoundsThunkBuilder {
let genericArg = TypeSyntax(parsedDesugaredType.as(IdentifierTypeSyntax.self)!
.genericArgumentClause!.arguments.first!.argument)!
types[index] = replaceBaseType(param.type,
TypeSyntax("Span<\(raw: dropConstSuffix(try getTypeName(genericArg).text))>"))
TypeSyntax("Span<\(raw: dropCxxQualifiers(genericArg))>"))
return try base.buildFunctionSignature(types, returnType)
}

Expand Down Expand Up @@ -440,7 +469,7 @@ struct CxxSpanReturnThunkBuilder: BoundsCheckedThunkBuilder {
let genericArg = TypeSyntax(parsedDesugaredType.as(IdentifierTypeSyntax.self)!
.genericArgumentClause!.arguments.first!.argument)!
let newType = replaceBaseType(signature.returnClause!.type,
TypeSyntax("Span<\(raw: dropConstSuffix(try getTypeName(genericArg).text))>"))
TypeSyntax("Span<\(raw: dropCxxQualifiers(genericArg))>"))
return try base.buildFunctionSignature(argTypes, newType)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,19 @@ typedef DoubleWrapper<MagicWrapper<int[42]>> DoubleWrappedMagicIntFixedSizeArr1;
typedef DoubleWrapper<MagicWrapper<int[43]>> DoubleWrappedMagicIntFixedSizeArr2;
typedef DoubleWrapper<MagicWrapper<std::nullptr_t>> DoubleWrappedMagicNullPtr;

typedef DoubleWrapper<const MagicWrapper<int>> DoubleConstWrappedInt;
typedef DoubleWrapper<const MagicWrapper<const int>> DoubleConstWrappedIntConst;
typedef DoubleWrapper<const MagicWrapper<const long>> DoubleConstWrappedLongConst;
typedef DoubleWrapper<const MagicWrapper<int*>> DoubleConstWrappedIntPtr;
typedef DoubleWrapper<const MagicWrapper<const int*>> DoubleConstWrappedIntConstPtr;
typedef DoubleWrapper<const MagicWrapper<int[]>> DoubleConstWrappedMagicIntArr;
typedef DoubleWrapper<const MagicWrapper<long[]>> DoubleConstWrappedMagicLongArr;
typedef DoubleWrapper<const MagicWrapper<int[42]>> DoubleConstWrappedMagicIntFixedSizeArr1;
typedef DoubleWrapper<const MagicWrapper<int[43]>> DoubleConstWrappedMagicIntFixedSizeArr2;
typedef DoubleWrapper<const MagicWrapper<std::nullptr_t>> DoubleConstWrappedMagicNullPtr;

typedef MagicWrapper<volatile int> WrappedVolatileInt;
typedef MagicWrapper<const volatile int> WrappedConstVolatileInt;
typedef MagicWrapper<volatile const int> WrappedVolatileConstInt;

#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_WITH_PRIMITIVE_ARGUMENT_H
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=ClassTemplateWithPrimitiveArgument -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print=ClassTemplateWithPrimitiveArgument -I %S/Inputs -cxx-interoperability-mode=default | %FileCheck %s

// CHECK: @available(*, unavailable
// CHECK: struct MagicWrapper<T> {
Expand All @@ -8,24 +8,39 @@
// CHECK: }

// CHECK: typealias WrappedMagicInt = MagicWrapper<CInt>
// CHECK: typealias WrappedMagicIntConst = MagicWrapper<CInt_const>
// CHECK: typealias WrappedMagicLongConst = MagicWrapper<CLong_const>
// CHECK: typealias WrappedMagicIntConst = MagicWrapper<__cxxConst<CInt>>
// CHECK: typealias WrappedMagicLongConst = MagicWrapper<__cxxConst<CLong>>
// CHECK: typealias WrappedMagicIntPtr = MagicWrapper<UnsafeMutablePointer<CInt>>
// CHECK: typealias WrappedMagicIntConstPtr = MagicWrapper<UnsafePointer<CInt>>
// CHECK: typealias WrappedMagicIntPtrPtr = MagicWrapper<UnsafeMutablePointer<UnsafeMutablePointer<CInt>>>
// CHECK: typealias WrappedMagicIntArr = MagicWrapper<[CInt]>
// CHECK: typealias WrappedMagicLongArr = MagicWrapper<[CLong]>
// CHECK: typealias WrappedMagicIntFixedSizeArr1 = MagicWrapper<Vector<CInt, 123>>
// CHECK: typealias WrappedMagicIntFixedSizeArr2 = MagicWrapper<Vector<CInt, 124>>
// CHECK: typealias WrappedMagicNullPtr = MagicWrapper<nil>
// CHECK: typealias WrappedMagicNullPtr = MagicWrapper<__cxxNullPtrT>

// CHECK: typealias DoubleWrappedInt = DoubleWrapper<MagicWrapper<CInt>>
// CHECK: typealias DoubleWrappedIntConst = DoubleWrapper<MagicWrapper<CInt_const>>
// CHECK: typealias DoubleWrappedLongConst = DoubleWrapper<MagicWrapper<CLong_const>>
// CHECK: typealias DoubleWrappedIntConst = DoubleWrapper<MagicWrapper<__cxxConst<CInt>>>
// CHECK: typealias DoubleWrappedLongConst = DoubleWrapper<MagicWrapper<__cxxConst<CLong>>>
// CHECK: typealias DoubleWrappedIntPtr = DoubleWrapper<MagicWrapper<UnsafeMutablePointer<CInt>>>
// CHECK: typealias DoubleWrappedIntConstPtr = DoubleWrapper<MagicWrapper<UnsafePointer<CInt>>>
// CHECK: typealias DoubleWrappedMagicIntArr = DoubleWrapper<MagicWrapper<[CInt]>>
// CHECK: typealias DoubleWrappedMagicLongArr = DoubleWrapper<MagicWrapper<[CLong]>>
// CHECK: typealias DoubleWrappedMagicIntFixedSizeArr1 = DoubleWrapper<MagicWrapper<Vector<CInt, 42>>>
// CHECK: typealias DoubleWrappedMagicIntFixedSizeArr2 = DoubleWrapper<MagicWrapper<Vector<CInt, 43>>>
// CHECK: typealias DoubleWrappedMagicNullPtr = DoubleWrapper<MagicWrapper<nil>>
// CHECK: typealias DoubleWrappedMagicNullPtr = DoubleWrapper<MagicWrapper<__cxxNullPtrT>>

// CHECK: typealias DoubleConstWrappedInt = DoubleWrapper<__cxxConst<MagicWrapper<CInt>>>
// CHECK: typealias DoubleConstWrappedIntConst = DoubleWrapper<__cxxConst<MagicWrapper<__cxxConst<CInt>>>>
// CHECK: typealias DoubleConstWrappedLongConst = DoubleWrapper<__cxxConst<MagicWrapper<__cxxConst<CLong>>>>
// CHECK: typealias DoubleConstWrappedIntPtr = DoubleWrapper<__cxxConst<MagicWrapper<UnsafeMutablePointer<CInt>>>>
// CHECK: typealias DoubleConstWrappedIntConstPtr = DoubleWrapper<__cxxConst<MagicWrapper<UnsafePointer<CInt>>>>
// CHECK: typealias DoubleConstWrappedMagicIntArr = DoubleWrapper<__cxxConst<MagicWrapper<[CInt]>>>
// CHECK: typealias DoubleConstWrappedMagicLongArr = DoubleWrapper<__cxxConst<MagicWrapper<[CLong]>>>
// CHECK: typealias DoubleConstWrappedMagicIntFixedSizeArr1 = DoubleWrapper<__cxxConst<MagicWrapper<Vector<CInt, 42>>>>
// CHECK: typealias DoubleConstWrappedMagicIntFixedSizeArr2 = DoubleWrapper<__cxxConst<MagicWrapper<Vector<CInt, 43>>>>
// CHECK: typealias DoubleConstWrappedMagicNullPtr = DoubleWrapper<__cxxConst<MagicWrapper<__cxxNullPtrT>>>

// CHECK: typealias WrappedVolatileInt = MagicWrapper<__cxxVolatile<CInt>>
// CHECK: typealias WrappedConstVolatileInt = MagicWrapper<__cxxConst<__cxxVolatile<CInt>>>
// CHECK: typealias WrappedVolatileConstInt = MagicWrapper<__cxxConst<__cxxVolatile<CInt>>>