April 2016's Issue #33174 called out the E0446 diagnostics as
confusing. While adding the name of the restricted type to the message
(
548e681f) 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.
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));
}
}
}
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 | | }
--- /dev/null
+// 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() {}
--- /dev/null
+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`.