Skip to content

Commit 6274f00

Browse files
committed
Fix a crash during lookup of an operator 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 3b08abb commit 6274f00

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

lib/AST/Decl.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3973,11 +3973,19 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
39733973
case AccessLevel::Package: {
39743974
auto pkg = resultDC->getPackageContext(/*lookupIfNotCurrent*/ true);
39753975
if (!pkg) {
3976-
// No package context was found; show diagnostics
3977-
auto &d = VD->getASTContext().Diags;
3978-
d.diagnose(VD->getLoc(), diag::access_control_requires_package_name);
3979-
// Instead of reporting and failing early, return the scope of
3980-
// resultDC to allow continuation (should still non-zero exit later)
3976+
auto srcFile = resultDC->getParentSourceFile();
3977+
// Check if the file containing package decls is an interface file; if an
3978+
// interface file contains package decls, they must be usableFromInline or
3979+
// inlinable and are accessed within the defining module, so package-name
3980+
// is not needed; do not show diagnostics in such case.
3981+
auto shouldSkipDiag = srcFile && srcFile->Kind == SourceFileKind::Interface;
3982+
if (!shouldSkipDiag) {
3983+
// No package context was found; show diagnostics
3984+
auto &d = VD->getASTContext().Diags;
3985+
d.diagnose(VD->getLoc(), diag::access_control_requires_package_name);
3986+
}
3987+
// Instead of reporting and failing early, return the scope of resultDC to
3988+
// allow continuation (should still non-zero exit later if in script mode)
39813989
return AccessScope(resultDC);
39823990
} else {
39833991
return AccessScope(pkg);
@@ -4169,9 +4177,17 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
41694177
return useSF && useSF->hasTestableOrPrivateImport(access, sourceModule);
41704178
}
41714179
case AccessLevel::Package: {
4180+
auto srcFile = sourceDC->getParentSourceFile();
4181+
4182+
// srcFile could be null if VD decl is from an imported .swiftmodule
4183+
if (srcFile && srcFile->Kind == SourceFileKind::Interface) {
4184+
// If source file is interface, package decls must be usableFromInline or
4185+
// inlinable, and are accessed only within the defining module so return true
4186+
return true;
4187+
}
41724188
auto srcPkg = sourceDC->getPackageContext(/*lookupIfNotCurrent*/ true);
41734189
auto usePkg = useDC->getPackageContext(/*lookupIfNotCurrent*/ true);
4174-
return usePkg->isSamePackageAs(srcPkg);
4190+
return srcPkg && usePkg && usePkg->isSamePackageAs(srcPkg);
41754191
}
41764192
case AccessLevel::Public:
41774193
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)