Skip to content

Make sure to allow '@objc' on enum elements #18910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lib/Sema/TypeCheckDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ bool swift::shouldDiagnoseObjCReason(ObjCReason reason, ASTContext &ctx) {

case ObjCReason::MemberOfObjCSubclass:
case ObjCReason::MemberOfObjCMembersClass:
case ObjCReason::ElementOfObjCEnum:
case ObjCReason::Accessor:
return false;
}
Expand All @@ -73,6 +74,7 @@ unsigned swift::getObjCDiagnosticAttrKind(ObjCReason reason) {

case ObjCReason::MemberOfObjCSubclass:
case ObjCReason::MemberOfObjCMembersClass:
case ObjCReason::ElementOfObjCEnum:
case ObjCReason::Accessor:
llvm_unreachable("should not diagnose this @objc reason");
}
Expand Down Expand Up @@ -1273,6 +1275,14 @@ IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const {
// as an arithmetic type in C.
if (isEnumObjC(enumDecl))
isObjC = ObjCReason(ObjCReason::ExplicitlyObjC);
} else if (auto enumElement = dyn_cast<EnumElementDecl>(VD)) {
// Enum elements can be @objc so long as the containing enum is @objc.
if (enumElement->getParentEnum()->isObjC()) {
if (enumElement->getAttrs().hasAttribute<ObjCAttr>())
isObjC = ObjCReason::ExplicitlyObjC;
else
isObjC = ObjCReason::ElementOfObjCEnum;
}
} else if (auto proto = dyn_cast<ProtocolDecl>(VD)) {
if (proto->getAttrs().hasAttribute<ObjCAttr>()) {
isObjC = ObjCReason(ObjCReason::ExplicitlyObjC);
Expand Down Expand Up @@ -1521,7 +1531,7 @@ void markAsObjC(ValueDecl *D, ObjCReason reason,
ctx.getLazyResolver()->resolveDeclSignature(D);
}

if (!isa<AccessorDecl>(D) && !isa<TypeDecl>(D)) {
if (!isa<TypeDecl>(D) && !isa<AccessorDecl>(D) && !isa<EnumElementDecl>(D)) {
useObjectiveCBridgeableConformances(D->getInnermostDeclContext(),
D->getInterfaceType());
}
Expand Down
5 changes: 5 additions & 0 deletions lib/Sema/TypeCheckObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,15 @@ class ObjCReason {
ExplicitlyGKInspectable,
/// Is it a member of an @objc extension of a class.
MemberOfObjCExtension,

// These kinds do not appear in diagnostics.

/// Is it a member of an @objcMembers class.
MemberOfObjCMembersClass,
/// A member of an Objective-C-defined class or subclass.
MemberOfObjCSubclass,
/// Is a member of an @objc enum.
ElementOfObjCEnum,
/// An accessor to a property.
Accessor,
};
Expand Down
6 changes: 6 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2186,6 +2186,12 @@ void Serializer::writeDeclAttribute(const DeclAttribute *DA) {
if (DA->isNotSerialized())
return;

// Ignore attributes that have been marked invalid. (This usually means
// type-checking removed them, but only provided a warning rather than an
// error.)
if (DA->isInvalid())
return;

switch (DA->getKind()) {
case DAK_RawDocComment:
case DAK_ReferenceOwnership: // Serialized as part of the type.
Expand Down
7 changes: 7 additions & 0 deletions test/PrintAsObjC/enums.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-source-import -emit-module -emit-module-doc -o %t %s -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %t/enums.swiftmodule -typecheck -emit-objc-header-path %t/enums.h -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module
// RUN: %FileCheck %s < %t/enums.h
// RUN: %FileCheck -check-prefix=NEGATIVE %s < %t/enums.h
// RUN: %check-in-clang %t/enums.h
// RUN: %check-in-clang -fno-modules -Qunused-arguments %t/enums.h -include ctypes.h -include CoreFoundation.h

// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-source-import -emit-module -o /dev/null -emit-module-doc-path /dev/null -module-name enums %s -emit-objc-header-path %t/enums.WMO.h -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module
// RUN: %FileCheck %s < %t/enums.WMO.h
// RUN: %FileCheck -check-prefix=NEGATIVE %s < %t/enums.WMO.h
// RUN: %check-in-clang %t/enums.WMO.h
// RUN: %check-in-clang -fno-modules -Qunused-arguments %t/enums.WMO.h -include ctypes.h -include CoreFoundation.h

// REQUIRES: objc_interop

import Foundation
Expand Down
14 changes: 14 additions & 0 deletions test/Serialization/attr-invalid.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/attr.swiftmodule %s -verify
// RUN: llvm-bcanalyzer -dump %t/attr.swiftmodule | %FileCheck -check-prefix=CHECK-NON-RESILIENT %s
// RUN: %target-swift-frontend -emit-module -o %t/attr_resilient.swiftmodule -enable-resilience -warnings-as-errors %s
// RUN: llvm-bcanalyzer -dump %t/attr_resilient.swiftmodule | %FileCheck -check-prefix=CHECK-RESILIENT %s

// These two should be checking for the same thing.
// CHECK-RESILIENT: Frozen_DECL_ATTR
// CHECK-NON-RESILIENT-NOT: Frozen_DECL_ATTR

@_frozen // expected-warning {{@_frozen has no effect without -enable-resilience}}
public enum SomeEnum {
case x
}
4 changes: 2 additions & 2 deletions test/api-digester/compare-dump.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %empty-directory(%t.mod)
// RUN: %empty-directory(%t.sdk)
// RUN: %empty-directory(%t.module-cache)
// RUN: %swift -emit-module -o %t.mod/cake1.swiftmodule %S/Inputs/cake1.swift -parse-as-library -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource
// RUN: %swift -emit-module -o %t.mod/cake2.swiftmodule %S/Inputs/cake2.swift -parse-as-library -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource
// RUN: %swift -emit-module -o %t.mod/cake1.swiftmodule %S/Inputs/cake1.swift -parse-as-library -enable-resilience -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource
// RUN: %swift -emit-module -o %t.mod/cake2.swiftmodule %S/Inputs/cake2.swift -parse-as-library -enable-resilience -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource
// RUN: %api-digester -dump-sdk -module cake1 -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod -I %S/Inputs/APINotesLeft
// RUN: %api-digester -dump-sdk -module cake2 -o %t.dump2.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod -I %S/Inputs/APINotesRight
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json > %t.result
Expand Down
4 changes: 4 additions & 0 deletions test/attr/attr_nonobjc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ protocol SR4226_Protocol : class {}
extension SR4226_Protocol {
@nonobjc func function() {} // expected-error {{only class members and extensions of classes can be declared @nonobjc}}
}

@objc enum SomeEnum: Int {
@nonobjc case what // expected-error {{'@nonobjc' attribute cannot be applied to this declaration}}
}