Skip to content

Commit 4fb57e0

Browse files
committed
one-time diagnostic and suggestion for reëxporting private variant error
We issue just one message for an erroneous glob private variant reëxport (using the Session's one-time-diagnostics capability), but individual (non-glob) such erroneous reëxports still get their own messages. The suggestion to make the enum public is also one-time. The enum variant reëxport error didn't have an associated error code (and remedying this here is deemed out of the scope of this commit), so we resort to the expediency of using 0 as the `DiagnosticMessageId` value. Adding Debug to NameResolution was helpful in development. This resolves #46209.
1 parent 883f5e5 commit 4fb57e0

File tree

3 files changed

+109
-10
lines changed

3 files changed

+109
-10
lines changed

src/librustc_resolve/resolve_imports.rs

+54-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc::ty;
2121
use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
2222
use rustc::hir::def_id::DefId;
2323
use rustc::hir::def::*;
24+
use rustc::session::DiagnosticMessageId;
2425
use rustc::util::nodemap::{FxHashMap, FxHashSet};
2526

2627
use syntax::ast::{Ident, Name, SpannedIdent, NodeId};
@@ -72,7 +73,7 @@ impl<'a> ImportDirective<'a> {
7273
}
7374
}
7475

75-
#[derive(Clone, Default)]
76+
#[derive(Clone, Default, Debug)]
7677
/// Records information about the resolution of a name in a namespace of a module.
7778
pub struct NameResolution<'a> {
7879
/// The single imports that define the name in the namespace.
@@ -867,12 +868,59 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
867868
}
868869

869870
match binding.kind {
870-
NameBindingKind::Import { binding: orig_binding, .. } => {
871+
NameBindingKind::Import { binding: orig_binding, directive, .. } => {
871872
if ns == TypeNS && orig_binding.is_variant() &&
872-
!orig_binding.vis.is_at_least(binding.vis, &*self) {
873-
let msg = format!("variant `{}` is private, and cannot be reexported, \
874-
consider declaring its enum as `pub`", ident);
875-
self.session.span_err(binding.span, &msg);
873+
!orig_binding.vis.is_at_least(binding.vis, &*self) {
874+
let msg = match directive.subclass {
875+
ImportDirectiveSubclass::SingleImport { .. } => {
876+
format!("variant `{}` is private and cannot be reexported",
877+
ident)
878+
},
879+
ImportDirectiveSubclass::GlobImport { .. } => {
880+
let msg = "enum is private and its variants \
881+
cannot be reexported".to_owned();
882+
let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
883+
Some(binding.span),
884+
msg.clone());
885+
let fresh = self.session.one_time_diagnostics
886+
.borrow_mut().insert(error_id);
887+
if !fresh {
888+
continue;
889+
}
890+
msg
891+
},
892+
ref s @ _ => bug!("unexpected import subclass {:?}", s)
893+
};
894+
let mut err = self.session.struct_span_err(binding.span, &msg);
895+
896+
let imported_module = directive.imported_module.get()
897+
.expect("module should exist");
898+
let resolutions = imported_module.parent.expect("parent should exist")
899+
.resolutions.borrow();
900+
let enum_path_segment_index = directive.module_path.len() - 1;
901+
let enum_ident = directive.module_path[enum_path_segment_index].node;
902+
903+
let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
904+
.expect("resolution should exist");
905+
let enum_span = enum_resolution.borrow()
906+
.binding.expect("binding should exist")
907+
.span;
908+
let enum_def_span = self.session.codemap().def_span(enum_span);
909+
let enum_def_snippet = self.session.codemap()
910+
.span_to_snippet(enum_def_span).expect("snippet should exist");
911+
// potentially need to strip extant `crate`/`pub(path)` for suggestion
912+
let after_vis_index = enum_def_snippet.find("enum")
913+
.expect("`enum` keyword should exist in snippet");
914+
let suggestion = format!("pub {}",
915+
&enum_def_snippet[after_vis_index..]);
916+
917+
self.session
918+
.diag_span_suggestion_once(&mut err,
919+
DiagnosticMessageId::ErrorId(0),
920+
enum_def_span,
921+
"consider making the enum public",
922+
suggestion);
923+
err.emit();
876924
}
877925
}
878926
NameBindingKind::Ambiguity { b1, b2, .. }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2017 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+
#![feature(crate_visibility_modifier)]
12+
13+
mod rank {
14+
pub use self::Professor::*;
15+
//~^ ERROR enum is private and its variants cannot be reexported
16+
pub use self::Lieutenant::{JuniorGrade, Full};
17+
//~^ ERROR variant `JuniorGrade` is private and cannot be reexported
18+
//~| ERROR variant `Full` is private and cannot be reexported
19+
pub use self::PettyOfficer::*;
20+
//~^ ERROR enum is private and its variants cannot be reexported
21+
pub use self::Crewman::*;
22+
//~^ ERROR enum is private and its variants cannot be reexported
23+
24+
enum Professor {
25+
Adjunct,
26+
Assistant,
27+
Associate,
28+
Full
29+
}
30+
31+
enum Lieutenant {
32+
JuniorGrade,
33+
Full,
34+
}
35+
36+
pub(in rank) enum PettyOfficer {
37+
SecondClass,
38+
FirstClass,
39+
Chief,
40+
MasterChief
41+
}
42+
43+
crate enum Crewman {
44+
Recruit,
45+
Apprentice,
46+
Full
47+
}
48+
49+
}
50+
51+
fn main() {}

src/test/compile-fail/private-variant-reexport.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@
99
// except according to those terms.
1010

1111
mod m1 {
12-
pub use ::E::V; //~ ERROR variant `V` is private, and cannot be reexported
12+
pub use ::E::V; //~ ERROR variant `V` is private and cannot be reexported
1313
}
1414

1515
mod m2 {
16-
pub use ::E::{V}; //~ ERROR variant `V` is private, and cannot be reexported
16+
pub use ::E::{V}; //~ ERROR variant `V` is private and cannot be reexported
1717
}
1818

1919
mod m3 {
20-
pub use ::E::V::{self}; //~ ERROR variant `V` is private, and cannot be reexported
20+
pub use ::E::V::{self}; //~ ERROR variant `V` is private and cannot be reexported
2121
}
2222

2323
mod m4 {
24-
pub use ::E::*; //~ ERROR variant `V` is private, and cannot be reexported
24+
pub use ::E::*; //~ ERROR enum is private and its variants cannot be reexported
2525
}
2626

2727
enum E { V }

0 commit comments

Comments
 (0)