Skip to content

Commit c2d44b2

Browse files
committed
in which the private/restricted-in-public error messaging gets specific
April 2016's Issue #33174 called out the E0446 diagnostics as confusing. While adding the name of the restricted type to the message (548e681) clarified matters somewhat, Esteban Küber pointed out that we could stand to place a secondary span on the restricted type. Here, we differentiate between crate-visible, truly private, and otherwise restricted types, and place a secondary span specifically on the visibility modifier of the restricted type's declaration (which we can do now that HIR visibilities have spans!). At long last, this resolves #33174.
1 parent 8d1cbb0 commit c2d44b2

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed

src/librustc_privacy/lib.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -1456,29 +1456,36 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
14561456
if let Some(def_id) = ty_def_id {
14571457
// Non-local means public (private items can't leave their crate, modulo bugs)
14581458
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
1459-
let vis = match self.tcx.hir.find(node_id) {
1459+
let hir_vis = match self.tcx.hir.find(node_id) {
14601460
Some(hir::map::NodeItem(item)) => &item.vis,
14611461
Some(hir::map::NodeForeignItem(item)) => &item.vis,
14621462
_ => bug!("expected item of foreign item"),
14631463
};
14641464

1465-
let vis = ty::Visibility::from_hir(vis, node_id, self.tcx);
1465+
let vis = ty::Visibility::from_hir(hir_vis, node_id, self.tcx);
14661466

14671467
if !vis.is_at_least(self.min_visibility, self.tcx) {
14681468
self.min_visibility = vis;
14691469
}
14701470
if !vis.is_at_least(self.required_visibility, self.tcx) {
1471+
let vis_adj = match hir_vis.node {
1472+
hir::VisibilityCrate(_) => "crate-visible",
1473+
hir::VisibilityRestricted { .. } => "restricted",
1474+
_ => "private"
1475+
};
1476+
14711477
if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
14721478
let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
1473-
"private type `{}` in public interface", ty);
1474-
err.span_label(self.span, "can't leak private type");
1479+
"{} type `{}` in public interface", vis_adj, ty);
1480+
err.span_label(self.span, format!("can't leak {} type", vis_adj));
1481+
err.span_label(hir_vis.span, format!("`{}` declared as {}", ty, vis_adj));
14751482
err.emit();
14761483
} else {
14771484
self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC,
14781485
node_id,
14791486
self.span,
1480-
&format!("private type `{}` in public \
1481-
interface (error E0446)", ty));
1487+
&format!("{} type `{}` in public \
1488+
interface (error E0446)", vis_adj, ty));
14821489
}
14831490
}
14841491
}

src/test/ui/error-codes/E0446.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0446]: private type `Foo::Bar` in public interface
22
--> $DIR/E0446.rs:14:5
33
|
4+
LL | struct Bar(u32);
5+
| - `Foo::Bar` declared as private
6+
LL |
47
LL | / pub fn bar() -> Bar { //~ ERROR E0446
58
LL | | Bar(0)
69
LL | | }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(non_camel_case_types)] // genus is always capitalized
12+
13+
pub(crate) struct Snail;
14+
//~^ NOTE `Snail` declared as crate-visible
15+
16+
mod sea {
17+
pub(super) struct Turtle;
18+
//~^ NOTE `sea::Turtle` declared as restricted
19+
}
20+
21+
struct Tortoise;
22+
//~^ NOTE `Tortoise` declared as private
23+
24+
pub struct Shell<T> {
25+
pub(crate) creature: T,
26+
}
27+
28+
pub type Helix_pomatia = Shell<Snail>;
29+
//~^ ERROR crate-visible type `Snail` in public interface
30+
//~| NOTE can't leak crate-visible type
31+
pub type Dermochelys_coriacea = Shell<sea::Turtle>;
32+
//~^ ERROR restricted type `sea::Turtle` in public interface
33+
//~| NOTE can't leak restricted type
34+
pub type Testudo_graeca = Shell<Tortoise>;
35+
//~^ ERROR private type `Tortoise` in public interface
36+
//~| NOTE can't leak private type
37+
38+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0446]: crate-visible type `Snail` in public interface
2+
--> $DIR/issue-33174-restricted-type-in-public-interface.rs:28:1
3+
|
4+
LL | pub(crate) struct Snail;
5+
| ---------- `Snail` declared as crate-visible
6+
...
7+
LL | pub type Helix_pomatia = Shell<Snail>;
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-visible type
9+
10+
error[E0446]: restricted type `sea::Turtle` in public interface
11+
--> $DIR/issue-33174-restricted-type-in-public-interface.rs:31:1
12+
|
13+
LL | pub(super) struct Turtle;
14+
| ---------- `sea::Turtle` declared as restricted
15+
...
16+
LL | pub type Dermochelys_coriacea = Shell<sea::Turtle>;
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak restricted type
18+
19+
error[E0446]: private type `Tortoise` in public interface
20+
--> $DIR/issue-33174-restricted-type-in-public-interface.rs:34:1
21+
|
22+
LL | struct Tortoise;
23+
| - `Tortoise` declared as private
24+
...
25+
LL | pub type Testudo_graeca = Shell<Tortoise>;
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
27+
28+
error: aborting due to 3 previous errors
29+
30+
For more information about this error, try `rustc --explain E0446`.

0 commit comments

Comments
 (0)