Skip to content

Commit 19c08ee

Browse files
committed
[Clang printing] Loosen assertion on noncopyable & nonescaping requirements
Noncopyable and nonescaping APIs in Swift can be expressed in C++ with some downsides. Teach the AST printer to be more lenient, allowing Swift APIs involving noncopyable and nonescapable types to be printed.
1 parent 1752b48 commit 19c08ee

File tree

5 files changed

+63
-64
lines changed

5 files changed

+63
-64
lines changed

Diff for: include/swift/AST/SwiftNameTranslation.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818
#include "swift/AST/Identifier.h"
1919

2020
namespace swift {
21-
class ValueDecl;
22-
class EnumDecl;
23-
class EnumElementDecl;
21+
22+
class EnumDecl;
23+
class EnumElementDecl;
24+
struct InverseRequirement;
25+
class GenericSignature;
26+
class ValueDecl;
2427

2528
namespace objc_translation {
2629
enum CustomNamesOnly_t : bool {
@@ -107,6 +110,9 @@ inline bool isExposableToCxx(const ValueDecl *VD) {
107110
bool isVisibleToCxx(const ValueDecl *VD, AccessLevel minRequiredAccess,
108111
bool checkParent = true);
109112

113+
/// Determine whether the given generic signature can be exposed to C++.
114+
bool isExposableToCxx(GenericSignature genericSig);
115+
110116
} // end namespace cxx_translation
111117

112118
} // end namespace swift

Diff for: lib/AST/SwiftNameTranslation.cpp

+47-16
Original file line numberDiff line numberDiff line change
@@ -281,22 +281,8 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
281281
}
282282

283283
// Generic requirements are not yet supported in C++.
284-
if (genericSignature) {
285-
286-
// FIXME: This should use getRequirements() and actually
287-
// support arbitrary requirements. We don't really want
288-
// to use getRequirementsWithInverses() here.
289-
//
290-
// For now, we use the inverse transform as a quick way to
291-
// check for the "default" generic signature where each
292-
// generic parameter is Copyable and Escapable, but not
293-
// subject to any other requirements; that's exactly the
294-
// generic signature that C++ interop supports today.
295-
SmallVector<Requirement, 2> reqs;
296-
SmallVector<InverseRequirement, 2> inverseReqs;
297-
genericSignature->getRequirementsWithInverses(reqs, inverseReqs);
298-
if (!reqs.empty() || !inverseReqs.empty())
299-
return {Unsupported, UnrepresentableGenericRequirements};
284+
if (!isExposableToCxx(genericSignature)) {
285+
return {Unsupported, UnrepresentableGenericRequirements};
300286
}
301287

302288
return {Representable, std::nullopt};
@@ -321,6 +307,51 @@ bool swift::cxx_translation::isVisibleToCxx(const ValueDecl *VD,
321307
return false;
322308
}
323309

310+
bool swift::cxx_translation::isExposableToCxx(GenericSignature genericSig) {
311+
// If there's no generic signature, it's fine.
312+
if (!genericSig)
313+
return true;
314+
315+
// FIXME: This should use getRequirements() and actually
316+
// support arbitrary requirements. We don't really want
317+
// to use getRequirementsWithInverses() here.
318+
//
319+
// For now, we use the inverse transform as a quick way to
320+
// check for the "default" generic signature where each
321+
// generic parameter is Copyable and Escapable, but not
322+
// subject to any other requirements; that's exactly the
323+
// generic signature that C++ interop supports today.
324+
SmallVector<Requirement, 2> reqs;
325+
SmallVector<InverseRequirement, 2> inverseReqs;
326+
genericSig->getRequirementsWithInverses(reqs, inverseReqs);
327+
if (!reqs.empty()) {
328+
// Conformance requirements to marker protocols are okay.
329+
for (const auto &req: reqs) {
330+
if (req.getKind() != RequirementKind::Conformance)
331+
return false;
332+
333+
auto proto = req.getProtocolDecl();
334+
if (!proto->isMarkerProtocol())
335+
return false;
336+
}
337+
}
338+
339+
// Allow Copyable and Escapable.
340+
for (const auto &req: inverseReqs) {
341+
switch (req.getKind()) {
342+
case InvertibleProtocolKind::Copyable:
343+
continue;
344+
345+
case InvertibleProtocolKind::Escapable:
346+
continue;
347+
}
348+
349+
return false;
350+
}
351+
352+
return true;
353+
}
354+
324355
Diagnostic
325356
swift::cxx_translation::diagnoseRepresenationError(RepresentationError error,
326357
ValueDecl *vd) {

Diff for: lib/PrintAsClang/DeclAndTypePrinter.cpp

+3-16
Original file line numberDiff line numberDiff line change
@@ -383,22 +383,9 @@ class DeclAndTypePrinter::Implementation
383383
printMembers(SD->getMembers());
384384
for (const auto *ed :
385385
owningPrinter.interopContext.getExtensionsForNominalType(SD)) {
386-
SmallVector<Requirement, 2> reqs;
387-
SmallVector<InverseRequirement, 2> inverseReqs;
388-
if (auto sig = ed->getGenericSignature()) {
389-
// FIXME: This should use getRequirements() and actually
390-
// support arbitrary requirements. We don't really want
391-
// to use getRequirementsWithInverses() here.
392-
//
393-
// For now, we use the inverse transform as a quick way to
394-
// check for the "default" generic signature where each
395-
// generic parameter is Copyable and Escapable, but not
396-
// subject to any other requirements; that's exactly the
397-
// generic signature that C++ interop supports today.
398-
sig->getRequirementsWithInverses(reqs, inverseReqs);
399-
if (!reqs.empty() || !inverseReqs.empty())
400-
continue;
401-
}
386+
if (!cxx_translation::isExposableToCxx(ed->getGenericSignature()))
387+
continue;
388+
402389
printMembers(ed->getMembers());
403390
}
404391
},

Diff for: lib/PrintAsClang/PrintClangFunction.cpp

+2-14
Original file line numberDiff line numberDiff line change
@@ -700,21 +700,9 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
700700
}
701701
if (FD->isGeneric()) {
702702
auto Signature = FD->getGenericSignature().getCanonicalSignature();
703-
704-
// FIXME: This should use getRequirements() and actually
705-
// support arbitrary requirements. We don't really want
706-
// to use getRequirementsWithInverses() here.
707-
//
708-
// For now, we use the inverse transform as a quick way to
709-
// check for the "default" generic signature where each
710-
// generic parameter is Copyable and Escapable, but not
711-
// subject to any other requirements; that's exactly the
712-
// generic signature that C++ interop supports today.
713-
SmallVector<Requirement, 2> reqs;
714-
SmallVector<InverseRequirement, 2> inverseReqs;
715-
Signature->getRequirementsWithInverses(reqs, inverseReqs);
716-
if (!reqs.empty() || !inverseReqs.empty())
703+
if (!cxx_translation::isExposableToCxx(Signature))
717704
return ClangRepresentation::unsupported;
705+
718706
// Print the template and requires clauses for this function.
719707
if (kind == FunctionSignatureKind::CxxInlineThunk)
720708
ClangSyntaxPrinter(os).printGenericSignature(Signature);

Diff for: lib/PrintAsClang/PrintClangValueType.cpp

+2-15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTMangler.h"
2020
#include "swift/AST/Decl.h"
2121
#include "swift/AST/ParameterList.h"
22+
#include "swift/AST/SwiftNameTranslation.h"
2223
#include "swift/AST/Type.h"
2324
#include "swift/AST/TypeVisitor.h"
2425
#include "swift/ClangImporter/ClangImporter.h"
@@ -193,21 +194,7 @@ void ClangValueTypePrinter::printValueTypeDecl(
193194
};
194195
if (typeDecl->isGeneric()) {
195196
genericSignature = typeDecl->getGenericSignature();
196-
197-
// FIXME: This should use getRequirements() and actually
198-
// support arbitrary requirements. We don't really want
199-
// to use getRequirementsWithInverses() here.
200-
//
201-
// For now, we use the inverse transform as a quick way to
202-
// check for the "default" generic signature where each
203-
// generic parameter is Copyable and Escapable, but not
204-
// subject to any other requirements; that's exactly the
205-
// generic signature that C++ interop supports today.
206-
SmallVector<Requirement, 2> reqs;
207-
SmallVector<InverseRequirement, 2> inverseReqs;
208-
genericSignature->getRequirementsWithInverses(reqs, inverseReqs);
209-
assert(inverseReqs.empty() && "Non-copyable generics not supported here!");
210-
assert(reqs.empty());
197+
assert(cxx_translation::isExposableToCxx(genericSignature));
211198

212199
// FIXME: Can we make some better layout than opaque layout for generic
213200
// types.

0 commit comments

Comments
 (0)