Skip to content

Add '@_alwaysEmitConformanceMetadata' protocol attribute #60367

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 1 commit into from
Aug 5, 2022
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
5 changes: 5 additions & 0 deletions docs/ReferenceGuides/UnderscoredAttributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -852,3 +852,8 @@ the distributed actor isolation checks. This is used for things like `whenLocal`
where the actor passed to the closure is known-to-be-local, and similarly a
`self` of obtained from an _isolated_ function inside a distributed actor is
also guaranteed to be local by construction.


## `@_alwaysEmitConformanceMetadata`

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.
4 changes: 4 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,10 @@ SIMPLE_DECL_ATTR(_moveOnly, MoveOnly,
UserInaccessible |
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
131)

SIMPLE_DECL_ATTR(_alwaysEmitConformanceMetadata, AlwaysEmitConformanceMetadata,
OnProtocol | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
132)

// If you're adding a new underscored attribute here, please document it in
// docs/ReferenceGuides/UnderscoredAttributes.md.
Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
void visitNonisolatedAttr(NonisolatedAttr *attr);

void visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr);

void visitAlwaysEmitConformanceMetadataAttr(AlwaysEmitConformanceMetadataAttr *attr);

void visitUnavailableFromAsyncAttr(UnavailableFromAsyncAttr *attr);

Expand Down Expand Up @@ -381,6 +383,10 @@ void AttributeChecker::visitNoImplicitCopyAttr(NoImplicitCopyAttr *attr) {
}
}

void AttributeChecker::visitAlwaysEmitConformanceMetadataAttr(AlwaysEmitConformanceMetadataAttr *attr) {
return;
}

void AttributeChecker::visitTransparentAttr(TransparentAttr *attr) {
DeclContext *dc = D->getDeclContext();
// Protocol declarations cannot be transparent.
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckDeclOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ namespace {

UNINTERESTING_ATTR(UnsafeInheritExecutor)
UNINTERESTING_ATTR(CompilerInitialized)
UNINTERESTING_ATTR(AlwaysEmitConformanceMetadata)
#undef UNINTERESTING_ATTR

void visitAvailableAttr(AvailableAttr *attr) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 698; // opaque decl with unavailability conditions
const uint16_t SWIFTMODULE_VERSION_MINOR = 699; // @_alwaysEmitConformanceMetadata

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down
18 changes: 18 additions & 0 deletions test/ModuleInterface/alwaysEmitConformanceMetadata_attr.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %empty-directory(%t)

// Ensure the attribute is printed in swiftinterface files
// RUN: %target-swift-emit-module-interface(%t/Foo.swiftinterface) %s -module-name Foo
// RUN: %target-swift-typecheck-module-from-interface(%t/Foo.swiftinterface) -module-name Foo
// RUN: %FileCheck %s < %t/Foo.swiftinterface

// Ensure the attribute is in .swiftmodule files
// 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
// RUN: %FileCheck %s < %t/printed-module.txt

@_alwaysEmitConformanceMetadata
public protocol TestP {
static var foo: Int { get }
}


// CHECK: @_alwaysEmitConformanceMetadata public protocol TestP
6 changes: 6 additions & 0 deletions test/Parse/alwaysEmitConformanceMetadata_attr.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %target-typecheck-verify-swift -parse -parse-stdlib -verify-syntax-tree

import Swift

@_alwaysEmitConformanceMetadata
protocol Test {}
25 changes: 25 additions & 0 deletions test/Sema/alwaysEmitConformanceMetadata_attr.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %target-typecheck-verify-swift -parse-stdlib -verify-syntax-tree

import Swift

@_alwaysEmitConformanceMetadata
protocol TestP {
static var foo: Int { get }
}

@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
class TestC {}

@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
struct TestS {}

@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
enum TestE {}

@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
extension TestS {}

class TestC2 {
@_alwaysEmitConformanceMetadata // expected-error {{@_alwaysEmitConformanceMetadata may only be used on 'protocol' declarations}}
var foo: Int = 11
}