Skip to content

Commit c4d6515

Browse files
authored
Merge pull request #67668 from hyp/eng/reverse-interop-simd-nested-fixes
[interop][SwiftToCxx] simd and nested type fixes
2 parents c2fc7ee + 1c380be commit c4d6515

File tree

10 files changed

+123
-17
lines changed

10 files changed

+123
-17
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,6 +1849,8 @@ ERROR(expose_protocol_to_cxx_unsupported,none,
18491849
"protocol %0 can not yet be represented in C++", (ValueDecl *))
18501850
ERROR(expose_move_only_to_cxx,none,
18511851
"noncopyable %kind0 can not yet be represented in C++", (ValueDecl *))
1852+
ERROR(expose_nested_type_to_cxx,none,
1853+
"nested %kind0 can not yet be represented in C++", (ValueDecl *))
18521854
ERROR(unexposed_other_decl_in_cxx,none,
18531855
"%kind0 is not yet exposed to C++", (ValueDecl *))
18541856
ERROR(unsupported_other_decl_in_cxx,none,

include/swift/AST/SwiftNameTranslation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ enum RepresentationError {
7979
UnrepresentableEnumCaseTuple,
8080
UnrepresentableProtocol,
8181
UnrepresentableMoveOnly,
82+
UnrepresentableNested,
8283
};
8384

8485
/// Constructs a diagnostic that describes the given C++ representation error.

lib/AST/SwiftNameTranslation.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
235235
genericSignature =
236236
typeDecl->getGenericSignature().getCanonicalSignature();
237237
}
238+
// Nested types are not yet supported.
239+
if (!typeDecl->hasClangNode() &&
240+
isa_and_nonnull<NominalTypeDecl>(
241+
typeDecl->getDeclContext()->getAsDecl()))
242+
return {Unsupported, UnrepresentableNested};
238243
}
239244
if (const auto *varDecl = dyn_cast<VarDecl>(VD)) {
240245
// Check if any property accessor throws, do not expose it in that case.
@@ -321,5 +326,7 @@ swift::cxx_translation::diagnoseRepresenationError(RepresentationError error,
321326
return Diagnostic(diag::expose_protocol_to_cxx_unsupported, vd);
322327
case UnrepresentableMoveOnly:
323328
return Diagnostic(diag::expose_move_only_to_cxx, vd);
329+
case UnrepresentableNested:
330+
return Diagnostic(diag::expose_nested_type_to_cxx, vd);
324331
}
325332
}

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclInnerStaticAssert(
9696
}
9797

9898
void ClangSyntaxPrinter::printClangTypeReference(const clang::Decl *typeDecl) {
99+
if (cast<clang::NamedDecl>(typeDecl)->getDeclName().isEmpty() &&
100+
isa<clang::TagDecl>(typeDecl)) {
101+
if (auto *tnd =
102+
cast<clang::TagDecl>(typeDecl)->getTypedefNameForAnonDecl()) {
103+
printClangTypeReference(tnd);
104+
return;
105+
}
106+
}
99107
auto &clangCtx = typeDecl->getASTContext();
100108
clang::PrintingPolicy pp(clangCtx.getLangOpts());
101109
const auto *NS = clang::NestedNameSpecifier::getRequiredQualification(

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,10 @@ static std::string encodeTypeInfo(const T &abiTypeInfo,
556556
return std::move(typeEncodingOS.str());
557557
}
558558

559+
// Returns false if the given direct type is not yet supported because
560+
// of its ABI.
559561
template <class T>
560-
static void printDirectReturnOrParamCType(
562+
static bool printDirectReturnOrParamCType(
561563
const T &abiTypeInfo, Type valueType, const ModuleDecl *emittedModule,
562564
raw_ostream &os, raw_ostream &cPrologueOS,
563565
PrimitiveTypeMapping &typeMapping,
@@ -575,20 +577,21 @@ static void printDirectReturnOrParamCType(
575577

576578
unsigned Count = 0;
577579
clang::CharUnits lastOffset;
578-
abiTypeInfo.enumerateRecordMembers(
579-
[&](clang::CharUnits offset, clang::CharUnits end, Type t) {
580+
if (abiTypeInfo.enumerateRecordMembers([&](clang::CharUnits offset,
581+
clang::CharUnits end, Type t) {
580582
lastOffset = offset;
581583
++Count;
582584
addABIRecordToTypeEncoding(typeEncodingOS, offset, end, t, typeMapping);
583-
});
585+
}))
586+
return false;
584587
assert(Count > 0 && "missing return values");
585588

586589
// FIXME: is this "prettyfying" logic sound for multiple return values?
587590
if (isKnownCType(valueType, typeMapping) ||
588591
(Count == 1 && lastOffset.isZero() && !valueType->hasTypeParameter() &&
589592
valueType->isAnyClassReferenceType())) {
590593
prettifiedValuePrinter();
591-
return;
594+
return true;
592595
}
593596

594597
os << "struct " << typeEncodingOS.str();
@@ -642,6 +645,7 @@ static void printDirectReturnOrParamCType(
642645
interopContext.runIfStubForDeclNotEmitted(typeEncodingOS.str(), [&]() {
643646
printStub(cPrologueOS, typeEncodingOS.str());
644647
});
648+
return true;
645649
}
646650

647651
/// Make adjustments to the Swift parameter name in generated C++, to
@@ -750,18 +754,20 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
750754
if (!directResultType) {
751755
os << "void";
752756
} else {
753-
printDirectReturnOrParamCType(
754-
*directResultType, resultTy, emittedModule, os, cPrologueOS,
755-
typeMapping, interopContext, [&]() {
756-
OptionalTypeKind retKind;
757-
Type objTy;
758-
std::tie(objTy, retKind) =
759-
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
760-
761-
auto s = printClangFunctionReturnType(objTy, retKind, emittedModule,
762-
outputLang);
763-
assert(!s.isUnsupported());
764-
});
757+
if (!printDirectReturnOrParamCType(
758+
*directResultType, resultTy, emittedModule, os, cPrologueOS,
759+
typeMapping, interopContext, [&]() {
760+
OptionalTypeKind retKind;
761+
Type objTy;
762+
std::tie(objTy, retKind) =
763+
DeclAndTypePrinter::getObjectTypeAndOptionality(FD,
764+
resultTy);
765+
766+
auto s = printClangFunctionReturnType(
767+
objTy, retKind, emittedModule, outputLang);
768+
assert(!s.isUnsupported());
769+
}))
770+
return ClangRepresentation::unsupported;
765771
}
766772
} else {
767773
OptionalTypeKind retKind;

test/Inputs/clang-importer-sdk/usr/include/simd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ typedef double __attribute__((ext_vector_type(3))) double3;
3939
typedef double __attribute__((ext_vector_type(4))) double4;
4040
typedef double __attribute__((ext_vector_type(8))) double8;
4141

42+
typedef struct { float4 columns[4]; } float4x4;
43+
4244
// Types that we should not be able to import.
4345
typedef char __attribute__((ext_vector_type(17))) char17;
4446
typedef unsigned char __attribute__((ext_vector_type(21))) uchar21;
@@ -89,6 +91,7 @@ ushort6 makes_ushort6();
8991
int128 makes_int128();
9092
uint20 makes_uint20();
9193

94+
#ifndef SIMD_NO_CODE
9295
takes_char2(char2);
9396
takes_char64(char64);
9497
takes_uchar3(uchar3);
@@ -130,3 +133,4 @@ takes_short5(short5);
130133
takes_ushort6(ushort6);
131134
takes_int128(int128);
132135
takes_uint20(uint20);
136+
#endif

test/Interop/CxxToSwiftToCxx/bridge-cxx-struct-back-to-cxx.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ namespace ns {
8080

8181
using SimpleTypedef = int;
8282

83+
typedef struct { float column; } anonymousStruct;
84+
85+
namespace ns {
86+
87+
using anonStructInNS = struct { float row; };
88+
89+
}
90+
8391
//--- module.modulemap
8492
module CxxTest {
8593
header "header.h"
@@ -149,6 +157,12 @@ public func takeTrivial(_ x: Trivial) {
149157
public func takeTrivialInout(_ x: inout Trivial) {
150158
}
151159

160+
@_expose(Cxx)
161+
public struct Strct {
162+
public let transform: anonymousStruct
163+
public let transform2: ns.anonStructInNS
164+
}
165+
152166
// CHECK: #if __has_feature(objc_modules)
153167
// CHECK: #if __has_feature(objc_modules)
154168
// CHECK-NEXT: #if __has_warning("-Watimport-in-framework-header")
@@ -284,3 +298,9 @@ public func takeTrivialInout(_ x: inout Trivial) {
284298
// CHECK: SWIFT_INLINE_THUNK void takeTrivialInout(Trivial& x) noexcept SWIFT_SYMBOL({{.*}}) {
285299
// CHECK-NEXT: return _impl::$s8UseCxxTy16takeTrivialInoutyySo0E0VzF(swift::_impl::getOpaquePointer(x));
286300
// CHECK-NEXT: }
301+
302+
// CHECK: SWIFT_INLINE_THUNK anonymousStruct Strct::getTransform() const {
303+
// CHECK-NEXT: alignas(alignof(anonymousStruct)) char storage[sizeof(anonymousStruct)];
304+
305+
// CHECK: SWIFT_INLINE_THUNK ns::anonStructInNS Strct::getTransform2() const {
306+
// CHECK-NEXT: alignas(alignof(ns::anonStructInNS)) char storage[sizeof(ns::anonStructInNS)];
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/use-cxx-types.swift -typecheck -module-name UseCxxTy -emit-clang-header-path %t/UseCxxTy.h -I %t -enable-experimental-cxx-interop -disable-availability-checking -Xcc -DSIMD_NO_CODE
5+
6+
// RUN: %FileCheck %s < %t/UseCxxTy.h
7+
8+
// FIXME: remove once https://github.com/apple/swift/pull/60971 lands.
9+
// RUN: echo "#include \"header.h\"" > %t/full-cxx-swift-cxx-bridging.h
10+
// RUN: cat %t/UseCxxTy.h >> %t/full-cxx-swift-cxx-bridging.h
11+
12+
// RUN: %check-interop-cxx-header-in-clang(%t/full-cxx-swift-cxx-bridging.h -Wno-reserved-identifier -DSIMD_NO_CODE)
13+
14+
// This is required to verify that `Struct` is returned and passed directly.
15+
// REQUIRES: OS=macosx
16+
// REQUIRES: PTRSIZE=64
17+
18+
//--- header.h
19+
20+
#include <simd.h>
21+
22+
using simd_float4x4 = float4x4;
23+
24+
//--- module.modulemap
25+
module CxxTest {
26+
header "header.h"
27+
requires cplusplus
28+
}
29+
30+
//--- use-cxx-types.swift
31+
import CxxTest
32+
33+
public struct Struct {
34+
private let transform: simd_float4x4
35+
36+
public init() {
37+
transform = simd_float4x4()
38+
}
39+
}
40+
41+
public func passStruct(_ x : Struct) {
42+
43+
}
44+
45+
// CHECK: class SWIFT_SYMBOL("s:8UseCxxTy6StructV") Struct final {
46+
// CHECK-NOT: init(
47+
// CHECK: // Unavailable in C++: Swift global function 'passStruct(_:)'

test/Interop/SwiftToCxx/unsupported/unsupported-decls-in-cxx.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,7 @@ public distributed actor DistributedActorClass {
6464

6565
@_expose(Cxx) // ok
6666
nonisolated public var prop2: Int { 42 }
67+
68+
@_expose(Cxx) // expected-error {{nested struct 'NestedStruct' can not yet be represented in C++}}
69+
public struct NestedStruct {}
6770
}

test/Interop/SwiftToCxx/unsupported/unsupported-types-in-cxx.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@ public protocol TestProtocol {}
3434
public typealias unsupportedTypeAlias = () -> (Float, Float)
3535

3636
// CHECK: // Unavailable in C++: Swift type alias 'unsupportedTypeAlias'
37+
38+
public struct Container {
39+
public struct NestedStruct {}
40+
}
41+
42+
public typealias unsupportedTypeAliasNested = Container.NestedStruct
43+
44+
// CHECK: // Unavailable in C++: Swift type alias 'unsupportedTypeAliasNested'

0 commit comments

Comments
 (0)