Explorar el Código

Fix accidental name exposure on cross-package import use. (#3955)

Looking at `export` handling, I noticed and figured to fix this case
first.

Also makes the test file prelude-agnostic.
Jon Ross-Perkins hace 1 año
padre
commit
3b32d390ac

+ 5 - 0
toolchain/check/context.cpp

@@ -324,6 +324,11 @@ static auto LookupInImportIRScopes(Context& context, SemIRLoc loc,
       // Name doesn't exist in the import scope.
       continue;
     }
+    if (import_ir.sem_ir->insts().Is<SemIR::AnyImportRef>(it->second)) {
+      // This entity was added to name lookup by using an import, and is not
+      // exported.
+      continue;
+    }
 
     if (!bind_name_id.is_valid()) {
       bind_name_id = context.bind_names().Add(

+ 90 - 40
toolchain/check/testdata/packages/cross_package_import.carbon → toolchain/check/testdata/packages/no_prelude/cross_package_import.carbon

@@ -24,7 +24,7 @@ extern fn F();
 
 package Other library "fn_conflict" api;
 
-fn F(x: i32) {}
+fn F(x: ()) {}
 
 // --- other_fn2.carbon
 
@@ -32,6 +32,14 @@ package Other library "fn2" api;
 
 fn F2() {}
 
+// --- other_fn_use.carbon
+
+package Other library "fn_use" api;
+
+import library "fn";
+
+fn G() { F(); }
+
 // --- main_other_ns.carbon
 
 library "other_ns" api;
@@ -97,8 +105,8 @@ import Other library "fn";
 // CHECK:STDERR: import Other library "fn_conflict";
 // CHECK:STDERR: ^~~~~~
 // CHECK:STDERR: other_fn_conflict.carbon:4:1: ERROR: Duplicate name being declared in the same scope.
-// CHECK:STDERR: fn F(x: i32) {}
-// CHECK:STDERR: ^~~~~~~~~~~~~~
+// CHECK:STDERR: fn F(x: ()) {}
+// CHECK:STDERR: ^~~~~~~~~~~~~
 // CHECK:STDERR: fail_main_use_other_ambiguous.carbon:[[@LINE-7]]:1: In import.
 // CHECK:STDERR: import Other library "fn";
 // CHECK:STDERR: ^~~~~~
@@ -168,14 +176,26 @@ library "add_to_other" api;
 
 import Other library "fn";
 
-// CHECK:STDERR: fail_main_add_to_other.carbon:[[@LINE+6]]:4: ERROR: Imported packages cannot be used for declarations.
+// CHECK:STDERR: fail_main_add_to_other.carbon:[[@LINE+7]]:4: ERROR: Imported packages cannot be used for declarations.
 // CHECK:STDERR: fn Other.G() {}
 // CHECK:STDERR:    ^~~~~
 // CHECK:STDERR: fail_main_add_to_other.carbon:[[@LINE-5]]:1: Package imported here.
 // CHECK:STDERR: import Other library "fn";
 // CHECK:STDERR: ^~~~~~
+// CHECK:STDERR:
 fn Other.G() {}
 
+// --- fail_use_other_fn_use.carbon
+
+library "fail_use_other_fn_use" api;
+
+import Other library "fn_use";
+
+// CHECK:STDERR: fail_use_other_fn_use.carbon:[[@LINE+3]]:13: ERROR: Name `F` not found.
+// CHECK:STDERR: fn UseF() { Other.F(); }
+// CHECK:STDERR:             ^~~~~~~
+fn UseF() { Other.F(); }
+
 // CHECK:STDOUT: --- other_fn.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -186,10 +206,8 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %F.decl: F = fn_decl @F [template = constants.%struct] {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -208,10 +226,8 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %F.decl: F = fn_decl @F [template = constants.%struct] {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -220,24 +236,24 @@ fn Other.G() {}
 // CHECK:STDOUT: --- other_fn_conflict.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %F: type = fn_type @F [template]
 // CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %F: type = fn_type @F [template]
 // CHECK:STDOUT:   %struct: F = struct_value () [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .F = %F.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %F.decl: F = fn_decl @F [template = constants.%struct] {
-// CHECK:STDOUT:     %x.loc4_6.1: i32 = param x
-// CHECK:STDOUT:     @F.%x: i32 = bind_name x, %x.loc4_6.1
+// CHECK:STDOUT:     %.loc4_10.1: () = tuple_literal ()
+// CHECK:STDOUT:     %.loc4_10.2: type = converted %.loc4_10.1, constants.%.1 [template = constants.%.1]
+// CHECK:STDOUT:     %x.loc4_6.1: () = param x
+// CHECK:STDOUT:     @F.%x: () = bind_name x, %x.loc4_6.1
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @F(%x: i32) {
+// CHECK:STDOUT: fn @F(%x: ()) {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
@@ -252,10 +268,8 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .F2 = %F2.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %F2.decl: F2 = fn_decl @F2 [template = constants.%struct] {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -264,14 +278,40 @@ fn Other.G() {}
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: --- other_fn_use.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %G: type = fn_type @G [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %struct.1: G = struct_value () [template]
+// CHECK:STDOUT:   %F: type = fn_type @F [template]
+// CHECK:STDOUT:   %struct.2: F = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .F = %import_ref
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %import_ref: F = import_ref ir1, inst+1, loaded [template = constants.%struct.2]
+// CHECK:STDOUT:   %G.decl: G = fn_decl @G [template = constants.%struct.1] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %F.ref: F = name_ref F, file.%import_ref [template = constants.%struct.2]
+// CHECK:STDOUT:   %F.call: init () = call %F.ref()
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F();
+// CHECK:STDOUT:
 // CHECK:STDOUT: --- main_other_ns.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -289,15 +329,13 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:     .Run = %Run.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Run.decl: Run = fn_decl @Run [template = constants.%struct.1] {}
-// CHECK:STDOUT:   %import_ref.1: F = import_ref ir2, inst+2, loaded [template = constants.%struct.2]
-// CHECK:STDOUT:   %import_ref.2: F2 = import_ref ir3, inst+2, loaded [template = constants.%struct.3]
+// CHECK:STDOUT:   %import_ref.1: F = import_ref ir1, inst+1, loaded [template = constants.%struct.2]
+// CHECK:STDOUT:   %import_ref.2: F2 = import_ref ir2, inst+1, loaded [template = constants.%struct.3]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Run() {
@@ -327,15 +365,13 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:     .Run = %Run.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Run.decl: Run = fn_decl @Run [template = constants.%struct.1] {}
-// CHECK:STDOUT:   %import_ref.1: F = import_ref ir2, inst+2, loaded [template = constants.%struct.2]
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir3, inst+2, unloaded
+// CHECK:STDOUT:   %import_ref.1: F = import_ref ir1, inst+1, loaded [template = constants.%struct.2]
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir2, inst+1, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Run() {
@@ -352,10 +388,8 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -371,15 +405,13 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:     .Run = %Run.decl
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Run.decl: Run = fn_decl @Run [template = constants.%struct.1] {}
-// CHECK:STDOUT:   %import_ref.1: F = import_ref ir2, inst+2, loaded [template = constants.%struct.2]
-// CHECK:STDOUT:   %import_ref.2 = import_ref ir3, inst+4, unloaded
+// CHECK:STDOUT:   %import_ref.1: F = import_ref ir1, inst+1, loaded [template = constants.%struct.2]
+// CHECK:STDOUT:   %import_ref.2 = import_ref ir2, inst+6, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Run() {
@@ -403,12 +435,10 @@ fn Other.G() {}
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .Other = %Other
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %import_ref.1: <namespace> = import_ref ir1, inst+2, loaded
+// CHECK:STDOUT:   %import_ref.1: <namespace> = import_ref ir1, inst+1, loaded
 // CHECK:STDOUT:   %Other: <namespace> = namespace %import_ref.1, [template] {}
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
-// CHECK:STDOUT:   %import_ref.2: F = import_ref ir3, inst+2, loaded [template = constants.%struct]
+// CHECK:STDOUT:   %import_ref.2: F = import_ref ir2, inst+1, loaded [template = constants.%struct]
 // CHECK:STDOUT:   %F.decl: F = fn_decl @F [template = constants.%struct] {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -427,10 +457,8 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .G = %G.decl
 // CHECK:STDOUT:   }
@@ -453,10 +481,8 @@ fn Other.G() {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [template] {
-// CHECK:STDOUT:     .Core = %Core
 // CHECK:STDOUT:     .Other = %Other
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Core: <namespace> = namespace [template] {}
 // CHECK:STDOUT:   %Other: <namespace> = namespace [template] {
 // CHECK:STDOUT:     .G = %G.decl
 // CHECK:STDOUT:   }
@@ -468,3 +494,27 @@ fn Other.G() {}
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_use_other_fn_use.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %UseF: type = fn_type @UseF [template]
+// CHECK:STDOUT:   %.1: type = tuple_type () [template]
+// CHECK:STDOUT:   %struct: UseF = struct_value () [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Other = %Other
+// CHECK:STDOUT:     .UseF = %UseF.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Other: <namespace> = namespace [template] {}
+// CHECK:STDOUT:   %UseF.decl: UseF = fn_decl @UseF [template = constants.%struct] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @UseF() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %Other.ref: <namespace> = name_ref Other, file.%Other [template = file.%Other]
+// CHECK:STDOUT:   %F.ref: <error> = name_ref F, <error> [template = <error>]
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT: