Skip to content

Commit 0459d2f

Browse files
committed
Auto merge of rust-lang#100346 - matthiaskrgr:rollup-6rljn4p, r=matthiaskrgr
Rollup of 14 pull requests Successful merges: - rust-lang#98775 (rustdoc: improve scroll locking in the rustdoc mobile sidebars) - rust-lang#99479 (rustdoc-json: Remove doc FIXME for Import::id and explain) - rust-lang#100040 (Error on broken pipe but do not backtrace or ICE) - rust-lang#100072 (linker-plugin-lto.md: Correct the name of example c file) - rust-lang#100098 (Some "this expression has a field"-related fixes) - rust-lang#100226 (Do not manually craft a span pointing inside a multibyte character.) - rust-lang#100240 (Fail gracefully when const pattern is not structural match.) - rust-lang#100256 (Add some high-level docs to `FnCtxt` and `ItemCtxt`) - rust-lang#100261 (Set tainted errors bit before emitting coerce suggestions.) - rust-lang#100275 (also update anyhow in codegen_cranelift) - rust-lang#100281 (Remove more Clean trait implementations) - rust-lang#100314 (Mention `unit-test` in MIR opt test README) - rust-lang#100319 (Remove more Clean trait implementations) - rust-lang#100323 ([rustdoc] Don't render impl blocks with doc comment if they only contain private items by default) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 34a6cae + 752b9a8 commit 0459d2f

38 files changed

+798
-311
lines changed

compiler/rustc_codegen_cranelift/Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ dependencies = [
1515

1616
[[package]]
1717
name = "anyhow"
18-
version = "1.0.56"
18+
version = "1.0.60"
1919
source = "registry+https://github.com/rust-lang/crates.io-index"
20-
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
20+
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
2121

2222
[[package]]
2323
name = "ar"

compiler/rustc_driver/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,17 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
11481148
LazyLock::new(|| {
11491149
let hook = panic::take_hook();
11501150
panic::set_hook(Box::new(|info| {
1151+
// If the error was caused by a broken pipe then this is not a bug.
1152+
// Write the error and return immediately. See #98700.
1153+
#[cfg(windows)]
1154+
if let Some(msg) = info.payload().downcast_ref::<String>() {
1155+
if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
1156+
{
1157+
early_error_no_abort(ErrorOutputType::default(), &msg);
1158+
return;
1159+
}
1160+
};
1161+
11511162
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
11521163
(*DEFAULT_HOOK)(info);
11531164

compiler/rustc_lint/src/unused.rs

+42-46
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment;
1111
use rustc_middle::ty::{self, Ty};
1212
use rustc_span::symbol::Symbol;
1313
use rustc_span::symbol::{kw, sym};
14-
use rustc_span::{BytePos, Span, DUMMY_SP};
14+
use rustc_span::{BytePos, Span};
1515

1616
declare_lint! {
1717
/// The `unused_must_use` lint detects unused result of a type flagged as
@@ -504,23 +504,23 @@ trait UnusedDelimLint {
504504
ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
505505
let start = block.stmts[0].span;
506506
let end = block.stmts[block.stmts.len() - 1].span;
507-
if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
508-
(
509-
value.span.with_hi(value.span.lo() + BytePos(1)),
510-
value.span.with_lo(value.span.hi() - BytePos(1)),
511-
)
507+
if let Some(start) = start.find_ancestor_inside(value.span)
508+
&& let Some(end) = end.find_ancestor_inside(value.span)
509+
{
510+
Some((
511+
value.span.with_hi(start.lo()),
512+
value.span.with_lo(end.hi()),
513+
))
512514
} else {
513-
(value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
515+
None
514516
}
515517
}
516518
ast::ExprKind::Paren(ref expr) => {
517-
if value.span.from_expansion() || expr.span.from_expansion() {
518-
(
519-
value.span.with_hi(value.span.lo() + BytePos(1)),
520-
value.span.with_lo(value.span.hi() - BytePos(1)),
521-
)
519+
let expr_span = expr.span.find_ancestor_inside(value.span);
520+
if let Some(expr_span) = expr_span {
521+
Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
522522
} else {
523-
(value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
523+
None
524524
}
525525
}
526526
_ => return,
@@ -529,36 +529,38 @@ trait UnusedDelimLint {
529529
left_pos.map_or(false, |s| s >= value.span.lo()),
530530
right_pos.map_or(false, |s| s <= value.span.hi()),
531531
);
532-
self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
532+
self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
533533
}
534534

535535
fn emit_unused_delims(
536536
&self,
537537
cx: &EarlyContext<'_>,
538-
spans: (Span, Span),
538+
value_span: Span,
539+
spans: Option<(Span, Span)>,
539540
msg: &str,
540541
keep_space: (bool, bool),
541542
) {
542-
// FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
543-
// properly.
544-
if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
545-
return;
546-
}
547-
548-
cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
549-
let replacement = vec![
550-
(spans.0, if keep_space.0 { " ".into() } else { "".into() }),
551-
(spans.1, if keep_space.1 { " ".into() } else { "".into() }),
552-
];
553-
lint.build(fluent::lint::unused_delim)
554-
.set_arg("delim", Self::DELIM_STR)
555-
.set_arg("item", msg)
556-
.multipart_suggestion(
543+
let primary_span = if let Some((lo, hi)) = spans {
544+
MultiSpan::from(vec![lo, hi])
545+
} else {
546+
MultiSpan::from(value_span)
547+
};
548+
cx.struct_span_lint(self.lint(), primary_span, |lint| {
549+
let mut db = lint.build(fluent::lint::unused_delim);
550+
db.set_arg("delim", Self::DELIM_STR);
551+
db.set_arg("item", msg);
552+
if let Some((lo, hi)) = spans {
553+
let replacement = vec![
554+
(lo, if keep_space.0 { " ".into() } else { "".into() }),
555+
(hi, if keep_space.1 { " ".into() } else { "".into() }),
556+
];
557+
db.multipart_suggestion(
557558
fluent::lint::suggestion,
558559
replacement,
559560
Applicability::MachineApplicable,
560-
)
561-
.emit();
561+
);
562+
}
563+
db.emit();
562564
});
563565
}
564566

@@ -766,15 +768,12 @@ impl UnusedParens {
766768
// Otherwise proceed with linting.
767769
_ => {}
768770
}
769-
let spans = if value.span.from_expansion() || inner.span.from_expansion() {
770-
(
771-
value.span.with_hi(value.span.lo() + BytePos(1)),
772-
value.span.with_lo(value.span.hi() - BytePos(1)),
773-
)
771+
let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
772+
Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
774773
} else {
775-
(value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
774+
None
776775
};
777-
self.emit_unused_delims(cx, spans, "pattern", (false, false));
776+
self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
778777
}
779778
}
780779
}
@@ -879,15 +878,12 @@ impl EarlyLintPass for UnusedParens {
879878
);
880879
}
881880
_ => {
882-
let spans = if ty.span.from_expansion() || r.span.from_expansion() {
883-
(
884-
ty.span.with_hi(ty.span.lo() + BytePos(1)),
885-
ty.span.with_lo(ty.span.hi() - BytePos(1)),
886-
)
881+
let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
882+
Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
887883
} else {
888-
(ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
884+
None
889885
};
890-
self.emit_unused_delims(cx, spans, "type", (false, false));
886+
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
891887
}
892888
}
893889
}

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
168168
// once indirect_structural_match is a full fledged error, this
169169
// level of indirection can be eliminated
170170

171-
let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
171+
let inlined_const_as_pat =
172+
self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
173+
span: self.span,
174+
ty: cv.ty(),
175+
kind: Box::new(PatKind::Constant { value: cv }),
176+
});
172177

173178
if self.include_lint_checks && !self.saw_const_match_error.get() {
174179
// If we were able to successfully convert the const to some pat,

compiler/rustc_typeck/src/check/coercion.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14791479
}
14801480
}
14811481
Err(coercion_error) => {
1482+
// Mark that we've failed to coerce the types here to suppress
1483+
// any superfluous errors we might encounter while trying to
1484+
// emit or provide suggestions on how to fix the initial error.
1485+
fcx.set_tainted_by_errors();
14821486
let (expected, found) = if label_expression_as_expected {
14831487
// In the case where this is a "forced unit", like
14841488
// `break`, we want to call the `()` "expected"

compiler/rustc_typeck/src/check/expr.rs

+43-29
Original file line numberDiff line numberDiff line change
@@ -2526,15 +2526,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25262526
);
25272527

25282528
// try to add a suggestion in case the field is a nested field of a field of the Adt
2529-
if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
2530-
for candidate_field in fields.iter() {
2529+
let mod_id = self.tcx.parent_module(id).to_def_id();
2530+
if let Some((fields, substs)) =
2531+
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
2532+
{
2533+
for candidate_field in fields {
25312534
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
25322535
span,
25332536
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
25342537
candidate_field,
25352538
substs,
25362539
vec![],
2537-
self.tcx.parent_module(id).to_def_id(),
2540+
mod_id,
25382541
) {
25392542
// field_path includes `field` that we're looking for, so pop it.
25402543
field_path.pop();
@@ -2558,22 +2561,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25582561
err
25592562
}
25602563

2561-
pub(crate) fn get_field_candidates(
2564+
pub(crate) fn get_field_candidates_considering_privacy(
25622565
&self,
25632566
span: Span,
2564-
base_t: Ty<'tcx>,
2565-
) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
2566-
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
2567+
base_ty: Ty<'tcx>,
2568+
mod_id: DefId,
2569+
) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
2570+
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
25672571

2568-
for (base_t, _) in self.autoderef(span, base_t) {
2572+
for (base_t, _) in self.autoderef(span, base_ty) {
25692573
match base_t.kind() {
25702574
ty::Adt(base_def, substs) if !base_def.is_enum() => {
2575+
let tcx = self.tcx;
25712576
let fields = &base_def.non_enum_variant().fields;
2572-
// For compile-time reasons put a limit on number of fields we search
2573-
if fields.len() > 100 {
2574-
return None;
2577+
// Some struct, e.g. some that impl `Deref`, have all private fields
2578+
// because you're expected to deref them to access the _real_ fields.
2579+
// This, for example, will help us suggest accessing a field through a `Box<T>`.
2580+
if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
2581+
continue;
25752582
}
2576-
return Some((fields, substs));
2583+
return Some((
2584+
fields
2585+
.iter()
2586+
.filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
2587+
// For compile-time reasons put a limit on number of fields we search
2588+
.take(100),
2589+
substs,
2590+
));
25772591
}
25782592
_ => {}
25792593
}
@@ -2590,7 +2604,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25902604
candidate_field: &ty::FieldDef,
25912605
subst: SubstsRef<'tcx>,
25922606
mut field_path: Vec<Ident>,
2593-
id: DefId,
2607+
mod_id: DefId,
25942608
) -> Option<Vec<Ident>> {
25952609
debug!(
25962610
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
@@ -2602,24 +2616,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26022616
// up to a depth of three
26032617
None
26042618
} else {
2605-
// recursively search fields of `candidate_field` if it's a ty::Adt
26062619
field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
26072620
let field_ty = candidate_field.ty(self.tcx, subst);
2608-
if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
2609-
for field in nested_fields.iter() {
2610-
if field.vis.is_accessible_from(id, self.tcx) {
2611-
if matches(candidate_field, field_ty) {
2612-
return Some(field_path);
2613-
} else if let Some(field_path) = self.check_for_nested_field_satisfying(
2614-
span,
2615-
matches,
2616-
field,
2617-
subst,
2618-
field_path.clone(),
2619-
id,
2620-
) {
2621-
return Some(field_path);
2622-
}
2621+
if matches(candidate_field, field_ty) {
2622+
return Some(field_path);
2623+
} else if let Some((nested_fields, subst)) =
2624+
self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
2625+
{
2626+
// recursively search fields of `candidate_field` if it's a ty::Adt
2627+
for field in nested_fields {
2628+
if let Some(field_path) = self.check_for_nested_field_satisfying(
2629+
span,
2630+
matches,
2631+
field,
2632+
subst,
2633+
field_path.clone(),
2634+
mod_id,
2635+
) {
2636+
return Some(field_path);
26232637
}
26242638
}
26252639
}

compiler/rustc_typeck/src/check/fn_ctxt/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
2626
use std::cell::{Cell, RefCell};
2727
use std::ops::Deref;
2828

29+
/// The `FnCtxt` stores type-checking context needed to type-check bodies of
30+
/// functions, closures, and `const`s, including performing type inference
31+
/// with [`InferCtxt`].
32+
///
33+
/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
34+
/// and thus does not perform type inference.
35+
///
36+
/// See [`ItemCtxt`]'s docs for more.
37+
///
38+
/// [`ItemCtxt`]: crate::collect::ItemCtxt
39+
/// [`InferCtxt`]: infer::InferCtxt
2940
pub struct FnCtxt<'a, 'tcx> {
3041
pub(super) body_id: hir::HirId,
3142

compiler/rustc_typeck/src/check/method/suggest.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10001000
label_span_not_found(&mut err);
10011001
}
10021002

1003-
self.check_for_field_method(&mut err, source, span, actual, item_name);
1003+
// Don't suggest (for example) `expr.field.method()` if `expr.method()`
1004+
// doesn't exist due to unsatisfied predicates.
1005+
if unsatisfied_predicates.is_empty() {
1006+
self.check_for_field_method(&mut err, source, span, actual, item_name);
1007+
}
10041008

10051009
self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
10061010

@@ -1334,10 +1338,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13341338
item_name: Ident,
13351339
) {
13361340
if let SelfSource::MethodCall(expr) = source
1337-
&& let Some((fields, substs)) = self.get_field_candidates(span, actual)
1341+
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
1342+
&& let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
13381343
{
13391344
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
1340-
for candidate_field in fields.iter() {
1345+
for candidate_field in fields {
13411346
if let Some(field_path) = self.check_for_nested_field_satisfying(
13421347
span,
13431348
&|_, field_ty| {
@@ -1353,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13531358
candidate_field,
13541359
substs,
13551360
vec![],
1356-
self.tcx.parent_module(expr.hir_id).to_def_id(),
1361+
mod_id,
13571362
) {
13581363
let field_path_str = field_path
13591364
.iter()

compiler/rustc_typeck/src/collect.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,27 @@ pub fn provide(providers: &mut Providers) {
9494
///////////////////////////////////////////////////////////////////////////
9595

9696
/// Context specific to some particular item. This is what implements
97-
/// `AstConv`. It has information about the predicates that are defined
97+
/// [`AstConv`].
98+
///
99+
/// # `ItemCtxt` vs `FnCtxt`
100+
///
101+
/// `ItemCtxt` is primarily used to type-check item signatures and lower them
102+
/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
103+
/// It's also used for the bodies of items like structs where the body (the fields)
104+
/// are just signatures.
105+
///
106+
/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
107+
/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
108+
///
109+
/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
110+
/// while `FnCtxt` does do inference.
111+
///
112+
/// [`FnCtxt`]: crate::check::FnCtxt
113+
/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
114+
///
115+
/// # Trait predicates
116+
///
117+
/// `ItemCtxt` has information about the predicates that are defined
98118
/// on the trait. Unfortunately, this predicate information is
99119
/// available in various different forms at various points in the
100120
/// process. So we can't just store a pointer to e.g., the AST or the

0 commit comments

Comments
 (0)