Skip to content

Commit d349273

Browse files
authored
Rollup merge of rust-lang#68153 - petrochenkov:privdiag, r=estebank
resolve: Point at the private item definitions in privacy errors A basic version of rust-lang#67951. r? @estebank
2 parents 30ef7e1 + a68334a commit d349273

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1210
-316
lines changed

src/librustc_resolve/diagnostics.rs

+160-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet;
88
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
99
use rustc_feature::BUILTIN_ATTRIBUTES;
1010
use rustc_hir::def::Namespace::{self, *};
11-
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
11+
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
1212
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1313
use rustc_span::hygiene::MacroKind;
1414
use rustc_span::source_map::SourceMap;
@@ -20,8 +20,9 @@ use syntax::util::lev_distance::find_best_match_for_name;
2020

2121
use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
2222
use crate::path_names_to_string;
23-
use crate::VisResolutionError;
23+
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
2424
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
25+
use crate::{NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
2526
use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment};
2627

2728
use rustc_error_codes::*;
@@ -802,6 +803,163 @@ impl<'a> Resolver<'a> {
802803
}
803804
false
804805
}
806+
807+
fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
808+
let res = b.res();
809+
if b.span.is_dummy() {
810+
let add_built_in = match b.res() {
811+
// These already contain the "built-in" prefix or look bad with it.
812+
Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod => false,
813+
_ => true,
814+
};
815+
let (built_in, from) = if from_prelude {
816+
("", " from prelude")
817+
} else if b.is_extern_crate()
818+
&& !b.is_import()
819+
&& self.session.opts.externs.get(&ident.as_str()).is_some()
820+
{
821+
("", " passed with `--extern`")
822+
} else if add_built_in {
823+
(" built-in", "")
824+
} else {
825+
("", "")
826+
};
827+
828+
let article = if built_in.is_empty() { res.article() } else { "a" };
829+
format!(
830+
"{a}{built_in} {thing}{from}",
831+
a = article,
832+
thing = res.descr(),
833+
built_in = built_in,
834+
from = from
835+
)
836+
} else {
837+
let introduced = if b.is_import() { "imported" } else { "defined" };
838+
format!("the {thing} {introduced} here", thing = res.descr(), introduced = introduced)
839+
}
840+
}
841+
842+
crate fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
843+
let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
844+
let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
845+
// We have to print the span-less alternative first, otherwise formatting looks bad.
846+
(b2, b1, misc2, misc1, true)
847+
} else {
848+
(b1, b2, misc1, misc2, false)
849+
};
850+
851+
let mut err = struct_span_err!(
852+
self.session,
853+
ident.span,
854+
E0659,
855+
"`{ident}` is ambiguous ({why})",
856+
ident = ident,
857+
why = kind.descr()
858+
);
859+
err.span_label(ident.span, "ambiguous name");
860+
861+
let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
862+
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
863+
let note_msg = format!(
864+
"`{ident}` could{also} refer to {what}",
865+
ident = ident,
866+
also = also,
867+
what = what
868+
);
869+
870+
let thing = b.res().descr();
871+
let mut help_msgs = Vec::new();
872+
if b.is_glob_import()
873+
&& (kind == AmbiguityKind::GlobVsGlob
874+
|| kind == AmbiguityKind::GlobVsExpanded
875+
|| kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
876+
{
877+
help_msgs.push(format!(
878+
"consider adding an explicit import of \
879+
`{ident}` to disambiguate",
880+
ident = ident
881+
))
882+
}
883+
if b.is_extern_crate() && ident.span.rust_2018() {
884+
help_msgs.push(format!(
885+
"use `::{ident}` to refer to this {thing} unambiguously",
886+
ident = ident,
887+
thing = thing,
888+
))
889+
}
890+
if misc == AmbiguityErrorMisc::SuggestCrate {
891+
help_msgs.push(format!(
892+
"use `crate::{ident}` to refer to this {thing} unambiguously",
893+
ident = ident,
894+
thing = thing,
895+
))
896+
} else if misc == AmbiguityErrorMisc::SuggestSelf {
897+
help_msgs.push(format!(
898+
"use `self::{ident}` to refer to this {thing} unambiguously",
899+
ident = ident,
900+
thing = thing,
901+
))
902+
}
903+
904+
err.span_note(b.span, &note_msg);
905+
for (i, help_msg) in help_msgs.iter().enumerate() {
906+
let or = if i == 0 { "" } else { "or " };
907+
err.help(&format!("{}{}", or, help_msg));
908+
}
909+
};
910+
911+
could_refer_to(b1, misc1, "");
912+
could_refer_to(b2, misc2, " also");
913+
err.emit();
914+
}
915+
916+
crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
917+
let PrivacyError { ident, binding, .. } = *privacy_error;
918+
let session = &self.session;
919+
let mk_struct_span_error = |is_constructor| {
920+
let mut descr = binding.res().descr().to_string();
921+
if is_constructor {
922+
descr += " constructor";
923+
}
924+
if binding.is_import() {
925+
descr += " import";
926+
}
927+
928+
let mut err =
929+
struct_span_err!(session, ident.span, E0603, "{} `{}` is private", descr, ident);
930+
931+
err.span_label(ident.span, &format!("this {} is private", descr));
932+
err.span_note(
933+
session.source_map().def_span(binding.span),
934+
&format!("the {} `{}` is defined here", descr, ident),
935+
);
936+
937+
err
938+
};
939+
940+
let mut err = if let NameBindingKind::Res(
941+
Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id),
942+
_,
943+
) = binding.kind
944+
{
945+
let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
946+
if let Some(fields) = self.field_names.get(&def_id) {
947+
let mut err = mk_struct_span_error(true);
948+
let first_field = fields.first().expect("empty field list in the map");
949+
err.span_label(
950+
fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)),
951+
"a constructor is private if any of the fields is private",
952+
);
953+
err
954+
} else {
955+
mk_struct_span_error(false)
956+
}
957+
} else {
958+
mk_struct_span_error(false)
959+
};
960+
961+
err.emit();
962+
}
805963
}
806964

807965
impl<'a, 'b> ImportResolver<'a, 'b> {

src/librustc_resolve/imports.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,11 @@ impl<'a> Resolver<'a> {
319319
// Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
320320
!(self.last_import_segment && binding.is_extern_crate())
321321
{
322-
self.privacy_errors.push(PrivacyError(path_span, ident, binding));
322+
self.privacy_errors.push(PrivacyError {
323+
ident,
324+
binding,
325+
dedup_span: path_span,
326+
});
323327
}
324328

325329
Ok(binding)

src/librustc_resolve/lib.rs

+10-152
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22
//!
33
//! Module structure of the crate is built here.
44
//! Paths in macros, imports, expressions, types, patterns are resolved here.
5-
//! Label names are resolved here as well.
5+
//! Label and lifetime names are resolved here as well.
66
//!
77
//! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`.
8-
//! Lifetime names are resolved in `librustc/middle/resolve_lifetime.rs`.
9-
10-
// ignore-tidy-filelength
118
129
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
1310
#![feature(bool_to_option)]
@@ -33,7 +30,7 @@ use rustc_data_structures::sync::Lrc;
3330
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
3431
use rustc_expand::base::SyntaxExtension;
3532
use rustc_hir::def::Namespace::*;
36-
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
33+
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
3734
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
3835
use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
3936
use rustc_hir::{GlobMap, TraitMap};
@@ -604,7 +601,11 @@ impl<'a> NameBindingKind<'a> {
604601
}
605602
}
606603

607-
struct PrivacyError<'a>(Span, Ident, &'a NameBinding<'a>);
604+
struct PrivacyError<'a> {
605+
ident: Ident,
606+
binding: &'a NameBinding<'a>,
607+
dedup_span: Span,
608+
}
608609

609610
struct UseError<'a> {
610611
err: DiagnosticBuilder<'a>,
@@ -2446,115 +2447,6 @@ impl<'a> Resolver<'a> {
24462447
}
24472448
}
24482449

2449-
fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
2450-
let res = b.res();
2451-
if b.span.is_dummy() {
2452-
let add_built_in = match b.res() {
2453-
// These already contain the "built-in" prefix or look bad with it.
2454-
Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod => false,
2455-
_ => true,
2456-
};
2457-
let (built_in, from) = if from_prelude {
2458-
("", " from prelude")
2459-
} else if b.is_extern_crate()
2460-
&& !b.is_import()
2461-
&& self.session.opts.externs.get(&ident.as_str()).is_some()
2462-
{
2463-
("", " passed with `--extern`")
2464-
} else if add_built_in {
2465-
(" built-in", "")
2466-
} else {
2467-
("", "")
2468-
};
2469-
2470-
let article = if built_in.is_empty() { res.article() } else { "a" };
2471-
format!(
2472-
"{a}{built_in} {thing}{from}",
2473-
a = article,
2474-
thing = res.descr(),
2475-
built_in = built_in,
2476-
from = from
2477-
)
2478-
} else {
2479-
let introduced = if b.is_import() { "imported" } else { "defined" };
2480-
format!("the {thing} {introduced} here", thing = res.descr(), introduced = introduced)
2481-
}
2482-
}
2483-
2484-
fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
2485-
let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
2486-
let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
2487-
// We have to print the span-less alternative first, otherwise formatting looks bad.
2488-
(b2, b1, misc2, misc1, true)
2489-
} else {
2490-
(b1, b2, misc1, misc2, false)
2491-
};
2492-
2493-
let mut err = struct_span_err!(
2494-
self.session,
2495-
ident.span,
2496-
E0659,
2497-
"`{ident}` is ambiguous ({why})",
2498-
ident = ident,
2499-
why = kind.descr()
2500-
);
2501-
err.span_label(ident.span, "ambiguous name");
2502-
2503-
let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
2504-
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
2505-
let note_msg = format!(
2506-
"`{ident}` could{also} refer to {what}",
2507-
ident = ident,
2508-
also = also,
2509-
what = what
2510-
);
2511-
2512-
let thing = b.res().descr();
2513-
let mut help_msgs = Vec::new();
2514-
if b.is_glob_import()
2515-
&& (kind == AmbiguityKind::GlobVsGlob
2516-
|| kind == AmbiguityKind::GlobVsExpanded
2517-
|| kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
2518-
{
2519-
help_msgs.push(format!(
2520-
"consider adding an explicit import of \
2521-
`{ident}` to disambiguate",
2522-
ident = ident
2523-
))
2524-
}
2525-
if b.is_extern_crate() && ident.span.rust_2018() {
2526-
help_msgs.push(format!(
2527-
"use `::{ident}` to refer to this {thing} unambiguously",
2528-
ident = ident,
2529-
thing = thing,
2530-
))
2531-
}
2532-
if misc == AmbiguityErrorMisc::SuggestCrate {
2533-
help_msgs.push(format!(
2534-
"use `crate::{ident}` to refer to this {thing} unambiguously",
2535-
ident = ident,
2536-
thing = thing,
2537-
))
2538-
} else if misc == AmbiguityErrorMisc::SuggestSelf {
2539-
help_msgs.push(format!(
2540-
"use `self::{ident}` to refer to this {thing} unambiguously",
2541-
ident = ident,
2542-
thing = thing,
2543-
))
2544-
}
2545-
2546-
err.span_note(b.span, &note_msg);
2547-
for (i, help_msg) in help_msgs.iter().enumerate() {
2548-
let or = if i == 0 { "" } else { "or " };
2549-
err.help(&format!("{}{}", or, help_msg));
2550-
}
2551-
};
2552-
2553-
could_refer_to(b1, misc1, "");
2554-
could_refer_to(b2, misc2, " also");
2555-
err.emit();
2556-
}
2557-
25582450
fn report_errors(&mut self, krate: &Crate) {
25592451
self.report_with_use_injections(krate);
25602452

@@ -2575,43 +2467,9 @@ impl<'a> Resolver<'a> {
25752467
}
25762468

25772469
let mut reported_spans = FxHashSet::default();
2578-
for &PrivacyError(dedup_span, ident, binding) in &self.privacy_errors {
2579-
if reported_spans.insert(dedup_span) {
2580-
let session = &self.session;
2581-
let mk_struct_span_error = |is_constructor| {
2582-
struct_span_err!(
2583-
session,
2584-
ident.span,
2585-
E0603,
2586-
"{}{} `{}` is private",
2587-
binding.res().descr(),
2588-
if is_constructor { " constructor" } else { "" },
2589-
ident.name,
2590-
)
2591-
};
2592-
2593-
let mut err = if let NameBindingKind::Res(
2594-
Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id),
2595-
_,
2596-
) = binding.kind
2597-
{
2598-
let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
2599-
if let Some(fields) = self.field_names.get(&def_id) {
2600-
let mut err = mk_struct_span_error(true);
2601-
let first_field = fields.first().expect("empty field list in the map");
2602-
err.span_label(
2603-
fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)),
2604-
"a constructor is private if any of the fields is private",
2605-
);
2606-
err
2607-
} else {
2608-
mk_struct_span_error(false)
2609-
}
2610-
} else {
2611-
mk_struct_span_error(false)
2612-
};
2613-
2614-
err.emit();
2470+
for error in &self.privacy_errors {
2471+
if reported_spans.insert(error.dedup_span) {
2472+
self.report_privacy_error(error);
26152473
}
26162474
}
26172475
}

0 commit comments

Comments
 (0)