Skip to content

Commit eedc7c2

Browse files
committed
Sema: Update more diagnostics for @cdecl vs @objc
1 parent 0600ddd commit eedc7c2

File tree

5 files changed

+187
-44
lines changed

5 files changed

+187
-44
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5516,10 +5516,14 @@ FIXIT(insert_globalactor_attr, "@%0 ", (Type))
55165516
ERROR(main_function_must_be_mainActor,none,
55175517
"main() must be '@MainActor'", ())
55185518

5519+
// Keep aligned with enum ForeignLanguage
5520+
#define FOREIGN_LANG_SELECT "select{C|Objective-C}"
5521+
55195522
ERROR(not_objc_function_async,none,
55205523
"'async' %0 cannot be represented in Objective-C", (DescriptiveDeclKind))
55215524
NOTE(not_objc_function_type_async,none,
5522-
"'async' function types cannot be represented in Objective-C", ())
5525+
"'async' function types cannot be represented "
5526+
"in %" FOREIGN_LANG_SELECT "0", (ForeignLanguage))
55235527
ERROR(actor_isolated_objc,none,
55245528
"actor-isolated %kind0 cannot be '@objc'",
55255529
(const ValueDecl *))
@@ -6528,9 +6532,6 @@ ERROR(objc_cannot_infer_name_raw_identifier,none,
65286532
// If you change this, also change enum ObjCReason
65296533
#define OBJC_ATTR_SELECT "select{marked '@cdecl'|marked '@_cdecl'|marked dynamic|marked '@objc'|marked '@objcMembers'|marked '@IBOutlet'|marked '@IBAction'|marked '@IBSegueAction'|marked '@NSManaged'|a member of an '@objc' protocol|implicitly '@objc'|an '@objc' override|an implementation of an '@objc' requirement|marked '@IBInspectable'|marked '@GKInspectable'|in an '@objc' extension of a class (without '@nonobjc')|in an '@objc @implementation' extension of a class (without final or '@nonobjc')|marked '@objc' by an access note}"
65306534

6531-
// Keep aligned with enum ForeignLanguage
6532-
#define FOREIGN_LANG_SELECT "select{C|Objective-C}"
6533-
65346535
ERROR(objc_invalid_on_var,none,
65356536
"property cannot be %" OBJC_ATTR_SELECT "0 "
65366537
"because its type cannot be represented in Objective-C", (unsigned))
@@ -6562,25 +6563,32 @@ NOTE(not_objc_error_protocol_composition,none,
65626563
"protocol-constrained type containing 'Error' cannot be represented "
65636564
"in Objective-C", ())
65646565
NOTE(not_objc_empty_tuple,none,
6565-
"empty tuple type cannot be represented in Objective-C", ())
6566+
"empty tuple type cannot be represented in %" FOREIGN_LANG_SELECT "0",
6567+
(ForeignLanguage))
65666568
NOTE(not_objc_non_trivial_cxx_class,none,
6567-
"non-trivial C++ classes cannot be represented in Objective-C", ())
6569+
"non-trivial C++ classes cannot be represented in "
6570+
"%" FOREIGN_LANG_SELECT "0",
6571+
(ForeignLanguage))
65686572
NOTE(not_objc_tuple,none,
6569-
"tuples cannot be represented in Objective-C", ())
6573+
"tuples cannot be represented in %" FOREIGN_LANG_SELECT "0",
6574+
(ForeignLanguage))
65706575
NOTE(not_objc_swift_class,none,
65716576
"classes not annotated with '@objc' cannot be represented "
65726577
"in Objective-C", ())
65736578
NOTE(not_objc_swift_struct,none,
6574-
"Swift structs cannot be represented in Objective-C", ())
6579+
"Swift structs cannot be represented in %" FOREIGN_LANG_SELECT "0",
6580+
(ForeignLanguage))
65756581
NOTE(not_objc_swift_enum,none,
65766582
"non-'@objc' enums cannot be represented in Objective-C", ())
65776583
NOTE(not_objc_generic_type_param,none,
6578-
"generic type parameters cannot be represented in Objective-C", ())
6584+
"generic type parameters cannot be represented in "
6585+
"%" FOREIGN_LANG_SELECT "0", (ForeignLanguage))
65796586
NOTE(not_objc_function_type_param,none,
6580-
"function types cannot be represented in Objective-C unless their "
6581-
"parameters and returns can be", ())
6587+
"function types cannot be represented in %" FOREIGN_LANG_SELECT "0 "
6588+
"unless their parameters and returns can be", (ForeignLanguage))
65826589
NOTE(not_objc_function_type_throwing,none,
6583-
"throwing function types cannot be represented in Objective-C", ())
6590+
"throwing function types cannot be represented in "
6591+
"%" FOREIGN_LANG_SELECT "0", (ForeignLanguage))
65846592
NOTE(objc_inferring_on_objc_protocol_member,none,
65856593
"inferring '@objc' because the declaration is a member of "
65866594
"an '@objc' protocol", ())
@@ -6590,6 +6598,11 @@ NOTE(objc_witness_objc_requirement,none,
65906598
"satisfying requirement for %kind0 in protocol %1",
65916599
(const ValueDecl *, const ProtocolDecl *))
65926600

6601+
NOTE(cdecl_incompatible_with_protocols,none,
6602+
"protocols cannot be represented in C", ())
6603+
NOTE(cdecl_incompatible_with_classes,none,
6604+
"classes cannot be represented in C", ())
6605+
65936606
ERROR(no_opaque_return_type_of,none,
65946607
"unable to resolve type for _opaqueReturnTypeOf attribute", ())
65956608

@@ -6602,8 +6615,8 @@ ERROR(objc_addressor, none,
66026615
ERROR(objc_coroutine_accessor, none,
66036616
"'read' and 'modify' accessors are not allowed to be marked '@objc'", ())
66046617
ERROR(objc_invalid_on_func_variadic,none,
6605-
"method cannot be %" OBJC_ATTR_SELECT "0 because it has a variadic "
6606-
"parameter", (unsigned))
6618+
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because it has a variadic "
6619+
"parameter", (const AbstractFunctionDecl*, unsigned))
66076620
ERROR(objc_invalid_on_func_inout,none,
66086621
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because inout "
66096622
"parameters cannot be represented in %" FOREIGN_LANG_SELECT "2",

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -169,24 +169,32 @@ void ObjCReason::setAttrInvalid() const {
169169
static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
170170
Type T,
171171
SourceRange TypeRange,
172-
DiagnosticBehavior behavior) {
172+
DiagnosticBehavior behavior,
173+
ObjCReason reason) {
173174
auto &diags = DC->getASTContext().Diags;
175+
auto language = reason.getForeignLanguage();
174176

175177
// Special diagnostic for tuples.
176178
if (T->is<TupleType>()) {
177179
if (T->isVoid())
178-
diags.diagnose(TypeRange.Start, diag::not_objc_empty_tuple)
180+
diags.diagnose(TypeRange.Start, diag::not_objc_empty_tuple, language)
179181
.highlight(TypeRange)
180182
.limitBehavior(behavior);
181183
else
182-
diags.diagnose(TypeRange.Start, diag::not_objc_tuple)
184+
diags.diagnose(TypeRange.Start, diag::not_objc_tuple, language)
183185
.highlight(TypeRange)
184186
.limitBehavior(behavior);
185187
return;
186188
}
187189

188190
// Special diagnostic for classes.
189191
if (auto *CD = T->getClassOrBoundGenericClass()) {
192+
if (language == ForeignLanguage::C) {
193+
diags.diagnose(TypeRange.Start, diag::cdecl_incompatible_with_classes)
194+
.limitBehavior(behavior);
195+
return;
196+
}
197+
190198
if (!CD->isObjC())
191199
diags.diagnose(TypeRange.Start, diag::not_objc_swift_class)
192200
.highlight(TypeRange)
@@ -198,12 +206,14 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
198206
if (auto *SD = T->getStructOrBoundGenericStruct()) {
199207
if (isa_and_nonnull<clang::CXXRecordDecl>(SD->getClangDecl())) {
200208
// This can be a non-trivial C++ record.
201-
diags.diagnose(TypeRange.Start, diag::not_objc_non_trivial_cxx_class)
209+
diags.diagnose(TypeRange.Start, diag::not_objc_non_trivial_cxx_class,
210+
language)
202211
.highlight(TypeRange)
203212
.limitBehavior(behavior);
204213
return;
205214
}
206-
diags.diagnose(TypeRange.Start, diag::not_objc_swift_struct)
215+
diags.diagnose(TypeRange.Start, diag::not_objc_swift_struct,
216+
language)
207217
.highlight(TypeRange)
208218
.limitBehavior(behavior);
209219
return;
@@ -219,6 +229,13 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
219229

220230
// Special diagnostic for protocols and protocol compositions.
221231
if (T->isExistentialType()) {
232+
// No protocol is representable in C.
233+
if (language == ForeignLanguage::C) {
234+
diags.diagnose(TypeRange.Start, diag::cdecl_incompatible_with_protocols)
235+
.limitBehavior(behavior);
236+
return;
237+
}
238+
222239
if (T->isAny()) {
223240
// Any is not @objc.
224241
diags.diagnose(TypeRange.Start,
@@ -266,28 +283,32 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
266283
}
267284

268285
if (T->is<ArchetypeType>() || T->isTypeParameter()) {
269-
diags.diagnose(TypeRange.Start, diag::not_objc_generic_type_param)
286+
diags.diagnose(TypeRange.Start, diag::not_objc_generic_type_param,
287+
language)
270288
.highlight(TypeRange)
271289
.limitBehavior(behavior);
272290
return;
273291
}
274292

275293
if (auto fnTy = T->getAs<FunctionType>()) {
276294
if (fnTy->getExtInfo().isAsync()) {
277-
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_async)
295+
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_async,
296+
language)
278297
.highlight(TypeRange)
279298
.limitBehavior(behavior);
280299
return;
281300
}
282301

283302
if (fnTy->getExtInfo().isThrowing()) {
284-
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_throwing)
303+
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_throwing,
304+
language)
285305
.highlight(TypeRange)
286306
.limitBehavior(behavior);
287307
return;
288308
}
289309

290-
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_param)
310+
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_param,
311+
language)
291312
.highlight(TypeRange)
292313
.limitBehavior(behavior);
293314
return;
@@ -318,11 +339,12 @@ static void diagnoseFunctionParamNotRepresentable(
318339
if (P->hasAttachedPropertyWrapper()) {
319340
auto wrapperTy = P->getPropertyWrapperBackingPropertyType();
320341
SR = P->getOutermostAttachedPropertyWrapper()->getRange();
321-
diagnoseTypeNotRepresentableInObjC(AFD, wrapperTy, SR, behavior);
342+
diagnoseTypeNotRepresentableInObjC(AFD, wrapperTy, SR, behavior, Reason);
322343
} else {
323344
if (auto typeRepr = P->getTypeRepr())
324345
SR = typeRepr->getSourceRange();
325-
diagnoseTypeNotRepresentableInObjC(AFD, P->getTypeInContext(), SR, behavior);
346+
diagnoseTypeNotRepresentableInObjC(AFD, P->getTypeInContext(), SR,
347+
behavior, Reason);
326348
}
327349
Reason.describe(AFD);
328350
}
@@ -344,7 +366,7 @@ static bool isParamListRepresentableInLanguage(const AbstractFunctionDecl *AFD,
344366
if (param->isVariadic()) {
345367
softenIfAccessNote(AFD, Reason.getAttr(),
346368
diags.diagnose(param->getStartLoc(), diag::objc_invalid_on_func_variadic,
347-
getObjCDiagnosticAttrKind(Reason))
369+
AFD, getObjCDiagnosticAttrKind(Reason))
348370
.highlight(param->getSourceRange())
349371
.limitBehavior(behavior));
350372
Reason.describe(AFD);
@@ -805,7 +827,7 @@ bool swift::isRepresentableInLanguage(
805827
.limitBehavior(behavior));
806828
diagnoseTypeNotRepresentableInObjC(FD, ResultType,
807829
FD->getResultTypeSourceRange(),
808-
behavior);
830+
behavior, Reason);
809831
Reason.describe(FD);
810832
return false;
811833
}
@@ -862,7 +884,7 @@ bool swift::isRepresentableInLanguage(
862884
.limitBehavior(behavior));
863885
diagnoseTypeNotRepresentableInObjC(FD, type,
864886
FD->getResultTypeSourceRange(),
865-
behavior);
887+
behavior, Reason);
866888
Reason.describe(FD);
867889

868890
return true;
@@ -1170,7 +1192,7 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
11701192
.limitBehavior(behavior));
11711193
diagnoseTypeNotRepresentableInObjC(VD->getDeclContext(),
11721194
VD->getInterfaceType(),
1173-
TypeRange, behavior);
1195+
TypeRange, behavior, Reason);
11741196
Reason.describe(VD);
11751197
}
11761198

@@ -1259,7 +1281,7 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) {
12591281
diagnoseTypeNotRepresentableInObjC(SD->getDeclContext(),
12601282
!IndexResult ? IndexType
12611283
: ElementType,
1262-
TypeRange, behavior);
1284+
TypeRange, behavior, Reason);
12631285
Reason.describe(SD);
12641286
}
12651287

test/attr/attr_cdecl_official.swift

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/// @cdecl attribute
2+
/// This test shouldn't require the objc runtime.
3+
14
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s \
25
// RUN: -enable-experimental-feature CDecl -disable-objc-interop
36

@@ -31,7 +34,9 @@ enum SwiftEnum { case A, B }
3134
#endif
3235

3336
@cdecl("swiftStruct")
34-
func swiftStruct(x: SwiftStruct) {} // expected-error{{cannot be represented}} expected-note{{Swift struct}}
37+
func swiftStruct(x: SwiftStruct) {}
38+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
39+
// expected-note @-2 {{Swift structs cannot be represented in C}}
3540

3641
@cdecl("swiftEnum")
3742
func swiftEnum(x: SwiftEnum) {} // expected-error{{cannot be represented}} expected-note{{non-'@objc' enum}}
@@ -65,9 +70,97 @@ func acceptedPointers(_ x: UnsafeMutablePointer<Int>,
6570

6671
@cdecl("rejectedPointers")
6772
func rejectedPointers( // expected-error 6 {{global function cannot be marked '@cdecl' because the type of the parameter}}
68-
x: UnsafePointer<String>, // expected-note {{Swift structs cannot be represented in Objective-C}} // FIXME: Should reference C.
69-
y: CVaListPointer, // expected-note {{Swift structs cannot be represented in Objective-C}}
70-
z: UnsafeBufferPointer<Int>, // expected-note {{Swift structs cannot be represented in Objective-C}}
71-
u: UnsafeMutableBufferPointer<Int>, // expected-note {{Swift structs cannot be represented in Objective-C}}
72-
v: UnsafeRawBufferPointer, // expected-note {{Swift structs cannot be represented in Objective-C}}
73-
t: UnsafeMutableRawBufferPointer) {} // expected-note {{Swift structs cannot be represented in Objective-C}}
73+
x: UnsafePointer<String>, // expected-note {{Swift structs cannot be represented in C}}
74+
y: CVaListPointer, // expected-note {{Swift structs cannot be represented in C}}
75+
z: UnsafeBufferPointer<Int>, // expected-note {{Swift structs cannot be represented in C}}
76+
u: UnsafeMutableBufferPointer<Int>, // expected-note {{Swift structs cannot be represented in C}}
77+
v: UnsafeRawBufferPointer, // expected-note {{Swift structs cannot be represented in C}}
78+
t: UnsafeMutableRawBufferPointer) {} // expected-note {{Swift structs cannot be represented in C}}
79+
80+
@cdecl("genericParam")
81+
func genericParam<I>(i: I) {}
82+
// expected-error @-1 {{global function cannot be marked '@cdecl' because it has generic parameters}}
83+
84+
@cdecl("variadic")
85+
func variadic(_: Int...) {}
86+
// expected-error @-1 {{global function cannot be marked '@cdecl' because it has a variadic parameter}}
87+
88+
@cdecl("tupleParamEmpty")
89+
func tupleParamEmpty(a: ()) {}
90+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
91+
// expected-note @-2 {{empty tuple type cannot be represented in C}}
92+
93+
@cdecl("tupleParam")
94+
func tupleParam(a: (Int, Float)) {}
95+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
96+
// expected-note @-2 {{tuples cannot be represented in C}}
97+
98+
@cdecl("emptyTupleReturn")
99+
func emptyTupleReturn() -> () {}
100+
101+
@cdecl("tupleReturn")
102+
func tupleReturn() -> (Int, Float) { (1, 2.0) }
103+
// expected-error @-1 {{global function cannot be marked '@cdecl' because its result type cannot be represented in C}}
104+
// expected-note @-2 {{tuples cannot be represented in C}}
105+
106+
@cdecl("funcAcceptsThrowingFunc")
107+
func funcAcceptsThrowingFunc(fn: (String) throws -> Int) { }
108+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
109+
// expected-note @-2 {{throwing function types cannot be represented in C}}
110+
111+
@cdecl("funcAcceptsThrowingFuncReturn")
112+
func funcAcceptsThrowingFuncReturn() -> (String) throws -> Int { fatalError() }
113+
// expected-error @-1 {{global function cannot be marked '@cdecl' because its result type cannot be represented in C}}
114+
// expected-note @-2 {{throwing function types cannot be represented in C}}
115+
116+
@cdecl("bar")
117+
func bar(f: (SwiftEnum) -> SwiftStruct) {}
118+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
119+
// expected-note @-2 {{function types cannot be represented in C unless their parameters and returns can be}}
120+
121+
@cdecl("bas")
122+
func bas(f: (SwiftEnum) -> ()) {}
123+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
124+
// expected-note @-2 {{function types cannot be represented in C unless their parameters and returns can be}}
125+
126+
@cdecl("zim")
127+
func zim(f: () -> SwiftStruct) {}
128+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
129+
// expected-note @-2 {{function types cannot be represented in C unless their parameters and returns can be}}
130+
131+
@cdecl("zang")
132+
func zang(f: (SwiftEnum, SwiftStruct) -> ()) {}
133+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
134+
// expected-note @-2 {{function types cannot be represented in C unless their parameters and returns can be}}
135+
136+
@cdecl("zang_zang")
137+
func zangZang(f: (Int...) -> ()) {}
138+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
139+
// expected-note @-2 {{function types cannot be represented in C unless their parameters and returns can be}}
140+
141+
@cdecl("array")
142+
func array(i: [Int]) {}
143+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
144+
// expected-note @-2 {{Swift structs cannot be represented in C}}
145+
146+
class SwiftClass {}
147+
@cdecl("swiftClass")
148+
func swiftClass(p: SwiftClass) {}
149+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
150+
// expected-note @-2 {{classes cannot be represented in C}}
151+
152+
protocol SwiftProtocol {}
153+
@cdecl("swiftProtocol")
154+
func swiftProtocol(p: SwiftProtocol) {}
155+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
156+
// expected-note @-2 {{protocols cannot be represented in C}}
157+
158+
@cdecl("swiftErrorProtocol")
159+
func swiftErrorProtocol(e: Error) {}
160+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
161+
// expected-note @-2 {{protocols cannot be represented in C}}
162+
163+
@cdecl("anyParam")
164+
func anyParam(e:Any) {}
165+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
166+
// expected-note @-2 {{protocols cannot be represented in C}}

test/attr/attr_cdecl_official_async.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// RUN: %target-typecheck-verify-swift -enable-objc-interop -disable-availability-checking -enable-experimental-feature CDecl
1+
// RUN: %target-typecheck-verify-swift -enable-objc-interop \
2+
// RUN: -disable-availability-checking \
3+
// RUN: -enable-experimental-feature CDecl
24

35
// REQUIRES: concurrency
46
// REQUIRES: swift_feature_CDecl
@@ -9,3 +11,7 @@ func asynchronous() async { }
911
@cdecl("async2") // expected-error{{@cdecl global function cannot be asynchronous}}
1012
func asynchronous2() async { }
1113

14+
@cdecl("asyncParam")
15+
func asynchronousParam(fn: (String) async -> Int) { }
16+
// expected-error @-1 {{global function cannot be marked '@cdecl' because the type of the parameter cannot be represented in C}}
17+
// expected-note @-2 {{'async' function types cannot be represented in C}}

0 commit comments

Comments
 (0)