Skip to content

Commit ff21023

Browse files
authored
Merge pull request #60367 from artemcm/AddAlwaysEmitConformanceAttribute
Add '@_alwaysEmitConformanceMetadata' protocol attribute
2 parents 19d5728 + 4e2c1d1 commit ff21023

File tree

8 files changed

+66
-1
lines changed

8 files changed

+66
-1
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,3 +852,8 @@ the distributed actor isolation checks. This is used for things like `whenLocal`
852852
where the actor passed to the closure is known-to-be-local, and similarly a
853853
`self` of obtained from an _isolated_ function inside a distributed actor is
854854
also guaranteed to be local by construction.
855+
856+
857+
## `@_alwaysEmitConformanceMetadata`
858+
859+
Forces conformances of the attributed protocol to always have their Type Metadata get emitted into the binary and prevents it from being optimized away or stripped by the linker.

include/swift/AST/Attr.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,10 @@ SIMPLE_DECL_ATTR(_moveOnly, MoveOnly,
740740
UserInaccessible |
741741
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
742742
131)
743+
744+
SIMPLE_DECL_ATTR(_alwaysEmitConformanceMetadata, AlwaysEmitConformanceMetadata,
745+
OnProtocol | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
746+
132)
743747

744748
// If you're adding a new underscored attribute here, please document it in
745749
// docs/ReferenceGuides/UnderscoredAttributes.md.

lib/Sema/TypeCheckAttr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
311311
void visitNonisolatedAttr(NonisolatedAttr *attr);
312312

313313
void visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr);
314+
315+
void visitAlwaysEmitConformanceMetadataAttr(AlwaysEmitConformanceMetadataAttr *attr);
314316

315317
void visitUnavailableFromAsyncAttr(UnavailableFromAsyncAttr *attr);
316318

@@ -381,6 +383,10 @@ void AttributeChecker::visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr) {
381383
}
382384
}
383385

386+
void AttributeChecker::visitAlwaysEmitConformanceMetadataAttr(AlwaysEmitConformanceMetadataAttr *attr) {
387+
return;
388+
}
389+
384390
void AttributeChecker::visitTransparentAttr(TransparentAttr *attr) {
385391
DeclContext *dc = D->getDeclContext();
386392
// Protocol declarations cannot be transparent.

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,7 @@ namespace {
16131613

16141614
UNINTERESTING_ATTR(UnsafeInheritExecutor)
16151615
UNINTERESTING_ATTR(CompilerInitialized)
1616+
UNINTERESTING_ATTR(AlwaysEmitConformanceMetadata)
16161617
#undef UNINTERESTING_ATTR
16171618

16181619
void visitAvailableAttr(AvailableAttr *attr) {

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 698; // opaque decl with unavailability conditions
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 699; // @_alwaysEmitConformanceMetadata
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// Ensure the attribute is printed in swiftinterface files
4+
// RUN: %target-swift-emit-module-interface(%t/Foo.swiftinterface) %s -module-name Foo
5+
// RUN: %target-swift-typecheck-module-from-interface(%t/Foo.swiftinterface) -module-name Foo
6+
// RUN: %FileCheck %s < %t/Foo.swiftinterface
7+
8+
// Ensure the attribute is in .swiftmodule files
9+
// RUN: %target-swift-ide-test -print-module -module-to-print Foo -I %t -source-filename %s -fully-qualified-types -print-access > %t/printed-module.txt
10+
// RUN: %FileCheck %s < %t/printed-module.txt
11+
12+
@_alwaysEmitConformanceMetadata
13+
public protocol TestP {
14+
static var foo: Int { get }
15+
}
16+
17+
18+
// CHECK: @_alwaysEmitConformanceMetadata public protocol TestP
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-typecheck-verify-swift -parse -parse-stdlib -verify-syntax-tree
2+
3+
import Swift
4+
5+
@_alwaysEmitConformanceMetadata
6+
protocol Test {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-typecheck-verify-swift -parse-stdlib -verify-syntax-tree
2+
3+
import Swift
4+
5+
@_alwaysEmitConformanceMetadata
6+
protocol TestP {
7+
static var foo: Int { get }
8+
}
9+
10+
@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
11+
class TestC {}
12+
13+
@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
14+
struct TestS {}
15+
16+
@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
17+
enum TestE {}
18+
19+
@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
20+
extension TestS {}
21+
22+
class TestC2 {
23+
@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
24+
var foo: Int = 11
25+
}

0 commit comments

Comments
 (0)