Skip to content

Commit 777eafc

Browse files
authored
Merge pull request #61752 from zoecarver/enable-frt-no-cxx-interop
Support foreign reference types when C++ interop is disabled.
2 parents 80b54a8 + dc581b9 commit 777eafc

File tree

6 files changed

+131
-19
lines changed

6 files changed

+131
-19
lines changed

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,10 @@ enum class CxxRecordSemanticsKind {
315315
};
316316

317317
struct CxxRecordSemanticsDescriptor final {
318-
const clang::CXXRecordDecl *decl;
318+
const clang::RecordDecl *decl;
319319
ASTContext &ctx;
320320

321-
CxxRecordSemanticsDescriptor(const clang::CXXRecordDecl *decl,
321+
CxxRecordSemanticsDescriptor(const clang::RecordDecl *decl,
322322
ASTContext &ctx)
323323
: decl(decl), ctx(ctx) {}
324324

lib/ClangImporter/ClangImporter.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6333,37 +6333,41 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
63336333
return CxxRecordSemanticsKind::Reference;
63346334
}
63356335

6336-
if (!hasRequiredValueTypeOperations(decl)) {
6337-
if (hasUnsafeAPIAttr(decl))
6336+
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
6337+
if (!cxxDecl)
6338+
return CxxRecordSemanticsKind::Trivial;
6339+
6340+
if (!hasRequiredValueTypeOperations(cxxDecl)) {
6341+
if (hasUnsafeAPIAttr(cxxDecl))
63386342
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
63396343
"import_unsafe", decl->getNameAsString());
6340-
if (hasOwnedValueAttr(decl))
6344+
if (hasOwnedValueAttr(cxxDecl))
63416345
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
63426346
"import_owned", decl->getNameAsString());
6343-
if (hasIteratorAPIAttr(decl))
6347+
if (hasIteratorAPIAttr(cxxDecl))
63446348
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
63456349
"import_iterator", decl->getNameAsString());
63466350

63476351
return CxxRecordSemanticsKind::MissingLifetimeOperation;
63486352
}
63496353

6350-
if (hasUnsafeAPIAttr(decl)) {
6354+
if (hasUnsafeAPIAttr(cxxDecl)) {
63516355
return CxxRecordSemanticsKind::ExplicitlyUnsafe;
63526356
}
63536357

6354-
if (hasOwnedValueAttr(decl)) {
6358+
if (hasOwnedValueAttr(cxxDecl)) {
63556359
return CxxRecordSemanticsKind::Owned;
63566360
}
63576361

6358-
if (hasIteratorAPIAttr(decl) || isIterator(decl)) {
6362+
if (hasIteratorAPIAttr(cxxDecl) || isIterator(cxxDecl)) {
63596363
return CxxRecordSemanticsKind::Iterator;
63606364
}
63616365

6362-
if (hasPointerInSubobjects(decl)) {
6366+
if (hasPointerInSubobjects(cxxDecl)) {
63636367
return CxxRecordSemanticsKind::UnsafePointerMember;
63646368
}
63656369

6366-
if (isSufficientlyTrivial(decl)) {
6370+
if (isSufficientlyTrivial(cxxDecl)) {
63676371
return CxxRecordSemanticsKind::Trivial;
63686372
}
63696373

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,14 +1945,10 @@ namespace {
19451945
}
19461946

19471947
bool recordHasReferenceSemantics(const clang::RecordDecl *decl) {
1948-
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(decl)) {
1949-
auto semanticsKind = evaluateOrDefault(
1950-
Impl.SwiftContext.evaluator,
1951-
CxxRecordSemantics({cxxRecord, Impl.SwiftContext}), {});
1952-
return semanticsKind == CxxRecordSemanticsKind::Reference;
1953-
}
1954-
1955-
return false;
1948+
auto semanticsKind = evaluateOrDefault(
1949+
Impl.SwiftContext.evaluator,
1950+
CxxRecordSemantics({decl, Impl.SwiftContext}), {});
1951+
return semanticsKind == CxxRecordSemanticsKind::Reference;
19561952
}
19571953

19581954
Decl *VisitRecordDecl(const clang::RecordDecl *decl) {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#ifndef TEST_INTEROP_C_INPUTS_FOREIGN_REFERENCE_H
2+
#define TEST_INTEROP_C_INPUTS_FOREIGN_REFERENCE_H
3+
4+
#include <stdlib.h>
5+
6+
#if __has_feature(nullability)
7+
// Provide macros to temporarily suppress warning about the use of
8+
// _Nullable and _Nonnull.
9+
# define SWIFT_BEGIN_NULLABILITY_ANNOTATIONS \
10+
_Pragma("clang diagnostic push") \
11+
_Pragma("clang diagnostic ignored \"-Wnullability-extension\"") \
12+
_Pragma("clang assume_nonnull begin")
13+
# define SWIFT_END_NULLABILITY_ANNOTATIONS \
14+
_Pragma("clang diagnostic pop") \
15+
_Pragma("clang assume_nonnull end")
16+
17+
#else
18+
// #define _Nullable and _Nonnull to nothing if we're not being built
19+
// with a compiler that supports them.
20+
# define _Nullable
21+
# define _Nonnull
22+
# define _Null_unspecified
23+
# define SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
24+
# define SWIFT_END_NULLABILITY_ANNOTATIONS
25+
#endif
26+
27+
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
28+
29+
struct
30+
__attribute__((swift_attr("import_as_ref")))
31+
__attribute__((swift_attr("retain:LCRetain")))
32+
__attribute__((swift_attr("release:LCRelease")))
33+
LocalCount {
34+
int value;
35+
};
36+
37+
static inline struct LocalCount *createLocalCount() {
38+
struct LocalCount *ptr = malloc(sizeof(struct LocalCount));
39+
ptr->value = 1;
40+
return ptr;
41+
}
42+
43+
static inline void LCRetain(struct LocalCount *x) { x->value++; }
44+
static inline void LCRelease(struct LocalCount *x) { x->value--; }
45+
46+
static int globalCount = 0;
47+
48+
struct
49+
__attribute__((swift_attr("import_as_ref")))
50+
__attribute__((swift_attr("retain:GCRetain")))
51+
__attribute__((swift_attr("release:GCRelease")))
52+
GlobalCount {};
53+
54+
static inline struct GlobalCount *createGlobalCount() {
55+
globalCount++;
56+
return malloc(sizeof(struct GlobalCount));
57+
}
58+
59+
static inline void GCRetain(struct GlobalCount *x) { globalCount++; }
60+
static inline void GCRelease(struct GlobalCount *x) { globalCount--; }
61+
62+
SWIFT_END_NULLABILITY_ANNOTATIONS
63+
64+
#endif // TEST_INTEROP_C_INPUTS_FOREIGN_REFERENCE_H

test/Interop/C/struct/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@ module StructDeclContext {
22
header "struct-decl-context.h"
33
export *
44
}
5+
6+
module ForeignReference {
7+
header "foreign-reference.h"
8+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -validate-tbd-against-ir=none)
2+
//
3+
// REQUIRES: executable_test
4+
// TODO: This should work without ObjC interop in the future rdar://97497120
5+
// REQUIRES: objc_interop
6+
7+
import StdlibUnittest
8+
import ForeignReference
9+
10+
var ReferenceCountedTestSuite = TestSuite("Foreign reference types that have reference counts")
11+
12+
@inline(never)
13+
public func blackHole<T>(_ _: T) { }
14+
15+
ReferenceCountedTestSuite.test("Local") {
16+
var x = createLocalCount()
17+
expectEqual(x.value, 6) // This is 6 because of "var x" "x.value" * 2 and "(x, x, x)".
18+
19+
let t = (x, x, x)
20+
expectEqual(x.value, 5)
21+
}
22+
23+
@inline(never)
24+
func globalTest1() {
25+
var x = createGlobalCount()
26+
let t = (x, x, x)
27+
expectEqual(globalCount, 4)
28+
blackHole(t)
29+
}
30+
31+
@inline(never)
32+
func globalTest2() {
33+
var x = createGlobalCount()
34+
expectEqual(globalCount, 1)
35+
}
36+
37+
ReferenceCountedTestSuite.test("Global") {
38+
expectEqual(globalCount, 0)
39+
globalTest1()
40+
globalTest2()
41+
expectEqual(globalCount, 0)
42+
}
43+
44+
runAllTests()

0 commit comments

Comments
 (0)