Skip to content

Commit 708782d

Browse files
authored
Merge pull request #77100 from swiftlang/gaborh/empty-value-type-diagnostic
[cxx-interop] Mark some zero-sized value types as unavailable
2 parents 2747057 + 22b46d3 commit 708782d

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)