Skip to content

Commit c1e21fb

Browse files
committed
resolve: Catch "cannot reexport" errors from macros 2.0 better
1 parent 97cda43 commit c1e21fb

5 files changed

Lines changed: 75 additions & 8 deletions

File tree

compiler/rustc_resolve/src/imports.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,29 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
787787
let resolution = resolution.borrow();
788788
let Some(binding) = resolution.best_decl() else { continue };
789789

790+
// Report "cannot reexport" errors for exotic cases involving macros 2.0
791+
// privacy bending or invariant-breaking code under deprecation lints.
792+
for decl in [resolution.non_glob_decl, resolution.glob_decl] {
793+
if let Some(decl) = decl
794+
&& let DeclKind::Import { source_decl, import } = decl.kind
795+
{
796+
// The source entity is too private to be reexported
797+
// with the given import declaration's visibility.
798+
let ord = source_decl.vis().partial_cmp(decl.vis(), self.tcx);
799+
if matches!(ord, None | Some(Ordering::Less)) {
800+
let ident = match import.kind {
801+
ImportKind::Single { source, .. } => source,
802+
_ => key.ident.orig(resolution.orig_ident_span),
803+
};
804+
if let Some(lint) =
805+
self.report_cannot_reexport(import, source_decl, ident, key.ns)
806+
{
807+
self.lint_buffer.add_early_lint(lint);
808+
}
809+
}
810+
}
811+
}
812+
790813
if let DeclKind::Import { import, .. } = binding.kind
791814
&& let Some(amb_binding) = binding.ambiguity.get()
792815
&& binding.res() != Res::Err
@@ -1498,18 +1521,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14981521
let mut reexport_error = None;
14991522
let mut any_successful_reexport = false;
15001523
self.per_ns(|this, ns| {
1501-
let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) else {
1524+
let Some(binding) = bindings[ns].get().decl() else {
15021525
return;
15031526
};
15041527

15051528
if import.vis.greater_than(binding.vis(), this.tcx) {
1506-
reexport_error = Some((ns, binding));
1529+
// In isolation, a declaration like this is not an error, but if *all* 1-3
1530+
// declarations introduced by the import are more private than the import item's
1531+
// nominal visibility, then it's an error.
1532+
reexport_error = Some((ns, binding.import_source()));
15071533
} else {
15081534
any_successful_reexport = true;
15091535
}
15101536
});
15111537

1512-
// All namespaces must be re-exported with extra visibility for an error to occur.
15131538
if !any_successful_reexport {
15141539
let (ns, binding) = reexport_error.unwrap();
15151540
if let Some(lint) = self.report_cannot_reexport(import, binding, ident, ns) {

tests/ui/hygiene/privacy-early.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod foo {
88

99
pub macro m() {
1010
use f as g; //~ ERROR `f` is private, and cannot be re-exported
11+
//~| ERROR `f` is private, and cannot be re-exported
1112
f!();
1213
}
1314
}

tests/ui/hygiene/privacy-early.stderr

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,26 @@ LL | foo::m!();
1717
| --------- in this macro invocation
1818
= note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info)
1919

20-
error: aborting due to 1 previous error
20+
error[E0364]: `f` is private, and cannot be re-exported
21+
--> $DIR/privacy-early.rs:10:13
22+
|
23+
LL | use f as g;
24+
| ^^^^^^
25+
...
26+
LL | foo::m!();
27+
| --------- in this macro invocation
28+
|
29+
note: consider marking `f` as `pub` in the imported module
30+
--> $DIR/privacy-early.rs:10:13
31+
|
32+
LL | use f as g;
33+
| ^^^^^^
34+
...
35+
LL | foo::m!();
36+
| --------- in this macro invocation
37+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
38+
= note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info)
39+
40+
error: aborting due to 2 previous errors
2141

2242
For more information about this error, try `rustc --explain E0364`.

tests/ui/imports/private-from-decl-macro.fail.stderr

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
1+
error[E0364]: `S` is private, and cannot be re-exported
2+
--> $DIR/private-from-decl-macro.rs:18:13
3+
|
4+
LL | use crate::m::*;
5+
| ^^^^^^^^^^^
6+
...
7+
LL | crate::m::mac_glob!();
8+
| --------------------- in this macro invocation
9+
|
10+
note: consider marking `S` as `pub` in the imported module
11+
--> $DIR/private-from-decl-macro.rs:18:13
12+
|
13+
LL | use crate::m::*;
14+
| ^^^^^^^^^^^
15+
...
16+
LL | crate::m::mac_glob!();
17+
| --------------------- in this macro invocation
18+
= note: this error originates in the macro `crate::m::mac_glob` (in Nightly builds, run with -Z macro-backtrace for more info)
19+
120
error[E0423]: expected value, found struct `S`
2-
--> $DIR/private-from-decl-macro.rs:27:17
21+
--> $DIR/private-from-decl-macro.rs:28:17
322
|
423
LL | pub struct S {}
524
| --------------- `S` defined here
@@ -22,6 +41,7 @@ LL - let s = S;
2241
LL + let s = s;
2342
|
2443

25-
error: aborting due to 1 previous error
44+
error: aborting due to 2 previous errors
2645

27-
For more information about this error, try `rustc --explain E0423`.
46+
Some errors have detailed explanations: E0364, E0423.
47+
For more information about an error, try `rustc --explain E0364`.

tests/ui/imports/private-from-decl-macro.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ mod m {
1414
}
1515

1616
pub macro mac_glob() {
17-
use crate::m::*;
17+
#[cfg(fail)]
18+
use crate::m::*; //[fail]~ ERROR `S` is private, and cannot be re-exported
1819
}
1920
}
2021

0 commit comments

Comments
 (0)