Skip to content

Commit 951eaa7

Browse files
committed
Add experimental feature flags for @implementation
• ObjCImplementation controls @implementation on extensions • CImplementation controls @implementation and @_objcImplementation on cdecl functions Why the difference between them? Because `@_objcImplementation extension` has already been adopted pretty widely, while `@_objcImplementation @_cdecl` is very new.
1 parent dc055bf commit 951eaa7

10 files changed

+62
-6
lines changed

include/swift/Basic/Features.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE(IsolatedAny, true)
364364
// Alias for IsolatedAny
365365
EXPERIMENTAL_FEATURE(IsolatedAny2, true)
366366

367+
// Enable @implementation on extensions of ObjC classes.
368+
EXPERIMENTAL_FEATURE(ObjCImplementation, true)
369+
370+
// Enable @implementation on @_cdecl functions.
371+
EXPERIMENTAL_FEATURE(CImplementation, true)
372+
367373
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
368374
#undef EXPERIMENTAL_FEATURE
369375
#undef UPCOMING_FEATURE

lib/AST/FeatureSet.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,9 @@ static bool usesFeatureIsolatedAny(Decl *decl) {
683683

684684
UNINTERESTING_FEATURE(IsolatedAny2)
685685

686+
UNINTERESTING_FEATURE(ObjCImplementation)
687+
UNINTERESTING_FEATURE(CImplementation)
688+
686689
// ----------------------------------------------------------------------------
687690
// MARK: - FeatureSet
688691
// ----------------------------------------------------------------------------

lib/Sema/TypeCheckAttr.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,9 +1516,32 @@ void AttributeChecker::visitNonObjCAttr(NonObjCAttr *attr) {
15161516
}
15171517
}
15181518

1519+
static bool hasObjCImplementationFeature(Decl *D, ObjCImplementationAttr *attr,
1520+
Feature requiredFeature) {
1521+
if (D->getASTContext().LangOpts.hasFeature(requiredFeature)) {
1522+
return true;
1523+
}
1524+
1525+
// Allow the use of @_objcImplementation *without* Feature::ObjCImplementation
1526+
// as long as you're using the early adopter syntax. (Avoids breaking existing
1527+
// adopters.)
1528+
if (requiredFeature == Feature::ObjCImplementation && attr->isEarlyAdopter())
1529+
return true;
1530+
1531+
// Either you're using Feature::ObjCImplementation without the early adopter
1532+
// syntax, or you're using Feature::CImplementation. Either way, no go.
1533+
swift::diagnoseAndRemoveAttr(D, attr, diag::requires_experimental_feature,
1534+
attr->getAttrName(), attr->isDeclModifier(),
1535+
getFeatureName(requiredFeature));
1536+
return false;
1537+
}
1538+
15191539
void AttributeChecker::
15201540
visitObjCImplementationAttr(ObjCImplementationAttr *attr) {
15211541
if (auto ED = dyn_cast<ExtensionDecl>(D)) {
1542+
if (!hasObjCImplementationFeature(D, attr, Feature::ObjCImplementation))
1543+
return;
1544+
15221545
if (ED->isConstrainedExtension())
15231546
diagnoseAndRemoveAttr(attr,
15241547
diag::attr_objc_implementation_must_be_unconditional);
@@ -1575,6 +1598,9 @@ visitObjCImplementationAttr(ObjCImplementationAttr *attr) {
15751598
}
15761599
}
15771600
else if (auto AFD = dyn_cast<AbstractFunctionDecl>(D)) {
1601+
if (!hasObjCImplementationFeature(D, attr, Feature::CImplementation))
1602+
return;
1603+
15781604
if (!attr->CategoryName.empty()) {
15791605
auto diagnostic =
15801606
diagnose(attr->getLocation(),

test/IRGen/objc_implementation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Test doesn't pass on all platforms (rdar://101420862)
22
// REQUIRES: OS=macosx
33

4-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir > %t.ir
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-feature CImplementation -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir > %t.ir
55
// RUN: %FileCheck --input-file %t.ir %s
66
// RUN: %FileCheck --input-file %t.ir --check-prefix NEGATIVE %s
77
// REQUIRES: objc_interop

test/Interpreter/objc_implementation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/objc_implementation.h -D TOP_LEVEL_CODE -swift-version 5) %s | %FileCheck %s
1+
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/objc_implementation.h -D TOP_LEVEL_CODE -swift-version 5 -enable-experimental-feature CImplementation) %s | %FileCheck %s
22
// REQUIRES: executable_test
33
// REQUIRES: objc_interop
44

test/Interpreter/objc_implementation_swift_client.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// RUN: %empty-directory(%t/frameworks/objc_implementation.framework/Headers)
1313
// RUN: cp %S/Inputs/objc_implementation.modulemap %t/frameworks/objc_implementation.framework/Modules/module.modulemap
1414
// RUN: cp %S/Inputs/objc_implementation.h %t/frameworks/objc_implementation.framework/Headers
15-
// RUN: %target-build-swift-dylib(%t/frameworks/objc_implementation.framework/objc_implementation) -emit-module-path %t/frameworks/objc_implementation.framework/Modules/objc_implementation.swiftmodule/%module-target-triple.swiftmodule -module-name objc_implementation -F %t/frameworks -import-underlying-module -Xlinker -install_name -Xlinker %t/frameworks/objc_implementation.framework/objc_implementation %S/objc_implementation.swift
15+
// RUN: %target-build-swift-dylib(%t/frameworks/objc_implementation.framework/objc_implementation) -enable-experimental-feature CImplementation -emit-module-path %t/frameworks/objc_implementation.framework/Modules/objc_implementation.swiftmodule/%module-target-triple.swiftmodule -module-name objc_implementation -F %t/frameworks -import-underlying-module -Xlinker -install_name -Xlinker %t/frameworks/objc_implementation.framework/objc_implementation %S/objc_implementation.swift
1616

1717
//
1818
// Execute this file

test/PrintAsObjC/objc_implementation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
// FIXME: END -enable-source-import hackaround
1212

1313

14-
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -I %S/Inputs/custom-modules -import-underlying-module -o %t %s -disable-objc-attr-requires-foundation-module
15-
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -parse-as-library %t/objc_implementation.swiftmodule -typecheck -I %S/Inputs/custom-modules -emit-objc-header-path %t/objc_implementation-Swift.h -import-underlying-module -disable-objc-attr-requires-foundation-module
14+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -enable-experimental-feature CImplementation -I %S/Inputs/custom-modules -import-underlying-module -o %t %s -disable-objc-attr-requires-foundation-module
15+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -parse-as-library %t/objc_implementation.swiftmodule -typecheck -enable-experimental-feature CImplementation -I %S/Inputs/custom-modules -emit-objc-header-path %t/objc_implementation-Swift.h -import-underlying-module -disable-objc-attr-requires-foundation-module
1616
// RUN: %FileCheck %s --input-file %t/objc_implementation-Swift.h
1717
// RUN: %FileCheck --check-prefix=NEGATIVE %s --input-file %t/objc_implementation-Swift.h
1818
// RUN: %check-in-clang -I %S/Inputs/custom-modules/ %t/objc_implementation-Swift.h
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h 2>&1 | %FileCheck --check-prefixes NO,CHECK %s
2+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h -enable-experimental-feature CImplementation 2>&1 | %FileCheck --check-prefixes YES,C,CHECK %s
3+
4+
// NO-DAG: cdecl_implementation_features.swift:[[@LINE+3]]:{{[0-9]+}}: error: '_objcImplementation' attribute is only valid when experimental feature CImplementation is enabled
5+
// YES-NOT: cdecl_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: warning: warning-only '@_objcImplementation' spelling is deprecated; use '@implementation' instead
6+
// TODO: When @implementation @_cdecl stabilizes, YES-NOT on the line above will become YES-DAG
7+
@_objcImplementation @_cdecl("CImplFunc1") func CImplFunc1(_: Double) {}
8+
9+
// NO-DAG: cdecl_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature CImplementation is enabled
10+
// YES-NOT: cdecl_implementation_features.swift:[[@LINE+1]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature CImplementation is enabled
11+
@implementation @_cdecl("CImplFunc2") func CImplFunc2(_: Double) {}

test/decl/ext/objc_implementation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -import-objc-header %S/Inputs/objc_implementation.h
1+
// RUN: %target-typecheck-verify-swift -import-objc-header %S/Inputs/objc_implementation.h -enable-experimental-feature CImplementation
22
// REQUIRES: objc_interop
33

44
protocol EmptySwiftProto {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// REQUIRES: objc_interop
2+
3+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h 2>&1 | %FileCheck --check-prefixes NO,CHECK %s
4+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource) -typecheck %s -import-objc-header %S/Inputs/objc_implementation.h -enable-experimental-feature ObjCImplementation 2>&1 | %FileCheck --check-prefixes YES,CHECK %s
5+
6+
@_objcImplementation extension ObjCSubclass {}
7+
8+
// NO-DAG: objc_implementation_features.swift:[[@LINE+2]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature ObjCImplementation is enabled
9+
// YES-NOT: objc_implementation_features.swift:[[@LINE+1]]:{{[0-9]+}}: error: 'implementation' attribute is only valid when experimental feature ObjCImplementation is enabled
10+
@implementation extension ObjCBasicInitClass {}

0 commit comments

Comments
 (0)