Skip to content

Commit c2e15d6

Browse files
committed
[cxx-interop] disallow use of non-trivial C++ types in @objc declarations
Even though such types can technically be represented in C++, Swift's @objc support does not support them rdar://114163485
1 parent 41dc466 commit c2e15d6

File tree

4 files changed

+80
-0
lines changed

4 files changed

+80
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6084,6 +6084,8 @@ NOTE(not_objc_error_protocol_composition,none,
60846084
"in Objective-C", ())
60856085
NOTE(not_objc_empty_tuple,none,
60866086
"empty tuple type cannot be represented in Objective-C", ())
6087+
NOTE(not_objc_non_trivial_cxx_class,none,
6088+
"non-trivial C++ classes cannot be represented in Objective-C", ())
60876089
NOTE(not_objc_tuple,none,
60886090
"tuples cannot be represented in Objective-C", ())
60896091
NOTE(not_objc_swift_class,none,

lib/AST/Type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3096,6 +3096,17 @@ getForeignRepresentable(Type type, ForeignLanguage language,
30963096

30973097
case ForeignLanguage::ObjectiveC:
30983098
if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
3099+
// Non-trivial C++ classes and structures are not
3100+
// supported by @objc attribute, even though they can
3101+
// be represented in Objective-C++.
3102+
if (auto *cxxRec = dyn_cast_or_null<clang::CXXRecordDecl>(
3103+
nominal->getClangDecl())) {
3104+
if (cxxRec->hasNonTrivialCopyConstructor() ||
3105+
cxxRec->hasNonTrivialMoveConstructor() ||
3106+
cxxRec->hasNonTrivialDestructor())
3107+
return failure();
3108+
}
3109+
30993110
// Optional structs are not representable in (Objective-)C if they
31003111
// originally came from C, whether or not they are bridged, unless they
31013112
// came from swift_newtype. If they are defined in Swift, they are only

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
179179

180180
// Special diagnostic for structs.
181181
if (auto *SD = T->getStructOrBoundGenericStruct()) {
182+
if (isa_and_nonnull<clang::CXXRecordDecl>(SD->getClangDecl())) {
183+
// This can be a non-trivial C++ record.
184+
diags.diagnose(TypeRange.Start, diag::not_objc_non_trivial_cxx_class)
185+
.highlight(TypeRange)
186+
.limitBehavior(behavior);
187+
return;
188+
}
182189
diags.diagnose(TypeRange.Start, diag::not_objc_swift_struct)
183190
.highlight(TypeRange)
184191
.limitBehavior(behavior);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -typecheck -I %t/Inputs -cxx-interoperability-mode=default -verify %t/test.swift
5+
6+
// REQUIRES: objc_interop
7+
8+
//--- Inputs/header.h
9+
10+
class Trivial {
11+
public:
12+
int x;
13+
};
14+
15+
class NonTrivial {
16+
public:
17+
NonTrivial(const NonTrivial &other) : x(other.x) {}
18+
~NonTrivial() { }
19+
20+
private:
21+
int x;
22+
};
23+
24+
struct NonTrivialDestrOnly {
25+
~NonTrivialDestrOnly() { }
26+
27+
private:
28+
int x;
29+
};
30+
31+
//--- Inputs/module.modulemap
32+
33+
module NonTrivial {
34+
header "header.h"
35+
export *
36+
}
37+
38+
//--- test.swift
39+
40+
import Foundation
41+
import NonTrivial
42+
43+
@objc
44+
class ObjCObject: NSObject {
45+
@objc var prop: NonTrivial // expected-error {{property cannot be marked @objc because its type cannot be represented in Objective-C}}
46+
// expected-note@-1 {{non-trivial C++ classes cannot be represented in Objective-C}}
47+
48+
@objc var trivProp: Trivial
49+
50+
override init() { fatalError() }
51+
52+
@objc func getNonTrivial() -> NonTrivialDestrOnly { // expected-error {{method cannot be marked @objc because its result type cannot be represented in Objective-C}}
53+
// expected-note@-1 {{non-trivial C++ classes cannot be represented in Objective-C}}
54+
fatalError()
55+
}
56+
57+
@objc func getTrivial() -> Trivial {
58+
return Trivial(x: 11)
59+
}
60+
}

0 commit comments

Comments
 (0)