Skip to content

Commit ef84f0e

Browse files
committed
Sema: Update more diagnostics for @cdecl vs @objc
1 parent bb99891 commit ef84f0e

File tree

5 files changed

+184
-41
lines changed

5 files changed

+184
-41
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5512,11 +5512,15 @@ FIXIT(insert_globalactor_attr, "@%0 ", (Type))
55125512
ERROR(main_function_must_be_mainActor,none,
55135513
"main() must be '@MainActor'", ())
55145514

5515+
// Keep aligned with enum ForeignLanguage
5516+
#define FOREIGN_LANG_SELECT "select{C|Objective-C}"
5517+
55155518
ERROR(not_objc_function_async,none,
55165519
"'async' %kindonly0 cannot be represented in Objective-C",
55175520
(const AbstractFunctionDecl *))
55185521
NOTE(not_objc_function_type_async,none,
5519-
"'async' function types cannot be represented in Objective-C", ())
5522+
"'async' function types cannot be represented "
5523+
"in %" FOREIGN_LANG_SELECT "0", (ForeignLanguage))
55205524
ERROR(actor_isolated_objc,none,
55215525
"actor-isolated %kind0 cannot be '@objc'",
55225526
(const ValueDecl *))
@@ -6529,9 +6533,6 @@ ERROR(objc_cannot_infer_name_raw_identifier,none,
65296533
// If you change this, also change enum ObjCReason
65306534
#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}"
65316535

6532-
// Keep aligned with enum ForeignLanguage
6533-
#define FOREIGN_LANG_SELECT "select{C|Objective-C}"
6534-
65356536
ERROR(objc_invalid_on_var,none,
65366537
"property cannot be %" OBJC_ATTR_SELECT "0 "
65376538
"because its type cannot be represented in Objective-C", (unsigned))
@@ -6566,25 +6567,32 @@ NOTE(not_objc_error_protocol_composition,none,
65666567
"protocol-constrained type containing 'Error' cannot be represented "
65676568
"in Objective-C", ())
65686569
NOTE(not_objc_empty_tuple,none,
6569-
"empty tuple type cannot be represented in Objective-C", ())
6570+
"empty tuple type cannot be represented in %" FOREIGN_LANG_SELECT "0",
6571+
(ForeignLanguage))
65706572
NOTE(not_objc_non_trivial_cxx_class,none,
6571-
"non-trivial C++ classes cannot be represented in Objective-C", ())
6573+
"non-trivial C++ classes cannot be represented in "
6574+
"%" FOREIGN_LANG_SELECT "0",
6575+
(ForeignLanguage))
65726576
NOTE(not_objc_tuple,none,
6573-
"tuples cannot be represented in Objective-C", ())
6577+
"tuples cannot be represented in %" FOREIGN_LANG_SELECT "0",
6578+
(ForeignLanguage))
65746579
NOTE(not_objc_swift_class,none,
65756580
"classes not annotated with '@objc' cannot be represented "
65766581
"in Objective-C", ())
65776582
NOTE(not_objc_swift_struct,none,
6578-
"Swift structs cannot be represented in Objective-C", ())
6583+
"Swift structs cannot be represented in %" FOREIGN_LANG_SELECT "0",
6584+
(ForeignLanguage))
65796585
NOTE(not_objc_swift_enum,none,
65806586
"non-'@objc' enums cannot be represented in Objective-C", ())
65816587
NOTE(not_objc_generic_type_param,none,
6582-
"generic type parameters cannot be represented in Objective-C", ())
6588+
"generic type parameters cannot be represented in "
6589+
"%" FOREIGN_LANG_SELECT "0", (ForeignLanguage))
65836590
NOTE(not_objc_function_type_param,none,
6584-
"function types cannot be represented in Objective-C unless their "
6585-
"parameters and returns can be", ())
6591+
"function types cannot be represented in %" FOREIGN_LANG_SELECT "0 "
6592+
"unless their parameters and returns can be", (ForeignLanguage))
65866593
NOTE(not_objc_function_type_throwing,none,
6587-
"throwing function types cannot be represented in Objective-C", ())
6594+
"throwing function types cannot be represented in "
6595+
"%" FOREIGN_LANG_SELECT "0", (ForeignLanguage))
65886596
NOTE(objc_inferring_on_objc_protocol_member,none,
65896597
"inferring '@objc' because the declaration is a member of "
65906598
"an '@objc' protocol", ())
@@ -6594,6 +6602,11 @@ NOTE(objc_witness_objc_requirement,none,
65946602
"satisfying requirement for %kind0 in protocol %1",
65956603
(const ValueDecl *, const ProtocolDecl *))
65966604

6605+
NOTE(cdecl_incompatible_with_protocols,none,
6606+
"protocols cannot be represented in C", ())
6607+
NOTE(cdecl_incompatible_with_classes,none,
6608+
"classes cannot be represented in C", ())
6609+
65976610
ERROR(no_opaque_return_type_of,none,
65986611
"unable to resolve type for _opaqueReturnTypeOf attribute", ())
65996612

@@ -6607,8 +6620,8 @@ ERROR(objc_addressor, none,
66076620
ERROR(objc_coroutine_accessor, none,
66086621
"'read' and 'modify' accessors are not allowed to be marked '@objc'", ())
66096622
ERROR(objc_invalid_on_func_variadic,none,
6610-
"method cannot be %" OBJC_ATTR_SELECT "0 because it has a variadic "
6611-
"parameter", (unsigned))
6623+
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because it has a variadic "
6624+
"parameter", (const AbstractFunctionDecl*, unsigned))
66126625
ERROR(objc_invalid_on_func_inout,none,
66136626
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because inout "
66146627
"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
@@ -170,24 +170,32 @@ void ObjCReason::setAttrInvalid() const {
170170
static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
171171
Type T,
172172
SourceRange TypeRange,
173-
DiagnosticBehavior behavior) {
173+
DiagnosticBehavior behavior,
174+
ObjCReason reason) {
174175
auto &diags = DC->getASTContext().Diags;
176+
auto language = reason.getForeignLanguage();
175177

176178
// Special diagnostic for tuples.
177179
if (T->is<TupleType>()) {
178180
if (T->isVoid())
179-
diags.diagnose(TypeRange.Start, diag::not_objc_empty_tuple)
181+
diags.diagnose(TypeRange.Start, diag::not_objc_empty_tuple, language)
180182
.highlight(TypeRange)
181183
.limitBehavior(behavior);
182184
else
183-
diags.diagnose(TypeRange.Start, diag::not_objc_tuple)
185+
diags.diagnose(TypeRange.Start, diag::not_objc_tuple, language)
184186
.highlight(TypeRange)
185187
.limitBehavior(behavior);
186188
return;
187189
}
188190

189191
// Special diagnostic for classes.
190192
if (auto *CD = T->getClassOrBoundGenericClass()) {
193+
if (language == ForeignLanguage::C) {
194+
diags.diagnose(TypeRange.Start, diag::cdecl_incompatible_with_classes)
195+
.limitBehavior(behavior);
196+
return;
197+
}
198+
191199
if (!CD->isObjC())
192200
diags.diagnose(TypeRange.Start, diag::not_objc_swift_class)
193201
.highlight(TypeRange)
@@ -199,12 +207,14 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
199207
if (auto *SD = T->getStructOrBoundGenericStruct()) {
200208
if (isa_and_nonnull<clang::CXXRecordDecl>(SD->getClangDecl())) {
201209
// This can be a non-trivial C++ record.
202-
diags.diagnose(TypeRange.Start, diag::not_objc_non_trivial_cxx_class)
210+
diags.diagnose(TypeRange.Start, diag::not_objc_non_trivial_cxx_class,
211+
language)
203212
.highlight(TypeRange)
204213
.limitBehavior(behavior);
205214
return;
206215
}
207-
diags.diagnose(TypeRange.Start, diag::not_objc_swift_struct)
216+
diags.diagnose(TypeRange.Start, diag::not_objc_swift_struct,
217+
language)
208218
.highlight(TypeRange)
209219
.limitBehavior(behavior);
210220
return;
@@ -220,6 +230,13 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
220230

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

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

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

284303
if (fnTy->getExtInfo().isThrowing()) {
285-
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_throwing)
304+
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_throwing,
305+
language)
286306
.highlight(TypeRange)
287307
.limitBehavior(behavior);
288308
return;
289309
}
290310

291-
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_param)
311+
diags.diagnose(TypeRange.Start, diag::not_objc_function_type_param,
312+
language)
292313
.highlight(TypeRange)
293314
.limitBehavior(behavior);
294315
return;
@@ -319,11 +340,12 @@ static void diagnoseFunctionParamNotRepresentable(
319340
if (P->hasAttachedPropertyWrapper()) {
320341
auto wrapperTy = P->getPropertyWrapperBackingPropertyType();
321342
SR = P->getOutermostAttachedPropertyWrapper()->getRange();
322-
diagnoseTypeNotRepresentableInObjC(AFD, wrapperTy, SR, behavior);
343+
diagnoseTypeNotRepresentableInObjC(AFD, wrapperTy, SR, behavior, Reason);
323344
} else {
324345
if (auto typeRepr = P->getTypeRepr())
325346
SR = typeRepr->getSourceRange();
326-
diagnoseTypeNotRepresentableInObjC(AFD, P->getTypeInContext(), SR, behavior);
347+
diagnoseTypeNotRepresentableInObjC(AFD, P->getTypeInContext(), SR,
348+
behavior, Reason);
327349
}
328350
Reason.describe(AFD);
329351
}
@@ -345,7 +367,7 @@ static bool isParamListRepresentableInLanguage(const AbstractFunctionDecl *AFD,
345367
if (param->isVariadic()) {
346368
softenIfAccessNote(AFD, Reason.getAttr(),
347369
diags.diagnose(param->getStartLoc(), diag::objc_invalid_on_func_variadic,
348-
getObjCDiagnosticAttrKind(Reason))
370+
AFD, getObjCDiagnosticAttrKind(Reason))
349371
.highlight(param->getSourceRange())
350372
.limitBehavior(behavior));
351373
Reason.describe(AFD);
@@ -804,7 +826,7 @@ bool swift::isRepresentableInLanguage(
804826
.limitBehavior(behavior));
805827
diagnoseTypeNotRepresentableInObjC(FD, ResultType,
806828
FD->getResultTypeSourceRange(),
807-
behavior);
829+
behavior, Reason);
808830
Reason.describe(FD);
809831
return false;
810832
}
@@ -861,7 +883,7 @@ bool swift::isRepresentableInLanguage(
861883
.limitBehavior(behavior));
862884
diagnoseTypeNotRepresentableInObjC(FD, type,
863885
FD->getResultTypeSourceRange(),
864-
behavior);
886+
behavior, Reason);
865887
Reason.describe(FD);
866888

867889
return true;
@@ -1168,7 +1190,7 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
11681190
.limitBehavior(behavior));
11691191
diagnoseTypeNotRepresentableInObjC(VD->getDeclContext(),
11701192
VD->getInterfaceType(),
1171-
TypeRange, behavior);
1193+
TypeRange, behavior, Reason);
11721194
Reason.describe(VD);
11731195
}
11741196

@@ -1256,7 +1278,7 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) {
12561278
diagnoseTypeNotRepresentableInObjC(SD->getDeclContext(),
12571279
!IndexResult ? IndexType
12581280
: ElementType,
1259-
TypeRange, behavior);
1281+
TypeRange, behavior, Reason);
12601282
Reason.describe(SD);
12611283
}
12621284

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)