Skip to content

Commit

Permalink
Auto merge of #100346 - matthiaskrgr:rollup-6rljn4p, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 14 pull requests

Successful merges:

 - #98775 (rustdoc: improve scroll locking in the rustdoc mobile sidebars)
 - #99479 (rustdoc-json: Remove doc FIXME for Import::id and explain)
 - #100040 (Error on broken pipe but do not backtrace or ICE)
 - #100072 (linker-plugin-lto.md: Correct the name of example c file)
 - #100098 (Some "this expression has a field"-related fixes)
 - #100226 (Do not manually craft a span pointing inside a multibyte character.)
 - #100240 (Fail gracefully when const pattern is not structural match.)
 - #100256 (Add some high-level docs to `FnCtxt` and `ItemCtxt`)
 - #100261 (Set tainted errors bit before emitting coerce suggestions.)
 - #100275 (also update anyhow in codegen_cranelift)
 - #100281 (Remove more Clean trait implementations)
 - #100314 (Mention `unit-test` in MIR opt test README)
 - #100319 (Remove more Clean trait implementations)
 - #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
  • Loading branch information
bors committed Aug 10, 2022
2 parents 34a6cae + 752b9a8 commit 0459d2f
Show file tree
Hide file tree
Showing 38 changed files with 798 additions and 311 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_cranelift/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ dependencies = [

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

[[package]]
name = "ar"
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,17 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
LazyLock::new(|| {
let hook = panic::take_hook();
panic::set_hook(Box::new(|info| {
// If the error was caused by a broken pipe then this is not a bug.
// Write the error and return immediately. See #98700.
#[cfg(windows)]
if let Some(msg) = info.payload().downcast_ref::<String>() {
if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
{
early_error_no_abort(ErrorOutputType::default(), &msg);
return;
}
};

// Invoke the default handler, which prints the actual panic message and optionally a backtrace
(*DEFAULT_HOOK)(info);

Expand Down
88 changes: 42 additions & 46 deletions compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, DUMMY_SP};
use rustc_span::{BytePos, Span};

declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as
Expand Down Expand Up @@ -504,23 +504,23 @@ trait UnusedDelimLint {
ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
let start = block.stmts[0].span;
let end = block.stmts[block.stmts.len() - 1].span;
if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
(
value.span.with_hi(value.span.lo() + BytePos(1)),
value.span.with_lo(value.span.hi() - BytePos(1)),
)
if let Some(start) = start.find_ancestor_inside(value.span)
&& let Some(end) = end.find_ancestor_inside(value.span)
{
Some((
value.span.with_hi(start.lo()),
value.span.with_lo(end.hi()),
))
} else {
(value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
None
}
}
ast::ExprKind::Paren(ref expr) => {
if value.span.from_expansion() || expr.span.from_expansion() {
(
value.span.with_hi(value.span.lo() + BytePos(1)),
value.span.with_lo(value.span.hi() - BytePos(1)),
)
let expr_span = expr.span.find_ancestor_inside(value.span);
if let Some(expr_span) = expr_span {
Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
} else {
(value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
None
}
}
_ => return,
Expand All @@ -529,36 +529,38 @@ trait UnusedDelimLint {
left_pos.map_or(false, |s| s >= value.span.lo()),
right_pos.map_or(false, |s| s <= value.span.hi()),
);
self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
}

fn emit_unused_delims(
&self,
cx: &EarlyContext<'_>,
spans: (Span, Span),
value_span: Span,
spans: Option<(Span, Span)>,
msg: &str,
keep_space: (bool, bool),
) {
// FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
// properly.
if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
return;
}

cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
let replacement = vec![
(spans.0, if keep_space.0 { " ".into() } else { "".into() }),
(spans.1, if keep_space.1 { " ".into() } else { "".into() }),
];
lint.build(fluent::lint::unused_delim)
.set_arg("delim", Self::DELIM_STR)
.set_arg("item", msg)
.multipart_suggestion(
let primary_span = if let Some((lo, hi)) = spans {
MultiSpan::from(vec![lo, hi])
} else {
MultiSpan::from(value_span)
};
cx.struct_span_lint(self.lint(), primary_span, |lint| {
let mut db = lint.build(fluent::lint::unused_delim);
db.set_arg("delim", Self::DELIM_STR);
db.set_arg("item", msg);
if let Some((lo, hi)) = spans {
let replacement = vec![
(lo, if keep_space.0 { " ".into() } else { "".into() }),
(hi, if keep_space.1 { " ".into() } else { "".into() }),
];
db.multipart_suggestion(
fluent::lint::suggestion,
replacement,
Applicability::MachineApplicable,
)
.emit();
);
}
db.emit();
});
}

Expand Down Expand Up @@ -766,15 +768,12 @@ impl UnusedParens {
// Otherwise proceed with linting.
_ => {}
}
let spans = if value.span.from_expansion() || inner.span.from_expansion() {
(
value.span.with_hi(value.span.lo() + BytePos(1)),
value.span.with_lo(value.span.hi() - BytePos(1)),
)
let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
} else {
(value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
None
};
self.emit_unused_delims(cx, spans, "pattern", (false, false));
self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
}
}
}
Expand Down Expand Up @@ -879,15 +878,12 @@ impl EarlyLintPass for UnusedParens {
);
}
_ => {
let spans = if ty.span.from_expansion() || r.span.from_expansion() {
(
ty.span.with_hi(ty.span.lo() + BytePos(1)),
ty.span.with_lo(ty.span.hi() - BytePos(1)),
)
let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
} else {
(ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
None
};
self.emit_unused_delims(cx, spans, "type", (false, false));
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// once indirect_structural_match is a full fledged error, this
// level of indirection can be eliminated

let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
let inlined_const_as_pat =
self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
span: self.span,
ty: cv.ty(),
kind: Box::new(PatKind::Constant { value: cv }),
});

if self.include_lint_checks && !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_typeck/src/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
Err(coercion_error) => {
// Mark that we've failed to coerce the types here to suppress
// any superfluous errors we might encounter while trying to
// emit or provide suggestions on how to fix the initial error.
fcx.set_tainted_by_errors();
let (expected, found) = if label_expression_as_expected {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
Expand Down
72 changes: 43 additions & 29 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2526,15 +2526,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);

// try to add a suggestion in case the field is a nested field of a field of the Adt
if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
for candidate_field in fields.iter() {
let mod_id = self.tcx.parent_module(id).to_def_id();
if let Some((fields, substs)) =
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
{
for candidate_field in fields {
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
span,
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
candidate_field,
substs,
vec![],
self.tcx.parent_module(id).to_def_id(),
mod_id,
) {
// field_path includes `field` that we're looking for, so pop it.
field_path.pop();
Expand All @@ -2558,22 +2561,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err
}

pub(crate) fn get_field_candidates(
pub(crate) fn get_field_candidates_considering_privacy(
&self,
span: Span,
base_t: Ty<'tcx>,
) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
base_ty: Ty<'tcx>,
mod_id: DefId,
) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);

for (base_t, _) in self.autoderef(span, base_t) {
for (base_t, _) in self.autoderef(span, base_ty) {
match base_t.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
let tcx = self.tcx;
let fields = &base_def.non_enum_variant().fields;
// For compile-time reasons put a limit on number of fields we search
if fields.len() > 100 {
return None;
// Some struct, e.g. some that impl `Deref`, have all private fields
// because you're expected to deref them to access the _real_ fields.
// This, for example, will help us suggest accessing a field through a `Box<T>`.
if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
continue;
}
return Some((fields, substs));
return Some((
fields
.iter()
.filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
// For compile-time reasons put a limit on number of fields we search
.take(100),
substs,
));
}
_ => {}
}
Expand All @@ -2590,7 +2604,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
candidate_field: &ty::FieldDef,
subst: SubstsRef<'tcx>,
mut field_path: Vec<Ident>,
id: DefId,
mod_id: DefId,
) -> Option<Vec<Ident>> {
debug!(
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
Expand All @@ -2602,24 +2616,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// up to a depth of three
None
} else {
// recursively search fields of `candidate_field` if it's a ty::Adt
field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
let field_ty = candidate_field.ty(self.tcx, subst);
if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
for field in nested_fields.iter() {
if field.vis.is_accessible_from(id, self.tcx) {
if matches(candidate_field, field_ty) {
return Some(field_path);
} else if let Some(field_path) = self.check_for_nested_field_satisfying(
span,
matches,
field,
subst,
field_path.clone(),
id,
) {
return Some(field_path);
}
if matches(candidate_field, field_ty) {
return Some(field_path);
} else if let Some((nested_fields, subst)) =
self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
{
// recursively search fields of `candidate_field` if it's a ty::Adt
for field in nested_fields {
if let Some(field_path) = self.check_for_nested_field_satisfying(
span,
matches,
field,
subst,
field_path.clone(),
mod_id,
) {
return Some(field_path);
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
use std::cell::{Cell, RefCell};
use std::ops::Deref;

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

Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_typeck/src/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
label_span_not_found(&mut err);
}

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

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

Expand Down Expand Up @@ -1334,10 +1338,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
) {
if let SelfSource::MethodCall(expr) = source
&& let Some((fields, substs)) = self.get_field_candidates(span, actual)
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
&& let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
{
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
for candidate_field in fields.iter() {
for candidate_field in fields {
if let Some(field_path) = self.check_for_nested_field_satisfying(
span,
&|_, field_ty| {
Expand All @@ -1353,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
candidate_field,
substs,
vec![],
self.tcx.parent_module(expr.hir_id).to_def_id(),
mod_id,
) {
let field_path_str = field_path
.iter()
Expand Down
22 changes: 21 additions & 1 deletion compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,27 @@ pub fn provide(providers: &mut Providers) {
///////////////////////////////////////////////////////////////////////////

/// Context specific to some particular item. This is what implements
/// `AstConv`. It has information about the predicates that are defined
/// [`AstConv`].
///
/// # `ItemCtxt` vs `FnCtxt`
///
/// `ItemCtxt` is primarily used to type-check item signatures and lower them
/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
/// It's also used for the bodies of items like structs where the body (the fields)
/// are just signatures.
///
/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
///
/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
/// while `FnCtxt` does do inference.
///
/// [`FnCtxt`]: crate::check::FnCtxt
/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
///
/// # Trait predicates
///
/// `ItemCtxt` has information about the predicates that are defined
/// on the trait. Unfortunately, this predicate information is
/// available in various different forms at various points in the
/// process. So we can't just store a pointer to e.g., the AST or the
Expand Down
Loading

0 comments on commit 0459d2f

Please sign in to comment.