Skip to content

Commit 8fd29a5

Browse files
committed
Sema: Add some missing checks for where clauses on non-generic declarations
Access control, availability and exportability checking missed these because of a baked-in assumption that getGenericParams() == nullptr rules out the presence of a trailing where clause.
1 parent 1888724 commit 8fd29a5

File tree

5 files changed

+80
-41
lines changed

5 files changed

+80
-41
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,10 @@ void AccessControlCheckerBase::checkGenericParamAccess(
323323
const Decl *ownerDecl,
324324
AccessScope accessScope,
325325
AccessLevel contextAccess) {
326-
auto params = ownerCtx->getGenericParams();
327-
if (!params)
326+
if (!ownerCtx->isGenericContext())
328327
return;
329328

330-
// This must stay in sync with diag::generic_param_access.
329+
// This must stay in sync with diag::generic_param_access.
331330
enum class ACEK {
332331
Parameter = 0,
333332
Requirement
@@ -355,20 +354,25 @@ void AccessControlCheckerBase::checkGenericParamAccess(
355354

356355
auto *DC = ownerDecl->getDeclContext();
357356

358-
for (auto param : *params) {
359-
if (param->getInherited().empty())
360-
continue;
361-
assert(param->getInherited().size() == 1);
362-
checkTypeAccessImpl(param->getInherited().front().getType(),
363-
param->getInherited().front().getTypeRepr(),
364-
accessScope, DC, /*mayBeInferred*/false,
365-
callback);
357+
if (auto params = ownerCtx->getGenericParams()) {
358+
for (auto param : *params) {
359+
if (param->getInherited().empty())
360+
continue;
361+
assert(param->getInherited().size() == 1);
362+
checkTypeAccessImpl(param->getInherited().front().getType(),
363+
param->getInherited().front().getTypeRepr(),
364+
accessScope, DC, /*mayBeInferred*/false,
365+
callback);
366+
}
366367
}
368+
367369
callbackACEK = ACEK::Requirement;
368370

369-
checkRequirementAccess(WhereClauseOwner(
370-
const_cast<GenericContext *>(ownerCtx)),
371-
accessScope, DC, callback);
371+
if (ownerCtx->getTrailingWhereClause()) {
372+
checkRequirementAccess(WhereClauseOwner(
373+
const_cast<GenericContext *>(ownerCtx)),
374+
accessScope, DC, callback);
375+
}
372376

373377
if (minAccessScope.isPublic())
374378
return;
@@ -1624,23 +1628,26 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
16241628

16251629
void checkGenericParams(const GenericContext *ownerCtx,
16261630
const ValueDecl *ownerDecl) {
1627-
const auto params = ownerCtx->getGenericParams();
1628-
if (!params)
1631+
if (!ownerCtx->isGenericContext())
16291632
return;
16301633

1631-
for (auto param : *params) {
1632-
if (param->getInherited().empty())
1633-
continue;
1634-
assert(param->getInherited().size() == 1);
1635-
checkType(param->getInherited().front(), ownerDecl,
1636-
getDiagnoser(ownerDecl));
1634+
if (auto params = ownerCtx->getGenericParams()) {
1635+
for (auto param : *params) {
1636+
if (param->getInherited().empty())
1637+
continue;
1638+
assert(param->getInherited().size() == 1);
1639+
checkType(param->getInherited().front(), ownerDecl,
1640+
getDiagnoser(ownerDecl));
1641+
}
16371642
}
16381643

1639-
forAllRequirementTypes(WhereClauseOwner(
1640-
const_cast<GenericContext *>(ownerCtx)),
1641-
[&](Type type, TypeRepr *typeRepr) {
1642-
checkType(type, typeRepr, ownerDecl, getDiagnoser(ownerDecl));
1643-
});
1644+
if (ownerCtx->getTrailingWhereClause()) {
1645+
forAllRequirementTypes(WhereClauseOwner(
1646+
const_cast<GenericContext *>(ownerCtx)),
1647+
[&](Type type, TypeRepr *typeRepr) {
1648+
checkType(type, typeRepr, ownerDecl, getDiagnoser(ownerDecl));
1649+
});
1650+
}
16441651
}
16451652

16461653
// This enum must be kept in sync with
@@ -2076,24 +2083,26 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
20762083

20772084
void checkGenericParams(const GenericContext *ownerCtx,
20782085
const ValueDecl *ownerDecl) {
2079-
// FIXME: What if we have a where clause and no generic params?
2080-
const auto params = ownerCtx->getGenericParams();
2081-
if (!params)
2086+
if (!ownerCtx->isGenericContext())
20822087
return;
20832088

2084-
for (auto param : *params) {
2085-
if (param->getInherited().empty())
2086-
continue;
2087-
assert(param->getInherited().size() == 1);
2088-
auto inherited = param->getInherited().front();
2089-
checkType(inherited.getType(), inherited.getTypeRepr(), ownerDecl);
2089+
if (auto params = ownerCtx->getGenericParams()) {
2090+
for (auto param : *params) {
2091+
if (param->getInherited().empty())
2092+
continue;
2093+
assert(param->getInherited().size() == 1);
2094+
auto inherited = param->getInherited().front();
2095+
checkType(inherited.getType(), inherited.getTypeRepr(), ownerDecl);
2096+
}
20902097
}
20912098

2092-
forAllRequirementTypes(WhereClauseOwner(
2093-
const_cast<GenericContext *>(ownerCtx)),
2094-
[&](Type type, TypeRepr *typeRepr) {
2095-
checkType(type, typeRepr, ownerDecl);
2096-
});
2099+
if (ownerCtx->getTrailingWhereClause()) {
2100+
forAllRequirementTypes(WhereClauseOwner(
2101+
const_cast<GenericContext *>(ownerCtx)),
2102+
[&](Type type, TypeRepr *typeRepr) {
2103+
checkType(type, typeRepr, ownerDecl);
2104+
});
2105+
}
20972106
}
20982107

20992108
public:

test/Sema/accessibility_where.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,12 @@ protocol Protocol7 : BaseProtocol where T == (PrivateStruct) -> Void {
8787
associatedtype X : BaseProtocol where X.T == (PrivateStruct) -> Void
8888
// expected-error@-1 {{associated type in an internal protocol uses a private type in its requirement}}
8989
}
90+
91+
private protocol PrivateProtocol {} // expected-note 2{{type declared here}}
92+
93+
struct GenericStruct<T> {
94+
struct Inner where T : PrivateProtocol {}
95+
// expected-error@-1 {{struct must be declared private because its generic requirement uses a private type}}
96+
func nonGenericWhereClause() where T : PrivateProtocol {}
97+
// expected-error@-1 {{instance method must be declared private because its generic requirement uses a private type}}
98+
}

test/Sema/availability_versions.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,14 @@ func GenericSignature<T : ProtocolAvailableOn10_51>(_ t: T) { // expected-error
928928
// expected-note@-1 * {{add @available attribute to enclosing global function}}
929929
}
930930

931+
struct GenericType<T> { // expected-note {{add @available attribute to enclosing generic struct}}
932+
func nonGenericWhereClause() where T : ProtocolAvailableOn10_51 {} // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
933+
// expected-note@-1 {{add @available attribute to enclosing instance method}}
934+
935+
struct NestedType where T : ProtocolAvailableOn10_51 {} // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
936+
// expected-note@-1 2{{add @available attribute to enclosing struct}}
937+
}
938+
931939
// Extensions
932940

933941
extension ClassAvailableOn10_51 { } // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}

test/Sema/implementation-only-import-in-decls.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public struct TestGenericParams<T: BadProto> {} // expected-error {{cannot use p
2121

2222
public struct TestGenericParamsWhereClause<T> where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
2323

24+
public struct TestGenericParamsWithOuter<T> {
25+
public func nonGenericWhereClause() where T : BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
26+
public struct Inner where T : BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
27+
}
28+
2429
public enum TestCase {
2530
case x(BadStruct) // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}}
2631
case y(Int, BadStruct) // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}}

test/attr/attr_usableFromInline.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,11 @@ public struct TestGenericSubscripts {
155155

156156
@usableFromInline typealias TestGenericAlias<T: InternalProtocol> = T // expected-warning {{type referenced from a generic parameter of a '@usableFromInline' type alias should be '@usableFromInline' or public}}
157157
@usableFromInline typealias TestGenericAliasWhereClause<T> = T where T: InternalProtocol // expected-warning {{type referenced from a generic requirement of a '@usableFromInline' type alias should be '@usableFromInline' or public}}
158+
159+
@usableFromInline struct GenericStruct<T> {
160+
@usableFromInline struct Nested where T : InternalProtocol {}
161+
// expected-error@-1 {{type referenced from a generic requirement of a '@usableFromInline' struct must be '@usableFromInline' or public}}
162+
163+
@usableFromInline func nonGenericWhereClause() where T : InternalProtocol {}
164+
// expected-error@-1 {{type referenced from a generic requirement of a '@usableFromInline' instance method must be '@usableFromInline' or public}}
165+
}

0 commit comments

Comments
 (0)