Skip to content

Commit

Permalink
in which the private/restricted-in-public error messaging gets specific
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
zackmdavis committed Jul 1, 2018
1 parent 8d1cbb0 commit c2d44b2
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 6 deletions.
19 changes: 13 additions & 6 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1456,29 +1456,36 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
if let Some(def_id) = ty_def_id {
// Non-local means public (private items can't leave their crate, modulo bugs)
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
let vis = match self.tcx.hir.find(node_id) {
let hir_vis = match self.tcx.hir.find(node_id) {
Some(hir::map::NodeItem(item)) => &item.vis,
Some(hir::map::NodeForeignItem(item)) => &item.vis,
_ => bug!("expected item of foreign item"),
};

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

if !vis.is_at_least(self.min_visibility, self.tcx) {
self.min_visibility = vis;
}
if !vis.is_at_least(self.required_visibility, self.tcx) {
let vis_adj = match hir_vis.node {
hir::VisibilityCrate(_) => "crate-visible",
hir::VisibilityRestricted { .. } => "restricted",
_ => "private"
};

if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
"private type `{}` in public interface", ty);
err.span_label(self.span, "can't leak private type");
"{} type `{}` in public interface", vis_adj, ty);
err.span_label(self.span, format!("can't leak {} type", vis_adj));
err.span_label(hir_vis.span, format!("`{}` declared as {}", ty, vis_adj));
err.emit();
} else {
self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC,
node_id,
self.span,
&format!("private type `{}` in public \
interface (error E0446)", ty));
&format!("{} type `{}` in public \
interface (error E0446)", vis_adj, ty));
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/error-codes/E0446.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
error[E0446]: private type `Foo::Bar` in public interface
--> $DIR/E0446.rs:14:5
|
LL | struct Bar(u32);
| - `Foo::Bar` declared as private
LL |
LL | / pub fn bar() -> Bar { //~ ERROR E0446
LL | | Bar(0)
LL | | }
Expand Down
38 changes: 38 additions & 0 deletions src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_camel_case_types)] // genus is always capitalized

pub(crate) struct Snail;
//~^ NOTE `Snail` declared as crate-visible

mod sea {
pub(super) struct Turtle;
//~^ NOTE `sea::Turtle` declared as restricted
}

struct Tortoise;
//~^ NOTE `Tortoise` declared as private

pub struct Shell<T> {
pub(crate) creature: T,
}

pub type Helix_pomatia = Shell<Snail>;
//~^ ERROR crate-visible type `Snail` in public interface
//~| NOTE can't leak crate-visible type
pub type Dermochelys_coriacea = Shell<sea::Turtle>;
//~^ ERROR restricted type `sea::Turtle` in public interface
//~| NOTE can't leak restricted type
pub type Testudo_graeca = Shell<Tortoise>;
//~^ ERROR private type `Tortoise` in public interface
//~| NOTE can't leak private type

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
error[E0446]: crate-visible type `Snail` in public interface
--> $DIR/issue-33174-restricted-type-in-public-interface.rs:28:1
|
LL | pub(crate) struct Snail;
| ---------- `Snail` declared as crate-visible
...
LL | pub type Helix_pomatia = Shell<Snail>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-visible type

error[E0446]: restricted type `sea::Turtle` in public interface
--> $DIR/issue-33174-restricted-type-in-public-interface.rs:31:1
|
LL | pub(super) struct Turtle;
| ---------- `sea::Turtle` declared as restricted
...
LL | pub type Dermochelys_coriacea = Shell<sea::Turtle>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak restricted type

error[E0446]: private type `Tortoise` in public interface
--> $DIR/issue-33174-restricted-type-in-public-interface.rs:34:1
|
LL | struct Tortoise;
| - `Tortoise` declared as private
...
LL | pub type Testudo_graeca = Shell<Tortoise>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type

error: aborting due to 3 previous errors

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

0 comments on commit c2d44b2

Please sign in to comment.