Skip to content

Commit a3c62ca

Browse files
committed
[Sema] Allow @objc on enum cases
1 parent cd9d2b5 commit a3c62ca

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ SIMPLE_DECL_ATTR(final, Final,
9292

9393
DECL_ATTR(objc, ObjC,
9494
OnFunc | OnClass | OnProtocol | OnVar | OnSubscript |
95-
OnConstructor | OnDestructor | OnEnum, 3)
95+
OnConstructor | OnDestructor | OnEnum | OnEnumElement, 3)
9696

9797
SIMPLE_DECL_ATTR(required, Required,
9898
OnConstructor|DeclModifier, 4)

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2333,7 +2333,7 @@ ERROR(objc_setter_for_nonobjc_subscript,sema_tcd,none,
23332333
ERROR(objc_enum_generic,sema_tcd,none,
23342334
"'@objc' enum cannot be generic", ())
23352335
ERROR(objc_name_req_nullary,sema_objc,none,
2336-
"'@objc' %select{class|protocol|enum|property}0 must have a simple name", (int))
2336+
"'@objc' %select{class|protocol|enum|enum case|property}0 must have a simple name", (int))
23372337
ERROR(objc_name_subscript,sema_objc,none,
23382338
"'@objc' subscript cannot have a name; did you mean to put "
23392339
"the name on the getter or setter?", ())
@@ -2343,6 +2343,13 @@ ERROR(objc_name_func_mismatch,sema_objc,none,
23432343
"%select{initializer|method}0 has %select{one parameter|%3 parameters}4"
23442344
"%select{| (%select{|including }4the error parameter)}5",
23452345
(bool, unsigned, bool, unsigned, bool, bool))
2346+
ERROR(objc_enum_case_req_name,sema_objc,none,
2347+
"attribute has no effect; cases within an '@objc' enum are already "
2348+
"exposed to Objective-C", ())
2349+
ERROR(objc_enum_case_req_objc_enum,sema_objc,none,
2350+
"'@objc' enum case is not allowed outside of an '@objc' enum", ())
2351+
ERROR(objc_enum_case_multi,sema_objc,none,
2352+
"'@objc' enum case declaration defines multiple enum cases with the same Objective-C name", ())
23462353

23472354
// If you change this, also change enum ObjCReason
23482355
#define OBJC_ATTR_SELECT "select{marked dynamic|marked @objc|marked @IBOutlet|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override}"

lib/Sema/TypeCheckDecl.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7004,6 +7004,12 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
70047004
} else if (auto ED = dyn_cast<EnumDecl>(D)) {
70057005
if (ED->isGenericContext())
70067006
error = diag::objc_enum_generic;
7007+
} else if (auto EED = dyn_cast<EnumElementDecl>(D)) {
7008+
auto ED = EED->getParentEnum();
7009+
if (!ED->getAttrs().hasAttribute<ObjCAttr>())
7010+
error = diag::objc_enum_case_req_objc_enum;
7011+
else if (objcAttr->hasName() && EED->getParentCase()->getElements().size() > 1)
7012+
error = diag::objc_enum_case_multi;
70077013
} else if (isa<FuncDecl>(D)) {
70087014
auto func = cast<FuncDecl>(D);
70097015
if (!checkObjCDeclContext(D))
@@ -7033,16 +7039,17 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
70337039
// If there is a name, check whether the kind of name is
70347040
// appropriate.
70357041
if (auto objcName = objcAttr->getName()) {
7036-
if (isa<ClassDecl>(D) || isa<ProtocolDecl>(D) || isa<EnumDecl>(D) ||
7037-
isa<VarDecl>(D)) {
7042+
if (isa<ClassDecl>(D) || isa<ProtocolDecl>(D) || isa<VarDecl>(D)
7043+
|| isa<EnumDecl>(D) || isa<EnumElementDecl>(D)) {
70387044
// Types and properties can only have nullary
70397045
// names. Complain and recover by chopping off everything
70407046
// after the first name.
70417047
if (objcName->getNumArgs() > 0) {
70427048
int which = isa<ClassDecl>(D)? 0
70437049
: isa<ProtocolDecl>(D)? 1
70447050
: isa<EnumDecl>(D)? 2
7045-
: 3;
7051+
: isa<EnumElementDecl>(D)? 3
7052+
: 4;
70467053
SourceLoc firstNameLoc = objcAttr->getNameLocs().front();
70477054
SourceLoc afterFirstNameLoc =
70487055
Lexer::getLocForEndOfToken(TC.Context.SourceMgr, firstNameLoc);
@@ -7091,6 +7098,11 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
70917098
D->getAttrs().removeAttribute(objcAttr);
70927099
}
70937100
}
7101+
} else if (isa<EnumElementDecl>(D)) {
7102+
// Enum elements require names.
7103+
TC.diagnose(objcAttr->getLocation(), diag::objc_enum_case_req_name)
7104+
.fixItRemove(objcAttr->getRangeWithAt());
7105+
objcAttr->setInvalid();
70947106
}
70957107
}
70967108

test/attr/attr_objc.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,33 @@ extension subject_genericClass {
194194

195195
@objc
196196
enum subject_enum: Int {
197-
@objc // expected-error {{@objc cannot be applied to this declaration}} {{3-9=}}
197+
@objc // expected-error {{attribute has no effect; cases within an '@objc' enum are already exposed to Objective-C}} {{3-9=}}
198198
case subject_enumElement1
199199

200+
@objc(subject_enumElement2)
201+
case subject_enumElement2
202+
203+
@objc(subject_enumElement3)
204+
case subject_enumElement3, subject_enumElement4 // expected-error {{'@objc' enum case declaration defines multiple enum cases with the same Objective-C name}}{{3-8=}}
205+
206+
@objc // expected-error {{attribute has no effect; cases within an '@objc' enum are already exposed to Objective-C}} {{3-9=}}
207+
case subject_enumElement5, subject_enumElement6
208+
209+
@nonobjc // expected-error {{@nonobjc cannot be applied to this declaration}}
210+
case subject_enumElement7
211+
200212
@objc
201213
init() {} // expected-error {{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} {{3-9=}}
202214

203215
@objc
204216
func subject_instanceFunc() {} // expected-error {{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} {{3-8=}}
205217
}
206218

219+
enum subject_enum2 {
220+
@objc(subject_enum2Element1)
221+
case subject_enumElement1 // expected-error{{'@objc' enum case is not allowed outside of an '@objc' enum}}{{3-8=}}
222+
}
223+
207224
@objc
208225
protocol subject_protocol1 {
209226
@objc
@@ -1752,6 +1769,12 @@ protocol BadProto1 { }
17521769
@objc(Enum:) // expected-error{{'@objc' enum must have a simple name}}{{11-12=}}
17531770
enum BadEnum1: Int { case X }
17541771

1772+
@objc
1773+
enum BadEnum2: Int {
1774+
@objc(X:) // expected-error{{'@objc' enum case must have a simple name}}{{10-11=}}
1775+
case X
1776+
}
1777+
17551778
class BadClass2 {
17561779
@objc(badprop:foo:wibble:) // expected-error{{'@objc' property must have a simple name}}{{16-28=}}
17571780
var badprop: Int = 5

0 commit comments

Comments
 (0)