Skip to content

Commit 1405520

Browse files
authored
[cxx-interop] Fix template parameter printing scheme for const types (#79237)
This patch changes the class template printer to disambiguate const-qualified template arguments by wrapping them with __cxxConst<>, rather than suffixing them with _const. This is necessary to accommodate template arguments that aren't just identifiers (i.e., Foo<Int_const> is ok, but Foo<Bar<T>_const> and Foo<((Bar) -> Baz)_const> are not syntactically valid). With this patch, we would produce Foo<__cxxConst<Int>>, Foo<__cxxConst<Bar<T>>, and Foo<__cxxConst<((Bar) -> Baz)>> instead. This patch also disambiguates volatile-qualified template arguments with __cxxVolatile<>, and changes the printing scheme for std::nullptr_t from nil to __cxxNullPtrT (since nil is not a syntactically valid type name). rdar://143769901
1 parent dc61784 commit 1405520

File tree

4 files changed

+85
-18
lines changed

4 files changed

+85
-18
lines changed

lib/ClangImporter/ClangClassTemplateNamePrinter.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct TemplateInstantiationNamePrinter
4444
case clang::BuiltinType::Void:
4545
return "Void";
4646
case clang::BuiltinType::NullPtr:
47-
return "nil";
47+
return "__cxxNullPtrT";
4848

4949
#define MAP_BUILTIN_TYPE(CLANG_BUILTIN_KIND, SWIFT_TYPE_NAME) \
5050
case clang::BuiltinType::CLANG_BUILTIN_KIND: \
@@ -183,10 +183,18 @@ struct TemplateArgumentPrinter
183183
void VisitTypeTemplateArgument(const clang::TemplateArgument &arg,
184184
llvm::raw_svector_ostream &buffer) {
185185
auto ty = arg.getAsType();
186+
187+
if (ty.isConstQualified())
188+
buffer << "__cxxConst<";
189+
if (ty.isVolatileQualified())
190+
buffer << "__cxxVolatile<";
191+
186192
buffer << typePrinter.Visit(ty.getTypePtr());
187-
if (ty.isConstQualified()) {
188-
buffer << "_const";
189-
}
193+
194+
if (ty.isVolatileQualified())
195+
buffer << ">";
196+
if (ty.isConstQualified())
197+
buffer << ">";
190198
}
191199

192200
void VisitIntegralTemplateArgument(const clang::TemplateArgument &arg,

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,42 @@ func replaceBaseType(_ type: TypeSyntax, _ base: TypeSyntax) -> TypeSyntax {
204204
return base
205205
}
206206

207+
// C++ type qualifiers, `const T` and `volatile T`, are encoded as fake generic
208+
// types, `__cxxConst<T>` and `__cxxVolatile<T>` respectively. Remove those.
209+
func dropQualifierGenerics(_ type: TypeSyntax) -> TypeSyntax {
210+
guard let identifier = type.as(IdentifierTypeSyntax.self) else { return type }
211+
guard let generic = identifier.genericArgumentClause else { return type }
212+
guard let genericArg = generic.arguments.first else { return type }
213+
guard case .type(let argType) = genericArg.argument else { return type }
214+
switch identifier.name.text {
215+
case "__cxxConst", "__cxxVolatile":
216+
return dropQualifierGenerics(argType)
217+
default:
218+
return type
219+
}
220+
}
221+
222+
// The `const` type qualifier used to be encoded as a `_const` suffix on type
223+
// names (though this causes issues for more complex types). We still drop the
224+
// suffix here for backwards compatibility with older textual interfaces.
225+
func dropQualifierSuffix(_ type: TypeSyntax) -> TypeSyntax {
226+
guard let identifier = type.as(IdentifierTypeSyntax.self) else { return type }
227+
let typename = identifier.name.text
228+
if typename.hasSuffix("_const") {
229+
return TypeSyntax(identifier.with(\.name, TokenSyntax.identifier(
230+
String(typename.dropLast("_const".count))
231+
)))
232+
}
233+
return type
234+
}
235+
207236
// The generated type names for template instantiations sometimes contain
208-
// a `_const` suffix for diambiguation purposes. We need to remove that.
209-
func dropConstSuffix(_ typeName: String) -> String {
210-
if typeName.hasSuffix("_const") {
211-
return String(typeName.dropLast("_const".count))
237+
// encoded qualifiers for disambiguation purposes. We need to remove those.
238+
func dropCxxQualifiers(_ type: TypeSyntax) -> TypeSyntax {
239+
if let attributed = type.as(AttributedTypeSyntax.self) {
240+
return dropCxxQualifiers(attributed.baseType)
212241
}
213-
return typeName
242+
return dropQualifierSuffix(dropQualifierGenerics(type))
214243
}
215244

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

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

test/Interop/Cxx/templates/Inputs/class-template-with-primitive-argument.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,19 @@ typedef DoubleWrapper<MagicWrapper<int[42]>> DoubleWrappedMagicIntFixedSizeArr1;
3838
typedef DoubleWrapper<MagicWrapper<int[43]>> DoubleWrappedMagicIntFixedSizeArr2;
3939
typedef DoubleWrapper<MagicWrapper<std::nullptr_t>> DoubleWrappedMagicNullPtr;
4040

41+
typedef DoubleWrapper<const MagicWrapper<int>> DoubleConstWrappedInt;
42+
typedef DoubleWrapper<const MagicWrapper<const int>> DoubleConstWrappedIntConst;
43+
typedef DoubleWrapper<const MagicWrapper<const long>> DoubleConstWrappedLongConst;
44+
typedef DoubleWrapper<const MagicWrapper<int*>> DoubleConstWrappedIntPtr;
45+
typedef DoubleWrapper<const MagicWrapper<const int*>> DoubleConstWrappedIntConstPtr;
46+
typedef DoubleWrapper<const MagicWrapper<int[]>> DoubleConstWrappedMagicIntArr;
47+
typedef DoubleWrapper<const MagicWrapper<long[]>> DoubleConstWrappedMagicLongArr;
48+
typedef DoubleWrapper<const MagicWrapper<int[42]>> DoubleConstWrappedMagicIntFixedSizeArr1;
49+
typedef DoubleWrapper<const MagicWrapper<int[43]>> DoubleConstWrappedMagicIntFixedSizeArr2;
50+
typedef DoubleWrapper<const MagicWrapper<std::nullptr_t>> DoubleConstWrappedMagicNullPtr;
51+
52+
typedef MagicWrapper<volatile int> WrappedVolatileInt;
53+
typedef MagicWrapper<const volatile int> WrappedConstVolatileInt;
54+
typedef MagicWrapper<volatile const int> WrappedVolatileConstInt;
55+
4156
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_WITH_PRIMITIVE_ARGUMENT_H
Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-ide-test -print-module -module-to-print=ClassTemplateWithPrimitiveArgument -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
1+
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print=ClassTemplateWithPrimitiveArgument -I %S/Inputs -cxx-interoperability-mode=default | %FileCheck %s
22

33
// CHECK: @available(*, unavailable
44
// CHECK: struct MagicWrapper<T> {
@@ -8,24 +8,39 @@
88
// CHECK: }
99

1010
// CHECK: typealias WrappedMagicInt = MagicWrapper<CInt>
11-
// CHECK: typealias WrappedMagicIntConst = MagicWrapper<CInt_const>
12-
// CHECK: typealias WrappedMagicLongConst = MagicWrapper<CLong_const>
11+
// CHECK: typealias WrappedMagicIntConst = MagicWrapper<__cxxConst<CInt>>
12+
// CHECK: typealias WrappedMagicLongConst = MagicWrapper<__cxxConst<CLong>>
1313
// CHECK: typealias WrappedMagicIntPtr = MagicWrapper<UnsafeMutablePointer<CInt>>
1414
// CHECK: typealias WrappedMagicIntConstPtr = MagicWrapper<UnsafePointer<CInt>>
1515
// CHECK: typealias WrappedMagicIntPtrPtr = MagicWrapper<UnsafeMutablePointer<UnsafeMutablePointer<CInt>>>
1616
// CHECK: typealias WrappedMagicIntArr = MagicWrapper<[CInt]>
1717
// CHECK: typealias WrappedMagicLongArr = MagicWrapper<[CLong]>
1818
// CHECK: typealias WrappedMagicIntFixedSizeArr1 = MagicWrapper<Vector<CInt, 123>>
1919
// CHECK: typealias WrappedMagicIntFixedSizeArr2 = MagicWrapper<Vector<CInt, 124>>
20-
// CHECK: typealias WrappedMagicNullPtr = MagicWrapper<nil>
20+
// CHECK: typealias WrappedMagicNullPtr = MagicWrapper<__cxxNullPtrT>
2121

2222
// CHECK: typealias DoubleWrappedInt = DoubleWrapper<MagicWrapper<CInt>>
23-
// CHECK: typealias DoubleWrappedIntConst = DoubleWrapper<MagicWrapper<CInt_const>>
24-
// CHECK: typealias DoubleWrappedLongConst = DoubleWrapper<MagicWrapper<CLong_const>>
23+
// CHECK: typealias DoubleWrappedIntConst = DoubleWrapper<MagicWrapper<__cxxConst<CInt>>>
24+
// CHECK: typealias DoubleWrappedLongConst = DoubleWrapper<MagicWrapper<__cxxConst<CLong>>>
2525
// CHECK: typealias DoubleWrappedIntPtr = DoubleWrapper<MagicWrapper<UnsafeMutablePointer<CInt>>>
2626
// CHECK: typealias DoubleWrappedIntConstPtr = DoubleWrapper<MagicWrapper<UnsafePointer<CInt>>>
2727
// CHECK: typealias DoubleWrappedMagicIntArr = DoubleWrapper<MagicWrapper<[CInt]>>
2828
// CHECK: typealias DoubleWrappedMagicLongArr = DoubleWrapper<MagicWrapper<[CLong]>>
2929
// CHECK: typealias DoubleWrappedMagicIntFixedSizeArr1 = DoubleWrapper<MagicWrapper<Vector<CInt, 42>>>
3030
// CHECK: typealias DoubleWrappedMagicIntFixedSizeArr2 = DoubleWrapper<MagicWrapper<Vector<CInt, 43>>>
31-
// CHECK: typealias DoubleWrappedMagicNullPtr = DoubleWrapper<MagicWrapper<nil>>
31+
// CHECK: typealias DoubleWrappedMagicNullPtr = DoubleWrapper<MagicWrapper<__cxxNullPtrT>>
32+
33+
// CHECK: typealias DoubleConstWrappedInt = DoubleWrapper<__cxxConst<MagicWrapper<CInt>>>
34+
// CHECK: typealias DoubleConstWrappedIntConst = DoubleWrapper<__cxxConst<MagicWrapper<__cxxConst<CInt>>>>
35+
// CHECK: typealias DoubleConstWrappedLongConst = DoubleWrapper<__cxxConst<MagicWrapper<__cxxConst<CLong>>>>
36+
// CHECK: typealias DoubleConstWrappedIntPtr = DoubleWrapper<__cxxConst<MagicWrapper<UnsafeMutablePointer<CInt>>>>
37+
// CHECK: typealias DoubleConstWrappedIntConstPtr = DoubleWrapper<__cxxConst<MagicWrapper<UnsafePointer<CInt>>>>
38+
// CHECK: typealias DoubleConstWrappedMagicIntArr = DoubleWrapper<__cxxConst<MagicWrapper<[CInt]>>>
39+
// CHECK: typealias DoubleConstWrappedMagicLongArr = DoubleWrapper<__cxxConst<MagicWrapper<[CLong]>>>
40+
// CHECK: typealias DoubleConstWrappedMagicIntFixedSizeArr1 = DoubleWrapper<__cxxConst<MagicWrapper<Vector<CInt, 42>>>>
41+
// CHECK: typealias DoubleConstWrappedMagicIntFixedSizeArr2 = DoubleWrapper<__cxxConst<MagicWrapper<Vector<CInt, 43>>>>
42+
// CHECK: typealias DoubleConstWrappedMagicNullPtr = DoubleWrapper<__cxxConst<MagicWrapper<__cxxNullPtrT>>>
43+
44+
// CHECK: typealias WrappedVolatileInt = MagicWrapper<__cxxVolatile<CInt>>
45+
// CHECK: typealias WrappedConstVolatileInt = MagicWrapper<__cxxConst<__cxxVolatile<CInt>>>
46+
// CHECK: typealias WrappedVolatileConstInt = MagicWrapper<__cxxConst<__cxxVolatile<CInt>>>

0 commit comments

Comments
 (0)