Skip to content

Commit 22b46d3

Browse files
author
Gabor Horvath
committed
[cxx-interop] Mark some zero-sized value types as unavailable
Currently, we do not support exporting zero-sized value types from Swift to C++. It needs some work on our end as these types are not part of the lowered signature. In the meantime, this PR makes sure that common (but not all) zero sized types are properly marked as unavailable. This is important as the proper diagnostic will give users a hint how to work around this problem. Moreover, it is really easy to hit this when someone is experimenting with interop, so it is important to not have a cryptic failure mode. rdar://138122545
1 parent 72615fe commit 22b46d3

File tree

9 files changed

+85
-7
lines changed

9 files changed

+85
-7
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,6 +2086,8 @@ ERROR(unexposed_other_decl_in_cxx,none,
20862086
"%kind0 is not yet exposed to C++", (ValueDecl *))
20872087
ERROR(unsupported_other_decl_in_cxx,none,
20882088
"Swift %kind0 cannot be represented in C++", (ValueDecl *))
2089+
ERROR(expose_zero_size_to_cxx,none,
2090+
"%0 is a zero sized value type, it cannot be exposed to C++ yet", (ValueDecl *))
20892091

20902092
ERROR(attr_methods_only,none,
20912093
"only methods can be declared %0", (DeclAttribute))

include/swift/AST/SwiftNameTranslation.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
#define SWIFT_NAME_TRANSLATION_H
1515

1616
#include "swift/AST/AttrKind.h"
17+
#include "swift/AST/Decl.h"
1718
#include "swift/AST/DiagnosticEngine.h"
1819
#include "swift/AST/Identifier.h"
20+
#include <optional>
1921

2022
namespace swift {
2123

@@ -84,6 +86,7 @@ enum RepresentationError {
8486
UnrepresentableMoveOnly,
8587
UnrepresentableNested,
8688
UnrepresentableMacro,
89+
UnrepresentableZeroSizedValueType,
8790
};
8891

8992
/// Constructs a diagnostic that describes the given C++ representation error.
@@ -99,11 +102,15 @@ struct DeclRepresentation {
99102
};
100103

101104
/// Returns the C++ representation info for the given declaration.
102-
DeclRepresentation getDeclRepresentation(const ValueDecl *VD);
105+
DeclRepresentation getDeclRepresentation(
106+
const ValueDecl *VD,
107+
std::optional<std::function<bool(const NominalTypeDecl *)>> isZeroSized);
103108

104109
/// Returns true if the given value decl is exposable to C++.
105-
inline bool isExposableToCxx(const ValueDecl *VD) {
106-
return !getDeclRepresentation(VD).isUnsupported();
110+
inline bool isExposableToCxx(
111+
const ValueDecl *VD,
112+
std::optional<std::function<bool(const NominalTypeDecl *)>> isZeroSized) {
113+
return !getDeclRepresentation(VD, isZeroSized).isUnsupported();
107114
}
108115

109116
/// Returns true if the given value decl D is visible to C++ of its

lib/AST/SwiftNameTranslation.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "swift/AST/LazyResolver.h"
2222
#include "swift/AST/Module.h"
2323
#include "swift/AST/ParameterList.h"
24+
#include "swift/AST/Type.h"
25+
#include "swift/AST/Types.h"
2426
#include "swift/Basic/Assertions.h"
2527
#include "swift/Basic/StringExtras.h"
2628

@@ -212,7 +214,9 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
212214
}
213215

214216
swift::cxx_translation::DeclRepresentation
215-
swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
217+
swift::cxx_translation::getDeclRepresentation(
218+
const ValueDecl *VD,
219+
std::optional<std::function<bool(const NominalTypeDecl *)>> isZeroSized) {
216220
if (getActorIsolation(const_cast<ValueDecl *>(VD)).isActorIsolated())
217221
return {Unsupported, UnrepresentableIsolatedInActor};
218222
if (isa<MacroDecl>(VD))
@@ -253,6 +257,8 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
253257
isa_and_nonnull<NominalTypeDecl>(
254258
typeDecl->getDeclContext()->getAsDecl()))
255259
return {Unsupported, UnrepresentableNested};
260+
if (!isa<ClassDecl>(typeDecl) && isZeroSized && (*isZeroSized)(typeDecl))
261+
return {Unsupported, UnrepresentableZeroSizedValueType};
256262
}
257263
if (const auto *varDecl = dyn_cast<VarDecl>(VD)) {
258264
// Check if any property accessor throws, do not expose it in that case.
@@ -393,5 +399,7 @@ swift::cxx_translation::diagnoseRepresenationError(RepresentationError error,
393399
return Diagnostic(diag::expose_nested_type_to_cxx, vd);
394400
case UnrepresentableMacro:
395401
return Diagnostic(diag::expose_macro_to_cxx, vd);
402+
case UnrepresentableZeroSizedValueType:
403+
return Diagnostic(diag::expose_zero_size_to_cxx, vd);
396404
}
397405
}

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2958,7 +2958,9 @@ bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
29582958
if (outputLang == OutputLanguageMode::Cxx) {
29592959
if (!isExposedToThisModule(M, VD, exposedModules))
29602960
return false;
2961-
if (!cxx_translation::isExposableToCxx(VD))
2961+
if (!cxx_translation::isExposableToCxx(
2962+
VD,
2963+
[this](const NominalTypeDecl *decl) { return isZeroSized(decl); }))
29622964
return false;
29632965
if (!isEnumExposableToCxx(VD, *this))
29642966
return false;
@@ -2976,6 +2978,16 @@ bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
29762978
return true;
29772979
}
29782980

2981+
bool DeclAndTypePrinter::isZeroSized(const NominalTypeDecl *decl) {
2982+
if (decl->isResilient())
2983+
return false;
2984+
auto &abiDetails = interopContext.getIrABIDetails();
2985+
auto sizeAndAlignment = abiDetails.getTypeSizeAlignment(decl);
2986+
if (sizeAndAlignment)
2987+
return sizeAndAlignment->size == 0;
2988+
return false;
2989+
}
2990+
29792991
bool DeclAndTypePrinter::isVisible(const ValueDecl *vd) const {
29802992
return outputLang == OutputLanguageMode::Cxx
29812993
? cxx_translation::isVisibleToCxx(vd, minRequiredAccess)

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class DeclAndTypePrinter {
118118
/// the options the printer was constructed with.
119119
bool shouldInclude(const ValueDecl *VD);
120120

121+
bool isZeroSized(const NominalTypeDecl *decl);
122+
121123
/// Returns true if \p vd is visible given the current access level and thus
122124
/// can be included in the generated header.
123125
bool isVisible(const ValueDecl *vd) const;

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,10 @@ class ModuleWriter {
952952

953953
// Emit an unavailable stub for a Swift type.
954954
if (auto *nmtd = dyn_cast<NominalTypeDecl>(vd)) {
955-
auto representation = cxx_translation::getDeclRepresentation(vd);
955+
auto representation = cxx_translation::getDeclRepresentation(
956+
vd, [this](const NominalTypeDecl *decl) {
957+
return printer.isZeroSized(decl);
958+
});
956959
if (nmtd->isGeneric()) {
957960
auto genericSignature =
958961
nmtd->getGenericSignature().getCanonicalSignature();

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
208208
// e.g. it has resilient fields.
209209
if (typeSizeAlign && typeSizeAlign->size == 0) {
210210
// FIXME: How to represent 0 sized structs?
211+
declAndTypePrinter.getCxxDeclEmissionScope()
212+
.additionalUnrepresentableDeclarations.push_back(typeDecl);
211213
return;
212214
}
213215
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "llvm/ADT/MapVector.h"
5151
#include "llvm/ADT/STLExtras.h"
5252
#include "llvm/Support/Debug.h"
53+
#include <optional>
5354

5455
using namespace swift;
5556

@@ -2321,7 +2322,7 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
23212322
}
23222323

23232324
// Verify that the declaration is exposable.
2324-
auto repr = cxx_translation::getDeclRepresentation(VD);
2325+
auto repr = cxx_translation::getDeclRepresentation(VD, std::nullopt);
23252326
if (repr.isUnsupported())
23262327
diagnose(attr->getLocation(),
23272328
cxx_translation::diagnoseRepresenationError(*repr.error, VD));

test/Interop/SwiftToCxx/structs/zero-sized-struct-in-cxx.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,45 @@
88

99
public struct ZeroSizedStruct {}
1010

11+
public struct ZeroSizedStruct2 {
12+
var property: ZeroSizedStruct
13+
var void: Void
14+
var bar: ()
15+
public init() {
16+
property = .init()
17+
}
18+
}
19+
20+
public enum ZeroSizedEnum {
21+
}
22+
23+
public enum ZeroSizedEnum2 {
24+
case foo
25+
}
26+
27+
public enum ZeroSizedEnum3 {
28+
case foo(ZeroSizedStruct, ZeroSizedEnum, ZeroSizedStruct2)
29+
}
30+
31+
public func f() -> ZeroSizedStruct {
32+
ZeroSizedStruct()
33+
}
34+
35+
public func g(x: ZeroSizedStruct) {
36+
}
37+
38+
// CHECK: class ZeroSizedEnum { } SWIFT_UNAVAILABLE_MSG("'ZeroSizedEnum' is a zero sized value type, it cannot be exposed to C++ yet");
39+
40+
// CHECK: class ZeroSizedEnum2 { } SWIFT_UNAVAILABLE_MSG("'ZeroSizedEnum2' is a zero sized value type, it cannot be exposed to C++ yet");
41+
42+
// CHECK: class ZeroSizedEnum3 { } SWIFT_UNAVAILABLE_MSG("'ZeroSizedEnum3' is a zero sized value type, it cannot be exposed to C++ yet");
43+
44+
// CHECK: class ZeroSizedStruct { } SWIFT_UNAVAILABLE_MSG("'ZeroSizedStruct' is a zero sized value type, it cannot be exposed to C++ yet");
45+
46+
// CHECK: class ZeroSizedStruct2 { } SWIFT_UNAVAILABLE_MSG("'ZeroSizedStruct2' is a zero sized value type, it cannot be exposed to C++ yet");
47+
48+
// CHECK: // Unavailable in C++: Swift global function 'f()'.
49+
50+
// CHECK: // Unavailable in C++: Swift global function 'g(x:)'.
51+
1152
// CHECK: } // namespace Structs

0 commit comments

Comments
 (0)