Skip to content

Commit 5c6941b

Browse files
authored
Rollup merge of #67106 - petrochenkov:docerr, r=matthewjasper
resolve: Resolve visibilities on fields with non-builtin attributes Follow-up to #66669. The first commit is primary (and also a backport candidate), the other ones are further cleanups. In this case it's not strictly necessary to avoid reporting errors during speculative resolution because 1) all visibilities are resolved non-speculatively sooner or later and 2) error reporting infrastructure merges identical errors with identical spans anyway. Fixes #67006 r? @matthewjasper
2 parents 4166ce8 + 5f6267c commit 5c6941b

File tree

5 files changed

+162
-88
lines changed

5 files changed

+162
-88
lines changed

src/librustc_resolve/build_reduced_graph.rs

+73-88
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm
1212
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
1313
use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
1414
use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
15-
use crate::{ResolutionError, Determinacy, PathResult, CrateLint};
15+
use crate::{ResolutionError, VisResolutionError, Determinacy, PathResult, CrateLint};
1616

1717
use rustc::bug;
1818
use rustc::hir::def::{self, *};
@@ -32,8 +32,7 @@ use syntax::attr;
3232
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
3333
use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
3434
use syntax::token::{self, Token};
35-
use syntax::print::pprust;
36-
use syntax::{span_err, struct_span_err};
35+
use syntax::span_err;
3736
use syntax::source_map::{respan, Spanned};
3837
use syntax::symbol::{kw, sym};
3938
use syntax::visit::{self, Visitor};
@@ -192,14 +191,25 @@ impl<'a> AsMut<Resolver<'a>> for BuildReducedGraphVisitor<'a, '_> {
192191

193192
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
194193
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
194+
self.resolve_visibility_speculative(vis, false).unwrap_or_else(|err| {
195+
self.r.report_vis_error(err);
196+
ty::Visibility::Public
197+
})
198+
}
199+
200+
fn resolve_visibility_speculative<'ast>(
201+
&mut self,
202+
vis: &'ast ast::Visibility,
203+
speculative: bool,
204+
) -> Result<ty::Visibility, VisResolutionError<'ast>> {
195205
let parent_scope = &self.parent_scope;
196206
match vis.node {
197-
ast::VisibilityKind::Public => ty::Visibility::Public,
207+
ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
198208
ast::VisibilityKind::Crate(..) => {
199-
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
209+
Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
200210
}
201211
ast::VisibilityKind::Inherited => {
202-
ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)
212+
Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id))
203213
}
204214
ast::VisibilityKind::Restricted { ref path, id, .. } => {
205215
// For visibilities we are not ready to provide correct implementation of "uniform
@@ -209,86 +219,67 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
209219
let ident = path.segments.get(0).expect("empty path in visibility").ident;
210220
let crate_root = if ident.is_path_segment_keyword() {
211221
None
212-
} else if ident.span.rust_2018() {
213-
let msg = "relative paths are not supported in visibilities on 2018 edition";
214-
self.r.session.struct_span_err(ident.span, msg)
215-
.span_suggestion(
216-
path.span,
217-
"try",
218-
format!("crate::{}", pprust::path_to_string(&path)),
219-
Applicability::MaybeIncorrect,
220-
)
221-
.emit();
222-
return ty::Visibility::Public;
223-
} else {
224-
let ctxt = ident.span.ctxt();
222+
} else if ident.span.rust_2015() {
225223
Some(Segment::from_ident(Ident::new(
226-
kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
224+
kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ident.span.ctxt())
227225
)))
226+
} else {
227+
return Err(VisResolutionError::Relative2018(ident.span, path));
228228
};
229229

230230
let segments = crate_root.into_iter()
231231
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
232-
let expected_found_error = |this: &Self, res: Res| {
233-
let path_str = Segment::names_to_string(&segments);
234-
struct_span_err!(this.r.session, path.span, E0577,
235-
"expected module, found {} `{}`", res.descr(), path_str)
236-
.span_label(path.span, "not a module").emit();
237-
};
232+
let expected_found_error = |res| Err(VisResolutionError::ExpectedFound(
233+
path.span, Segment::names_to_string(&segments), res
234+
));
238235
match self.r.resolve_path(
239236
&segments,
240237
Some(TypeNS),
241238
parent_scope,
242-
true,
239+
!speculative,
243240
path.span,
244241
CrateLint::SimplePath(id),
245242
) {
246243
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
247244
let res = module.res().expect("visibility resolved to unnamed block");
248-
self.r.record_partial_res(id, PartialRes::new(res));
245+
if !speculative {
246+
self.r.record_partial_res(id, PartialRes::new(res));
247+
}
249248
if module.is_normal() {
250249
if res == Res::Err {
251-
ty::Visibility::Public
250+
Ok(ty::Visibility::Public)
252251
} else {
253252
let vis = ty::Visibility::Restricted(res.def_id());
254253
if self.r.is_accessible_from(vis, parent_scope.module) {
255-
vis
254+
Ok(vis)
256255
} else {
257-
struct_span_err!(self.r.session, path.span, E0742,
258-
"visibilities can only be restricted to ancestor modules")
259-
.emit();
260-
ty::Visibility::Public
256+
Err(VisResolutionError::AncestorOnly(path.span))
261257
}
262258
}
263259
} else {
264-
expected_found_error(self, res);
265-
ty::Visibility::Public
260+
expected_found_error(res)
266261
}
267262
}
268-
PathResult::Module(..) => {
269-
self.r.session.span_err(path.span, "visibility must resolve to a module");
270-
ty::Visibility::Public
271-
}
272-
PathResult::NonModule(partial_res) => {
273-
expected_found_error(self, partial_res.base_res());
274-
ty::Visibility::Public
275-
}
276-
PathResult::Failed { span, label, suggestion, .. } => {
277-
self.r.report_error(
278-
span, ResolutionError::FailedToResolve { label, suggestion }
279-
);
280-
ty::Visibility::Public
281-
}
282-
PathResult::Indeterminate => {
283-
span_err!(self.r.session, path.span, E0578,
284-
"cannot determine resolution for the visibility");
285-
ty::Visibility::Public
286-
}
263+
PathResult::Module(..) =>
264+
Err(VisResolutionError::ModuleOnly(path.span)),
265+
PathResult::NonModule(partial_res) =>
266+
expected_found_error(partial_res.base_res()),
267+
PathResult::Failed { span, label, suggestion, .. } =>
268+
Err(VisResolutionError::FailedToResolve(span, label, suggestion)),
269+
PathResult::Indeterminate =>
270+
Err(VisResolutionError::Indeterminate(path.span)),
287271
}
288272
}
289273
}
290274
}
291275

276+
fn insert_field_names_local(&mut self, def_id: DefId, vdata: &ast::VariantData) {
277+
let field_names = vdata.fields().iter().map(|field| {
278+
respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
279+
}).collect();
280+
self.insert_field_names(def_id, field_names);
281+
}
282+
292283
fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Spanned<Name>>) {
293284
if !field_names.is_empty() {
294285
self.r.field_names.insert(def_id, field_names);
@@ -726,59 +717,52 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
726717
}
727718

728719
// These items live in both the type and value namespaces.
729-
ItemKind::Struct(ref struct_def, _) => {
720+
ItemKind::Struct(ref vdata, _) => {
730721
// Define a name in the type namespace.
731722
let def_id = self.r.definitions.local_def_id(item.id);
732723
let res = Res::Def(DefKind::Struct, def_id);
733724
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
734725

735-
let mut ctor_vis = vis;
736-
737-
let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive);
738-
739-
// If the structure is marked as non_exhaustive then lower the visibility
740-
// to within the crate.
741-
if has_non_exhaustive && vis == ty::Visibility::Public {
742-
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
743-
}
744-
745726
// Record field names for error reporting.
746-
let field_names = struct_def.fields().iter().map(|field| {
747-
// NOTE: The field may be an expansion placeholder, but expansion sets correct
748-
// visibilities for unnamed field placeholders specifically, so the constructor
749-
// visibility should still be determined correctly.
750-
let field_vis = self.resolve_visibility(&field.vis);
751-
if ctor_vis.is_at_least(field_vis, &*self.r) {
752-
ctor_vis = field_vis;
753-
}
754-
respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
755-
}).collect();
756-
let item_def_id = self.r.definitions.local_def_id(item.id);
757-
self.insert_field_names(item_def_id, field_names);
727+
self.insert_field_names_local(def_id, vdata);
758728

759729
// If this is a tuple or unit struct, define a name
760730
// in the value namespace as well.
761-
if let Some(ctor_node_id) = struct_def.ctor_id() {
731+
if let Some(ctor_node_id) = vdata.ctor_id() {
732+
let mut ctor_vis = vis;
733+
// If the structure is marked as non_exhaustive then lower the visibility
734+
// to within the crate.
735+
if vis == ty::Visibility::Public &&
736+
attr::contains_name(&item.attrs, sym::non_exhaustive) {
737+
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
738+
}
739+
for field in vdata.fields() {
740+
// NOTE: The field may be an expansion placeholder, but expansion sets
741+
// correct visibilities for unnamed field placeholders specifically, so the
742+
// constructor visibility should still be determined correctly.
743+
if let Ok(field_vis) =
744+
self.resolve_visibility_speculative(&field.vis, true) {
745+
if ctor_vis.is_at_least(field_vis, &*self.r) {
746+
ctor_vis = field_vis;
747+
}
748+
}
749+
}
762750
let ctor_res = Res::Def(
763-
DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)),
751+
DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
764752
self.r.definitions.local_def_id(ctor_node_id),
765753
);
766754
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
767-
self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
755+
self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis));
768756
}
769757
}
770758

771759
ItemKind::Union(ref vdata, _) => {
772-
let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id));
760+
let def_id = self.r.definitions.local_def_id(item.id);
761+
let res = Res::Def(DefKind::Union, def_id);
773762
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
774763

775764
// Record field names for error reporting.
776-
let field_names = vdata.fields().iter().map(|field| {
777-
self.resolve_visibility(&field.vis);
778-
respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
779-
}).collect();
780-
let item_def_id = self.r.definitions.local_def_id(item.id);
781-
self.insert_field_names(item_def_id, field_names);
765+
self.insert_field_names_local(def_id, vdata);
782766
}
783767

784768
ItemKind::Impl(.., ref impl_items) => {
@@ -1281,6 +1265,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
12811265
if sf.is_placeholder {
12821266
self.visit_invoc(sf.id);
12831267
} else {
1268+
self.resolve_visibility(&sf.vis);
12841269
visit::walk_struct_field(self, sf);
12851270
}
12861271
}

src/librustc_resolve/diagnostics.rs

+40
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc::ty::{self, DefIdTree};
1111
use rustc::util::nodemap::FxHashSet;
1212
use rustc_feature::BUILTIN_ATTRIBUTES;
1313
use syntax::ast::{self, Ident, Path};
14+
use syntax::print::pprust;
1415
use syntax::source_map::SourceMap;
1516
use syntax::struct_span_err;
1617
use syntax::symbol::{Symbol, kw};
@@ -22,6 +23,7 @@ use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportRes
2223
use crate::path_names_to_string;
2324
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
2425
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
26+
use crate::VisResolutionError;
2527

2628
use rustc_error_codes::*;
2729

@@ -357,6 +359,44 @@ impl<'a> Resolver<'a> {
357359
}
358360
}
359361

362+
crate fn report_vis_error(&self, vis_resolution_error: VisResolutionError<'_>) {
363+
match vis_resolution_error {
364+
VisResolutionError::Relative2018(span, path) => {
365+
let mut err = self.session.struct_span_err(span,
366+
"relative paths are not supported in visibilities on 2018 edition");
367+
err.span_suggestion(
368+
path.span,
369+
"try",
370+
format!("crate::{}", pprust::path_to_string(&path)),
371+
Applicability::MaybeIncorrect,
372+
);
373+
err
374+
}
375+
VisResolutionError::AncestorOnly(span) => {
376+
struct_span_err!(self.session, span, E0742,
377+
"visibilities can only be restricted to ancestor modules")
378+
}
379+
VisResolutionError::FailedToResolve(span, label, suggestion) => {
380+
self.into_struct_error(
381+
span, ResolutionError::FailedToResolve { label, suggestion }
382+
)
383+
}
384+
VisResolutionError::ExpectedFound(span, path_str, res) => {
385+
let mut err = struct_span_err!(self.session, span, E0577,
386+
"expected module, found {} `{}`", res.descr(), path_str);
387+
err.span_label(span, "not a module");
388+
err
389+
}
390+
VisResolutionError::Indeterminate(span) => {
391+
struct_span_err!(self.session, span, E0578,
392+
"cannot determine resolution for the visibility")
393+
}
394+
VisResolutionError::ModuleOnly(span) => {
395+
self.session.struct_span_err(span, "visibility must resolve to a module")
396+
}
397+
}.emit()
398+
}
399+
360400
/// Lookup typo candidate in scope for a macro or import.
361401
fn early_lookup_typo_candidate(
362402
&mut self,

src/librustc_resolve/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,15 @@ enum ResolutionError<'a> {
218218
SelfInTyParamDefault,
219219
}
220220

221+
enum VisResolutionError<'a> {
222+
Relative2018(Span, &'a ast::Path),
223+
AncestorOnly(Span),
224+
FailedToResolve(Span, String, Option<Suggestion>),
225+
ExpectedFound(Span, String, Res),
226+
Indeterminate(Span),
227+
ModuleOnly(Span),
228+
}
229+
221230
// A minimal representation of a path segment. We use this in resolve because
222231
// we synthesize 'path segments' which don't have the rest of an AST or HIR
223232
// `PathSegment`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Non-builtin attributes do not mess with field visibility resolution (issue #67006).
2+
3+
mod internal {
4+
struct S {
5+
#[rustfmt::skip]
6+
pub(in crate::internal) field: u8 // OK
7+
}
8+
9+
struct Z(
10+
#[rustfmt::skip]
11+
pub(in crate::internal) u8 // OK
12+
);
13+
}
14+
15+
struct S {
16+
#[rustfmt::skip]
17+
pub(in nonexistent) field: u8 //~ ERROR failed to resolve
18+
}
19+
20+
struct Z(
21+
#[rustfmt::skip]
22+
pub(in nonexistent) u8 //~ ERROR failed to resolve
23+
);
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
2+
--> $DIR/field-attributes-vis-unresolved.rs:17:12
3+
|
4+
LL | pub(in nonexistent) field: u8
5+
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
6+
7+
error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
8+
--> $DIR/field-attributes-vis-unresolved.rs:22:12
9+
|
10+
LL | pub(in nonexistent) u8
11+
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)