Skip to content

Commit 7b27997

Browse files
committed
Fix a crash during an operator type check with package acl
Type-checking an operator requires look up of all of its decls regardless of which access modifier is used before filtering. If one of them is a package decl in an imported module that was built with package-name, but the use site of the operator decl is in a module that is not built with package-name, it currently crashes as it tries to access package context of the use site, which is null. This PR checks if both decl site and use site have package contexts before accessing the package name property, otherwise return false to be filtered out. Resolves rdar://108961906
1 parent c2c2414 commit 7b27997

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

lib/AST/Decl.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3973,10 +3973,12 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
39733973
auto pkg = resultDC->getPackageContext(/*lookupIfNotCurrent*/ true);
39743974
if (!pkg) {
39753975
auto srcFile = resultDC->getParentSourceFile();
3976-
// Check if the file containing package decls is an interface file; if a public
3977-
// interface contains package decls, they must be inlinable and do not need a
3978-
// package-name, so don't show diagnostics in that case.
3979-
if (srcFile && srcFile->Kind != SourceFileKind::Interface) {
3976+
// Check if the file containing package decls is an interface file; if an
3977+
// interface file contains package decls, they must be usableFromInline or
3978+
// inlinable and are accessed within the defining module, so package-name
3979+
// is not needed; do not show diagnostics in such case.
3980+
auto shouldSkipDiag = srcFile && srcFile->Kind == SourceFileKind::Interface;
3981+
if (!shouldSkipDiag) {
39803982
// No package context was found; show diagnostics
39813983
auto &d = VD->getASTContext().Diags;
39823984
d.diagnose(VD->getLoc(), diag::access_control_requires_package_name);
@@ -4175,15 +4177,16 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
41754177
}
41764178
case AccessLevel::Package: {
41774179
auto srcFile = sourceDC->getParentSourceFile();
4178-
if (srcFile && srcFile->Kind != SourceFileKind::Interface) {
4179-
auto srcPkg = sourceDC->getPackageContext(/*lookupIfNotCurrent*/ true);
4180-
auto usePkg = useDC->getPackageContext(/*lookupIfNotCurrent*/ true);
4181-
return usePkg->isSamePackageAs(srcPkg);
4182-
} else {
4183-
// If source file is interface, package decls must be inlinable,
4184-
// essentially treated public so return true (see AccessLevel::Public)
4180+
4181+
// srcFile could be null if VD decl is from an imported .swiftmodule
4182+
if (srcFile && srcFile->Kind == SourceFileKind::Interface) {
4183+
// If source file is interface, package decls must be usableFromInline or
4184+
// inlinable, and are accessed only within the defining module so return true
41854185
return true;
41864186
}
4187+
auto srcPkg = sourceDC->getPackageContext(/*lookupIfNotCurrent*/ true);
4188+
auto usePkg = useDC->getPackageContext(/*lookupIfNotCurrent*/ true);
4189+
return srcPkg && usePkg && usePkg->isSamePackageAs(srcPkg);
41874190
}
41884191
case AccessLevel::Public:
41894192
case AccessLevel::Open:
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -verify -module-name Lib %t/Lib.swift -emit-module -emit-module-path %t/Lib.swiftmodule -package-name myPkg
5+
6+
/// Type-checking an operator (L30 below) causes look up of all of its decls regardless of which access modifier is
7+
/// used (decl in both Client and Lib in this case) before filtering. The decl in Lib is a package decl and has
8+
/// package-name associated with it, but the use site (in Client) does not have package-name. The package decl
9+
/// should be filtered out and the public == decl should be picked.
10+
// RUN: %target-swift-frontend -typecheck -verify %t/Client.swift -I %t
11+
12+
13+
//--- Lib.swift
14+
public class Decl {
15+
package static func == (lhs: Decl, rhs: Decl) -> Bool {
16+
return true
17+
}
18+
}
19+
20+
//--- Client.swift
21+
import Lib
22+
23+
extension Decl: Equatable {
24+
public static func == (lhs: Decl, rhs: Decl) -> Bool {
25+
return false
26+
}
27+
}
28+
29+
public protocol Proto {}
30+
extension Proto {
31+
func foo(first: Decl, second: Decl) -> Bool {
32+
// Type-checking below causes a look up of == in both Client and Lib
33+
return first == second
34+
}
35+
}

0 commit comments

Comments
 (0)