Skip to content

Commit eca56da

Browse files
committed
Add note, check against feature
1 parent 7da7c73 commit eca56da

File tree

5 files changed

+55
-10
lines changed

5 files changed

+55
-10
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,8 @@ ERROR(attr_static_exclusive_only_noncopyable,none,
19241924
"@_staticExclusiveOnly can only be applied to noncopyable types", ())
19251925
ERROR(attr_static_exclusive_only_let_only,none,
19261926
"variable of type %0 must be declared with a 'let'", (Type))
1927+
NOTE(attr_static_exclusive_only_type_nonmutating,none,
1928+
"%0 is a non-mutable type", (Type))
19271929
ERROR(attr_static_exclusive_only_let_only_param,none,
19281930
"parameter of type %0 must be declared as either 'borrowing' or 'consuming'", (Type))
19291931
ERROR(attr_static_exclusive_only_mutating,none,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7259,12 +7259,14 @@ void AttributeChecker::visitStaticExclusiveOnlyAttr(
72597259
StaticExclusiveOnlyAttr *attr) {
72607260
if (!Ctx.LangOpts.hasFeature(Feature::StaticExclusiveOnly)) {
72617261
diagnoseAndRemoveAttr(attr, diag::attr_static_exclusive_only_disabled);
7262+
return;
72627263
}
72637264

72647265
// Can only be applied to structs.
72657266
auto structDecl = cast<StructDecl>(D);
72667267

7267-
if (!structDecl->isNoncopyable()) {
7268+
if (!structDecl->getDeclaredInterfaceType()
7269+
->isNoncopyable(D->getDeclContext())) {
72687270
diagnoseAndRemoveAttr(attr, diag::attr_static_exclusive_only_noncopyable);
72697271
}
72707272
}

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,10 +2484,16 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24842484

24852485
// @_staticExclusiveOnly types cannot be put into 'var's, only 'let'.
24862486
if (auto SD = VD->getInterfaceType()->getStructOrBoundGenericStruct()) {
2487-
if (SD->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>() &&
2487+
if (getASTContext().LangOpts.hasFeature(Feature::StaticExclusiveOnly) &&
2488+
SD->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>() &&
24882489
!VD->isLet()) {
2489-
VD->diagnose(diag::attr_static_exclusive_only_let_only,
2490-
VD->getInterfaceType());
2490+
SD->getASTContext().Diags.diagnoseWithNotes(
2491+
VD->diagnose(diag::attr_static_exclusive_only_let_only,
2492+
VD->getInterfaceType()),
2493+
[&]() {
2494+
SD->diagnose(diag::attr_static_exclusive_only_type_nonmutating,
2495+
SD->getDeclaredInterfaceType());
2496+
});
24912497
}
24922498
}
24932499
}
@@ -4236,10 +4242,16 @@ void TypeChecker::checkParameterList(ParameterList *params,
42364242
// @_staticExclusiveOnly types cannot be passed as 'inout', only as either
42374243
// a borrow or as consuming.
42384244
if (auto SD = param->getInterfaceType()->getStructOrBoundGenericStruct()) {
4239-
if (SD->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>() &&
4245+
if (SD->getASTContext().LangOpts.hasFeature(Feature::StaticExclusiveOnly) &&
4246+
SD->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>() &&
42404247
param->isInOut()) {
4241-
param->diagnose(diag::attr_static_exclusive_only_let_only_param,
4242-
param->getInterfaceType());
4248+
SD->getASTContext().Diags.diagnoseWithNotes(
4249+
param->diagnose(diag::attr_static_exclusive_only_let_only_param,
4250+
param->getInterfaceType()),
4251+
[&]() {
4252+
SD->diagnose(diag::attr_static_exclusive_only_type_nonmutating,
4253+
SD->getDeclaredInterfaceType());
4254+
});
42434255
}
42444256
}
42454257
}

lib/Sema/TypeCheckType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3563,7 +3563,8 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
35633563
// @_staticExclusiveOnly types cannot be passed as 'inout' in function
35643564
// types.
35653565
if (auto SD = ty->getStructOrBoundGenericStruct()) {
3566-
if (SD->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>() &&
3566+
if (getASTContext().LangOpts.hasFeature(Feature::StaticExclusiveOnly) &&
3567+
SD->getAttrs().hasAttribute<StaticExclusiveOnlyAttr>() &&
35673568
ownership == ParamSpecifier::InOut) {
35683569
diagnose(eltTypeRepr->getLoc(),
35693570
diag::attr_static_exclusive_only_let_only_param,

test/attr/attr_static_exclusive_only.swift

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// RUN: %target-typecheck-verify-swift -enable-experimental-feature StaticExclusiveOnly
22

3-
@_staticExclusiveOnly // expected-error{{@_staticExclusiveOnly can only be applied to noncopyable types}}
3+
@_staticExclusiveOnly // expected-error {{@_staticExclusiveOnly can only be applied to noncopyable types}}
44
struct A {}
55

66
@_staticExclusiveOnly // OK
7-
struct B: ~Copyable {
7+
struct B: ~Copyable { // expected-note {{'B' is a non-mutable type}}
8+
// expected-note@-1 {{'B' is a non-mutable type}}
9+
// expected-note@-2 {{'B' is a non-mutable type}}
10+
// expected-note@-3 {{'B' is a non-mutable type}}
11+
// expected-note@-4 {{'B' is a non-mutable type}}
812
mutating func change() { // expected-error {{@_staticExclusiveOnly type 'B' cannot have mutating function 'change()'}}
913
print("123")
1014
}
@@ -40,3 +44,27 @@ func i() {
4044
return $0 + $1
4145
}
4246
}
47+
48+
@_staticExclusiveOnly // expected-error {{@_staticExclusiveOnly may only be used on 'struct' declarations}}
49+
enum J {}
50+
51+
@_staticExclusiveOnly // expected-error {{@_staticExclusiveOnly may only be used on 'struct' declarations}}
52+
class K {}
53+
54+
@_staticExclusiveOnly // expected-error {{@_staticExclusiveOnly may only be used on 'struct' declarations}}
55+
func l() {}
56+
57+
@_staticExclusiveOnly // expected-error {{@_staticExclusiveOnly may only be used on 'struct' declarations}}
58+
let m = 123
59+
60+
@_staticExclusiveOnly // expected-error {{@_staticExclusiveOnly may only be used on 'struct' declarations}}
61+
protocol N {}
62+
63+
func o(_: consuming B) {} // OK
64+
65+
func p(_: (consuming B) -> ()) {} // OK
66+
67+
@_staticExclusiveOnly
68+
struct Q<T>: ~Copyable {} // expected-note {{'Q<T>' is a non-mutable type}}
69+
70+
var r0 = Q<Int>() // expected-error {{variable of type 'Q<Int>' must be declared with a 'let'}}

0 commit comments

Comments
 (0)