Skip to content

Commit cd4e3cc

Browse files
author
Gabor Horvath
committed
[cxx-interop] Do not drop CV qualifiers during printing template names
Dropping qualifiers can result in collisions that can trigger compiler crashes or suprious errors. This PR attempts to make sure we always handle the qualifiers when a qualified type is present in the Clang API. The handling of pointers is somewhat special as foreign reference types has custom printing logic. rdar://164917816
1 parent 4432378 commit cd4e3cc

7 files changed

+96
-36
lines changed

lib/ClangImporter/ClangClassTemplateNamePrinter.cpp

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,21 @@ struct TemplateInstantiationNamePrinter
5858
return VisitType(type);
5959
}
6060

61+
void emitWithCVQualifiers(llvm::raw_svector_ostream &buffer,
62+
clang::QualType type) {
63+
if (type.isConstQualified())
64+
buffer << "__cxxConst<";
65+
if (type.isVolatileQualified())
66+
buffer << "__cxxVolatile<";
67+
68+
buffer << Visit(type.getTypePtr());
69+
70+
if (type.isVolatileQualified())
71+
buffer << ">";
72+
if (type.isConstQualified())
73+
buffer << ">";
74+
}
75+
6176
std::string VisitTagType(const clang::TagType *type) {
6277
auto tagDecl = type->getAsTagDecl();
6378
if (auto namedArg = dyn_cast_or_null<clang::NamedDecl>(tagDecl)) {
@@ -103,42 +118,47 @@ struct TemplateInstantiationNamePrinter
103118
} else {
104119
buffer << "__cxxRRef<";
105120
}
106-
buffer << Visit(type->getPointeeType().getTypePtr()) << ">";
121+
122+
emitWithCVQualifiers(buffer, type->getPointeeType());
123+
124+
buffer << ">";
107125
return buffer.str().str();
108126
}
109127

110128
std::string VisitPointerType(const clang::PointerType *type) {
111-
std::string pointeeResult = Visit(type->getPointeeType().getTypePtr());
112-
113-
enum class TagTypeDecorator { None, UnsafePointer, UnsafeMutablePointer };
129+
clang::QualType pointee = type->getPointeeType();
130+
std::string pointeeResult = Visit(pointee.getTypePtr());
114131

115132
// If this is a pointer to foreign reference type, we should not wrap
116133
// it in Unsafe(Mutable)?Pointer, since it will be imported as a class
117134
// in Swift.
118135
bool isReferenceType = false;
119-
if (auto tagDecl = type->getPointeeType()->getAsTagDecl()) {
136+
if (auto tagDecl = pointee->getAsTagDecl()) {
120137
if (auto *rd = dyn_cast<clang::RecordDecl>(tagDecl))
121138
isReferenceType = recordHasReferenceSemantics(rd, importerImpl);
122139
}
123140

124-
TagTypeDecorator decorator;
125-
if (!isReferenceType)
126-
decorator = type->getPointeeType().isConstQualified()
127-
? TagTypeDecorator::UnsafePointer
128-
: TagTypeDecorator::UnsafeMutablePointer;
129-
else
130-
decorator = TagTypeDecorator::None;
131-
132141
llvm::SmallString<128> storage;
133142
llvm::raw_svector_ostream buffer(storage);
134-
if (decorator != TagTypeDecorator::None)
135-
buffer << (decorator == TagTypeDecorator::UnsafePointer
136-
? "UnsafePointer"
137-
: "UnsafeMutablePointer")
138-
<< '<';
139-
buffer << pointeeResult;
140-
if (decorator != TagTypeDecorator::None)
143+
144+
if (pointee.isVolatileQualified())
145+
buffer << "__cxxVolatile<";
146+
147+
if (!isReferenceType) {
148+
buffer << (pointee.isConstQualified() ? "UnsafePointer<"
149+
: "UnsafeMutablePointer<");
150+
buffer << pointeeResult;
141151
buffer << '>';
152+
} else {
153+
if (pointee.isConstQualified())
154+
buffer << "__cxxConst<";
155+
buffer << pointeeResult;
156+
if (pointee.isConstQualified())
157+
buffer << ">";
158+
}
159+
160+
if (pointee.isVolatileQualified())
161+
buffer << ">";
142162

143163
return buffer.str().str();
144164
}
@@ -166,14 +186,23 @@ struct TemplateInstantiationNamePrinter
166186
}
167187

168188
std::string VisitArrayType(const clang::ArrayType *type) {
169-
return (Twine("[") + Visit(type->getElementType().getTypePtr()) + "]")
170-
.str();
189+
llvm::SmallString<128> storage;
190+
llvm::raw_svector_ostream buffer(storage);
191+
buffer << "[";
192+
emitWithCVQualifiers(buffer, type->getElementType());
193+
buffer << "]";
194+
return buffer.str().str();
171195
}
172196

173197
std::string VisitConstantArrayType(const clang::ConstantArrayType *type) {
174-
return (Twine("Vector<") + Visit(type->getElementType().getTypePtr()) +
175-
", " + std::to_string(type->getSExtSize()) + ">")
176-
.str();
198+
llvm::SmallString<128> storage;
199+
llvm::raw_svector_ostream buffer(storage);
200+
buffer << "Vector<";
201+
emitWithCVQualifiers(buffer, type->getElementType());
202+
buffer << ", ";
203+
buffer << type->getSExtSize();
204+
buffer << ">";
205+
return buffer.str().str();
177206
}
178207
};
179208

@@ -197,17 +226,7 @@ struct TemplateArgumentPrinter
197226
llvm::raw_svector_ostream &buffer) {
198227
auto ty = arg.getAsType();
199228

200-
if (ty.isConstQualified())
201-
buffer << "__cxxConst<";
202-
if (ty.isVolatileQualified())
203-
buffer << "__cxxVolatile<";
204-
205-
buffer << typePrinter.Visit(ty.getTypePtr());
206-
207-
if (ty.isVolatileQualified())
208-
buffer << ">";
209-
if (ty.isConstQualified())
210-
buffer << ">";
229+
typePrinter.emitWithCVQualifiers(buffer, ty);
211230
}
212231

213232
void VisitIntegralTemplateArgument(const clang::TemplateArgument &arg,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
template<class T>
4+
struct MagicWrapper {};
5+
6+
class __attribute__((swift_attr("import_reference")))
7+
__attribute__((swift_attr("retain:immortal")))
8+
__attribute__((swift_attr("release:immortal"))) Foo {};
9+
10+
using MagicWrapperFrt = MagicWrapper<Foo *>;
11+
using MagicWrapperConstFrt = MagicWrapper<const Foo *>;
12+
using MagicWrapperVolatileFrt = MagicWrapper<volatile Foo *>;
13+
using MagicWrapperVolatileFrtRef = MagicWrapper<volatile Foo &>;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ struct DoubleWrapper {
1515
int getValuePlusArg(int arg) const { return m.getValuePlusArg(arg); }
1616
};
1717

18+
template <class T>
19+
struct EmptyWrapper {};
20+
1821
typedef MagicWrapper<int> WrappedMagicInt;
1922
typedef MagicWrapper<const int> WrappedMagicIntConst;
2023
typedef MagicWrapper<const long> WrappedMagicLongConst;
@@ -26,6 +29,8 @@ typedef MagicWrapper<long[]> WrappedMagicLongArr;
2629
typedef MagicWrapper<int[123]> WrappedMagicIntFixedSizeArr1;
2730
typedef MagicWrapper<int[124]> WrappedMagicIntFixedSizeArr2;
2831
typedef MagicWrapper<std::nullptr_t> WrappedMagicNullPtr;
32+
typedef MagicWrapper<const int[]> WrappedMagicConstIntArr;
33+
typedef EmptyWrapper<volatile int &> WrappedVolatileIntRef;
2934

3035
typedef DoubleWrapper<MagicWrapper<int>> DoubleWrappedInt;
3136
typedef DoubleWrapper<MagicWrapper<const int>> DoubleWrappedIntConst;

test/Interop/Cxx/templates/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,8 @@ module ForwardDeclaredSpecialization {
187187
header "ForwardDeclaredSpecialization.h"
188188
requires cplusplus
189189
}
190+
191+
module ClassTemplateWithFrt {
192+
header "class-template-with-frt.h"
193+
requires cplusplus
194+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=ClassTemplateWithFrt -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
2+
3+
// CHECK: typealias MagicWrapperFrt = MagicWrapper<Foo>
4+
// CHECK: typealias MagicWrapperConstFrt = MagicWrapper<__cxxConst<Foo>>
5+
// CHECK: typealias MagicWrapperVolatileFrt = MagicWrapper<__cxxVolatile<Foo>>
6+
// CHECK: typealias MagicWrapperVolatileFrtRef = MagicWrapper<__cxxLRef<__cxxVolatile<Foo>>>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-emit-silgen %s -I %S/Inputs -enable-experimental-cxx-interop -disable-availability-checking
2+
3+
import ClassTemplateWithFrt
4+
5+
func f() {
6+
// Used to trigger error while emitting SIL.
7+
let _ = MagicWrapperFrt()
8+
let _ = MagicWrapperConstFrt()
9+
let _ = MagicWrapperVolatileFrtRef()
10+
}

test/Interop/Cxx/templates/class-template-with-primitive-argument-module-interface.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
// CHECK: typealias WrappedMagicIntFixedSizeArr1 = MagicWrapper<Vector<CInt, 123>>
1919
// CHECK: typealias WrappedMagicIntFixedSizeArr2 = MagicWrapper<Vector<CInt, 124>>
2020
// CHECK: typealias WrappedMagicNullPtr = MagicWrapper<__cxxNullPtrT>
21+
// CHECK: typealias WrappedMagicConstIntArr = MagicWrapper<__cxxConst<[CInt]>>
22+
// CHECK: typealias WrappedVolatileIntRef = EmptyWrapper<__cxxLRef<__cxxVolatile<CInt>>>
2123

2224
// CHECK: typealias DoubleWrappedInt = DoubleWrapper<MagicWrapper<CInt>>
2325
// CHECK: typealias DoubleWrappedIntConst = DoubleWrapper<MagicWrapper<__cxxConst<CInt>>>

0 commit comments

Comments
 (0)