Skip to content

Commit 42694d8

Browse files
committed
[AST] RuntimeMetadata: Allow use of reflection metadata attrs on unavailable extensions
This is just a way to opt-out a type from use of the attribute, there is no code generation for such cases because the attribute could never be reached.
1 parent 3fd895a commit 42694d8

File tree

4 files changed

+63
-1
lines changed

4 files changed

+63
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6914,6 +6914,14 @@ ERROR(invalid_decl_for_runtime_discoverable_attr,none,
69146914
"@%0 can only be applied to non-generic types, methods, "
69156915
"instance properties, and global functions", (StringRef))
69166916

6917+
ERROR(invalid_decl_for_runtime_discoverable_attr_in_extension,none,
6918+
"@%0 can only be applied to unavailable extensions in the same module"
6919+
" as %1", (StringRef, DeclName))
6920+
6921+
ERROR(invalid_attr_redeclaration_in_extension,none,
6922+
"@%0 is already applied to type %1; did you want to remove it?",
6923+
(StringRef, DeclName))
6924+
69176925
ERROR(duplicate_runtime_discoverable_attr,none,
69186926
"duplicate runtime discoverable attribute", ())
69196927

lib/Sema/TypeCheckAttr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3715,6 +3715,40 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
37153715
return;
37163716
}
37173717

3718+
case DeclKind::Extension: {
3719+
auto *ext = cast<ExtensionDecl>(D);
3720+
3721+
// Only allowed on unavailable extensions in the same module as type
3722+
// as a way to opt-out from use of the attribute.
3723+
if (AvailableAttr::isUnavailable(ext)) {
3724+
auto *extendedType = ext->getExtendedNominal();
3725+
3726+
// If there is no type, fallback to default diagnostic.
3727+
if (!extendedType)
3728+
break;
3729+
3730+
if (extendedType->getParentModule() == ext->getParentModule()) {
3731+
for (auto directAttr : extendedType->getRuntimeDiscoverableAttrs()) {
3732+
auto directAttrDecl =
3733+
extendedType->getRuntimeDiscoverableAttrTypeDecl(directAttr);
3734+
if (directAttrDecl == nominal) {
3735+
diagnose(attr->getLocation(),
3736+
diag::invalid_attr_redeclaration_in_extension,
3737+
nominal->getNameStr(), extendedType->getName())
3738+
.fixItRemove(directAttr->getRangeWithAt());
3739+
}
3740+
}
3741+
3742+
return;
3743+
}
3744+
}
3745+
3746+
diagnoseAndRemoveAttr(
3747+
attr, diag::invalid_decl_for_runtime_discoverable_attr_in_extension,
3748+
nominal->getNameStr(), ext->getExtendedNominal()->getName());
3749+
return;
3750+
}
3751+
37183752
default:
37193753
// All other kinds of declarations i.e. subscripts, constructors etc.
37203754
// are unsupported.

test/type/Inputs/RuntimeAttrs.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public struct CrossModuleTest {}

test/type/runtime_discoverable_attrs.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature RuntimeDiscoverableAttrs
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module %S/Inputs/RuntimeAttrs.swift -o %t
3+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature RuntimeDiscoverableAttrs -I %t
24

35
// REQUIRES: asserts
46

7+
import RuntimeAttrs
8+
59
@runtimeMetadata
610
struct Flag<T> {
711
init(attachedTo: T.Type, _ description: String = "") {}
@@ -264,3 +268,18 @@ extension EnumFlag where B == Void {
264268
@EnumFlag func testInst() {}
265269
@EnumFlag static func testStatic() -> Int { 42 }
266270
}
271+
272+
@Flag extension EnumTypeTest { // expected-error {{@Flag can only be applied to unavailable extensions in the same module as 'EnumTypeTest'}}
273+
}
274+
275+
@available(*, unavailable)
276+
@Flag extension EnumTypeTest { // Ok
277+
}
278+
279+
@available(*, unavailable)
280+
@EnumFlag extension EnumTypeTest { // expected-error {{@EnumFlag is already applied to type 'EnumTypeTest'; did you want to remove it?}} {{266:1-11=}}
281+
}
282+
283+
@available(*, unavailable)
284+
@Flag extension CrossModuleTest { // expected-error {{@Flag can only be applied to unavailable extensions in the same module as 'CrossModuleTest'}}
285+
}

0 commit comments

Comments
 (0)