Skip to content

Commit dc581b9

Browse files
committed
Support foreign reference types when C++ interop is disabled.
1 parent 485c8cc commit dc581b9

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
@@ -6328,37 +6328,41 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
63286328
return CxxRecordSemanticsKind::Reference;
63296329
}
63306330

6331-
if (!hasRequiredValueTypeOperations(decl)) {
6332-
if (hasUnsafeAPIAttr(decl))
6331+
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
6332+
if (!cxxDecl)
6333+
return CxxRecordSemanticsKind::Trivial;
6334+
6335+
if (!hasRequiredValueTypeOperations(cxxDecl)) {
6336+
if (hasUnsafeAPIAttr(cxxDecl))
63336337
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
63346338
"import_unsafe", decl->getNameAsString());
6335-
if (hasOwnedValueAttr(decl))
6339+
if (hasOwnedValueAttr(cxxDecl))
63366340
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
63376341
"import_owned", decl->getNameAsString());
6338-
if (hasIteratorAPIAttr(decl))
6342+
if (hasIteratorAPIAttr(cxxDecl))
63396343
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
63406344
"import_iterator", decl->getNameAsString());
63416345

63426346
return CxxRecordSemanticsKind::MissingLifetimeOperation;
63436347
}
63446348

6345-
if (hasUnsafeAPIAttr(decl)) {
6349+
if (hasUnsafeAPIAttr(cxxDecl)) {
63466350
return CxxRecordSemanticsKind::ExplicitlyUnsafe;
63476351
}
63486352

6349-
if (hasOwnedValueAttr(decl)) {
6353+
if (hasOwnedValueAttr(cxxDecl)) {
63506354
return CxxRecordSemanticsKind::Owned;
63516355
}
63526356

6353-
if (hasIteratorAPIAttr(decl) || isIterator(decl)) {
6357+
if (hasIteratorAPIAttr(cxxDecl) || isIterator(cxxDecl)) {
63546358
return CxxRecordSemanticsKind::Iterator;
63556359
}
63566360

6357-
if (hasPointerInSubobjects(decl)) {
6361+
if (hasPointerInSubobjects(cxxDecl)) {
63586362
return CxxRecordSemanticsKind::UnsafePointerMember;
63596363
}
63606364

6361-
if (isSufficientlyTrivial(decl)) {
6365+
if (isSufficientlyTrivial(cxxDecl)) {
63626366
return CxxRecordSemanticsKind::Trivial;
63636367
}
63646368

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)