diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 3189fcf7ff9bf..a7c6f8c5d8c26 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -756,6 +756,11 @@ impl Token { ) } + /// Returns `true` if the token is the integer literal. + pub fn is_integer_lit(&self) -> bool { + matches!(self.kind, Literal(Lit { kind: LitKind::Integer, .. })) + } + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 7d6e15839c508..6e44f44dc18b0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -42,6 +42,7 @@ use rustc_target::abi::FieldIdx; use smallvec::SmallVec; use std::cell::RefCell; use std::collections::BTreeMap; +use std::marker::PhantomData; use std::ops::Deref; use std::rc::Rc; @@ -100,7 +101,7 @@ use renumber::RegionCtxt; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } /// Associate some local constants with the `'tcx` lifetime -struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>); +struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>); impl<'tcx> TyCtxtConsts<'tcx> { const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref]; } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ac13d61229e05..be895417bbebc 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -44,7 +44,7 @@ use tempfile::Builder as TempFileBuilder; use itertools::Itertools; use std::cell::OnceCell; use std::collections::BTreeSet; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::{read, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::ops::Deref; @@ -2527,7 +2527,7 @@ fn add_native_libs_from_crate( NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { - cmd.arg(name); + cmd.linker_arg(OsStr::new(name), verbatim); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4dd688c22345d..f65afd99e39c7 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -196,6 +196,14 @@ pub trait Linker { fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} fn reset_per_library_state(&mut self) {} + fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) { + self.linker_args(&[arg], verbatim); + } + fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) { + args.into_iter().for_each(|a| { + self.cmd().arg(a); + }); + } } impl dyn Linker + '_ { @@ -223,38 +231,12 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - /// Passes an argument directly to the linker. - /// - /// When the linker is not ld-like such as when using a compiler as a linker, the argument is - /// prepended by `-Wl,`. - fn linker_arg(&mut self, arg: impl AsRef) -> &mut Self { - self.linker_args(&[arg]); - self + fn linker_arg(&mut self, arg: impl AsRef) { + Linker::linker_arg(self, arg.as_ref(), false); } - - /// Passes a series of arguments directly to the linker. - /// - /// When the linker is ld-like, the arguments are simply appended to the command. When the - /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by - /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a - /// single argument is appended to the command to ensure that the order of the arguments is - /// preserved by the compiler. - fn linker_args(&mut self, args: &[impl AsRef]) -> &mut Self { - if self.is_ld { - args.into_iter().for_each(|a| { - self.cmd.arg(a); - }); - } else { - if !args.is_empty() { - let mut s = OsString::from("-Wl"); - for a in args { - s.push(","); - s.push(a); - } - self.cmd.arg(s); - } - } - self + fn linker_args(&mut self, args: &[impl AsRef]) { + let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); + Linker::linker_args(self, &args_vec, false); } fn takes_hints(&self) -> bool { @@ -361,6 +343,30 @@ impl<'a> GccLinker<'a> { } impl<'a> Linker for GccLinker<'a> { + /// Passes a series of arguments directly to the linker. + /// + /// When the linker is ld-like, the arguments are simply appended to the command. When the + /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by + /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a + /// single argument is appended to the command to ensure that the order of the arguments is + /// preserved by the compiler. + fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) { + if self.is_ld || verbatim { + args.into_iter().for_each(|a| { + self.cmd.arg(a); + }); + } else { + if !args.is_empty() { + let mut s = OsString::from("-Wl"); + for a in args { + s.push(","); + s.push(a); + } + self.cmd.arg(s); + } + } + } + fn cmd(&mut self) -> &mut Command { &mut self.cmd } @@ -531,7 +537,7 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("-force_load"); self.linker_arg(&lib); } else { - self.linker_arg("--whole-archive").cmd.arg(lib); + self.linker_args(&[OsString::from("--whole-archive"), lib.into()]); self.linker_arg("--no-whole-archive"); } } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index a29d9c95e5ea0..e7cbbc713353f 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -139,7 +139,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(arm.body), arm_ty, - |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm), + |err| { + self.explain_never_type_coerced_to_unit(err, arm, arm_ty, prior_arm, expr); + }, false, ); @@ -177,6 +179,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.complete(self) } + fn explain_never_type_coerced_to_unit( + &self, + err: &mut Diagnostic, + arm: &hir::Arm<'tcx>, + arm_ty: Ty<'tcx>, + prior_arm: Option<(Option, Ty<'tcx>, Span)>, + expr: &hir::Expr<'tcx>, + ) { + if let hir::ExprKind::Block(block, _) = arm.body.kind + && let Some(expr) = block.expr + && let arm_tail_ty = self.node_ty(expr.hir_id) + && arm_tail_ty.is_never() + && !arm_ty.is_never() + { + err.span_label( + expr.span, + format!( + "this expression is of type `!`, but it is coerced to `{arm_ty}` due to its \ + surrounding expression", + ), + ); + self.suggest_mismatched_types_on_tail( + err, + expr, + arm_ty, + prior_arm.map_or(arm_tail_ty, |(_, ty, _)| ty), + expr.hir_id, + ); + } + self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm) + } + fn suggest_removing_semicolon_for_coerce( &self, diag: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ae2a4a9504ce3..587038d57bdfd 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1715,6 +1715,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // label pointing out the cause for the type coercion will be wrong // as prior return coercions would not be relevant (#57664). let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) { + fcx.suggest_missing_semicolon(&mut err, expr, expected, false); let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id); if let (Some(cond_expr), true, false) = ( diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f16269795e985..7f15478349e79 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -663,8 +663,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce_forced_unit( self, &cause, - |err| { - self.suggest_mismatched_types_on_tail(err, expr, ty, e_ty, target_id); + |mut err| { + self.suggest_missing_semicolon(&mut err, expr, e_ty, false); + self.suggest_mismatched_types_on_tail( + &mut err, expr, ty, e_ty, target_id, + ); let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = ty_kind_suggestion(ty) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 6660bea03d8b7..c74ef8f271338 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -72,7 +72,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, false); let mut pointing_at_return_type = false; if let hir::ExprKind::Break(..) = expr.kind { // `break` type mismatches provide better context for tail `loop` expressions. diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index b3ab01a740a95..c9c7ffdd9371f 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -126,11 +126,8 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( .deadlock_handler(|| { // On deadlock, creates a new thread and forwards information in thread // locals to it. The new thread runs the deadlock handler. - let query_map = FromDyn::from(tls::with(|tcx| { - QueryCtxt::new(tcx) - .try_collect_active_jobs() - .expect("active jobs shouldn't be locked in deadlock handler") - })); + let query_map = + FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs())); let registry = rayon_core::Registry::current(); thread::spawn(move || deadlock(query_map.into_inner(), ®istry)); }); diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 85447887cb0ec..c63b24b194fc2 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -385,7 +385,7 @@ pub(crate) fn provide(providers: &mut Providers) { enum Context { Safe, /// in an `unsafe fn` - UnsafeFn(HirId), + UnsafeFn, /// in a *used* `unsafe` block /// (i.e. a block without unused-unsafe warning) UnsafeBlock(HirId), @@ -407,7 +407,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { }; let unused_unsafe = match (self.context, used) { (_, false) => UnusedUnsafe::Unused, - (Context::Safe, true) | (Context::UnsafeFn(_), true) => { + (Context::Safe, true) | (Context::UnsafeFn, true) => { let previous_context = self.context; self.context = Context::UnsafeBlock(block.hir_id); intravisit::walk_block(self, block); @@ -454,7 +454,7 @@ fn check_unused_unsafe( let body = tcx.hir().body(body_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); let context = match tcx.hir().fn_sig_by_hir_id(hir_id) { - Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn(hir_id), + Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn, _ => Context::Safe, }; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 5316dde609605..620ba4a3cb363 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -567,20 +567,37 @@ impl<'a> Parser<'a> { snapshot.recover_diff_marker(); } if self.token == token::Colon { - // if next token is following a colon, it's likely a path - // and we can suggest a path separator - self.bump(); - if self.token.span.lo() == self.prev_token.span.hi() { + // if a previous and next token of the current one is + // integer literal (e.g. `1:42`), it's likely a range + // expression for Pythonistas and we can suggest so. + if self.prev_token.is_integer_lit() + && self.may_recover() + && self.look_ahead(1, |token| token.is_integer_lit()) + { + // FIXME(hkmatsumoto): Might be better to trigger + // this only when parsing an index expression. err.span_suggestion_verbose( - self.prev_token.span, - "maybe write a path separator here", - "::", + self.token.span, + "you might have meant a range expression", + "..", Applicability::MaybeIncorrect, ); - } - if self.sess.unstable_features.is_nightly_build() { - // FIXME(Nilstrieb): Remove this again after a few months. - err.note("type ascription syntax has been removed, see issue #101728 "); + } else { + // if next token is following a colon, it's likely a path + // and we can suggest a path separator + self.bump(); + if self.token.span.lo() == self.prev_token.span.hi() { + err.span_suggestion_verbose( + self.prev_token.span, + "maybe write a path separator here", + "::", + Applicability::MaybeIncorrect, + ); + } + if self.sess.unstable_features.is_nightly_build() { + // FIXME(Nilstrieb): Remove this again after a few months. + err.note("type ascription syntax has been removed, see issue #101728 "); + } } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9faf63f00e27e..acd3d71e63683 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -80,14 +80,14 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } - fn try_collect_active_jobs(self) -> Option { + fn collect_active_jobs(self) -> QueryMap { let mut jobs = QueryMap::default(); for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { collect(self.tcx, &mut jobs); } - Some(jobs) + jobs } // Interactions with on_disk_cache @@ -155,11 +155,11 @@ impl QueryContext for QueryCtxt<'_> { fn depth_limit_error(self, job: QueryJobId) { let mut span = None; let mut layout_of_depth = None; - if let Some(map) = self.try_collect_active_jobs() { - if let Some((info, depth)) = job.try_find_layout_root(map, dep_kinds::layout_of) { - span = Some(info.job.span); - layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth }); - } + if let Some((info, depth)) = + job.try_find_layout_root(self.collect_active_jobs(), dep_kinds::layout_of) + { + span = Some(info.job.span); + layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth }); } let suggested_limit = match self.recursion_limit() { diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index b38d71733b591..2a55ec72c5f70 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -620,13 +620,13 @@ pub fn print_query_stack( // state if it was responsible for triggering the panic. let mut count_printed = 0; let mut count_total = 0; - let query_map = qcx.try_collect_active_jobs(); + let query_map = qcx.collect_active_jobs(); if let Some(ref mut file) = file { let _ = writeln!(file, "\n\nquery stack during panic:"); } while let Some(query) = current_query { - let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else { + let Some(query_info) = query_map.get(&query) else { break; }; if Some(count_printed) < num_frames || num_frames.is_none() { diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 05dee9f12dbdb..96a0c7a033aa1 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn try_collect_active_jobs(self) -> Option; + fn collect_active_jobs(self) -> QueryMap; /// Load side effects associated to the node in the previous session. fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index ecbc7dc6b8f4e..2f9f094dae2e0 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -242,11 +242,8 @@ where Q: QueryConfig, Qcx: QueryContext, { - let error = try_execute.find_cycle_in_stack( - qcx.try_collect_active_jobs().unwrap(), - &qcx.current_query_job(), - span, - ); + let error = + try_execute.find_cycle_in_stack(qcx.collect_active_jobs(), &qcx.current_query_job(), span); (mk_cycle(query, qcx, error), None) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b1ee7f438d296..c52450e11d642 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -223,7 +223,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { // ``` // // In that case, the impl-trait is lowered as an additional generic parameter. - self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { + self.with_impl_trait(ImplTraitContext::Universal, |this| { visit::walk_generic_param(this, param) }); } @@ -310,9 +310,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { if p.is_placeholder { self.visit_macro_invoc(p.id) } else { - self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { - visit::walk_param(this, p) - }) + self.with_impl_trait(ImplTraitContext::Universal, |this| visit::walk_param(this, p)) } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 590bbfc3df1a1..d15e245868325 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -172,7 +172,7 @@ impl<'a> ParentScope<'a> { #[derive(Copy, Debug, Clone)] enum ImplTraitContext { Existential, - Universal(LocalDefId), + Universal, } #[derive(Debug)] diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 62a26bc089ad8..e9b835f90db24 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -578,13 +578,13 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { } mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt { discr: discr.stable(tables), - targets: targets - .iter() - .map(|(value, target)| stable_mir::mir::SwitchTarget { - value, - target: target.as_usize(), - }) - .collect(), + targets: { + let (value_vec, mut target_vec): (Vec<_>, Vec<_>) = + targets.iter().map(|(value, target)| (value, target.as_usize())).unzip(); + // We need to push otherwise as last element to ensure it's same as in MIR. + target_vec.push(targets.otherwise().as_usize()); + stable_mir::mir::SwitchTargets { value: value_vec, targets: target_vec } + }, otherwise: targets.otherwise().as_usize(), }, mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 96a118e590f39..14cb1d6d362e2 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -188,7 +188,11 @@ fn find_best_match_for_name_impl( return Some(*c); } - let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); + // `fn edit_distance()` use `chars()` to calculate edit distance, so we must + // also use `chars()` (and not `str::len()`) to calculate length here. + let lookup_len = lookup.chars().count(); + + let mut dist = dist.unwrap_or_else(|| cmp::max(lookup_len, 3) / 3); let mut best = None; // store the candidates with the same distance, only for `use_substring_score` current. let mut next_candidates = vec![]; diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 1f75dfb69cfd9..2099c485c6f8f 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -16,7 +16,7 @@ //! //! The goal is to eventually be published on //! [crates.io](https://crates.io). - +#![feature(type_alias_impl_trait)] #[macro_use] extern crate scoped_tls; @@ -184,7 +184,7 @@ impl std::fmt::Display for Opaque { impl std::fmt::Debug for Opaque { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) + write!(f, "{}", self.0) } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 8d237fc9f1d95..02a2868767659 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,10 +1,9 @@ -use crate::mir::pretty::{function_body, pretty_statement}; +use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator}; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, }; use crate::{Error, Opaque, Span, Symbol}; -use std::io; - +use std::{io, slice}; /// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { @@ -83,6 +82,8 @@ impl Body { Ok(()) }) .collect::>(); + pretty_terminator(&block.terminator.kind, w)?; + writeln!(w, "").unwrap(); writeln!(w, " }}").unwrap(); Ok(()) }) @@ -100,7 +101,7 @@ pub struct LocalDecl { pub mutability: Mutability, } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct BasicBlock { pub statements: Vec, pub terminator: Terminator, @@ -112,6 +113,14 @@ pub struct Terminator { pub span: Span, } +impl Terminator { + pub fn successors(&self) -> Successors<'_> { + self.kind.successors() + } +} + +pub type Successors<'a> = impl Iterator + 'a; + #[derive(Clone, Debug, Eq, PartialEq)] pub enum TerminatorKind { Goto { @@ -119,7 +128,7 @@ pub enum TerminatorKind { }, SwitchInt { discr: Operand, - targets: Vec, + targets: SwitchTargets, otherwise: usize, }, Resume, @@ -156,6 +165,58 @@ pub enum TerminatorKind { }, } +impl TerminatorKind { + pub fn successors(&self) -> Successors<'_> { + use self::TerminatorKind::*; + match *self { + Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { + Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) + } + Goto { target: t } + | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } + | Call { target: Some(t), unwind: _, .. } + | Drop { target: t, unwind: _, .. } + | Assert { target: t, unwind: _, .. } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } + | InlineAsm { destination: Some(t), unwind: _, .. } => { + Some(t).into_iter().chain((&[]).into_iter().copied()) + } + + CoroutineDrop + | Return + | Resume + | Abort + | Unreachable + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => { + None.into_iter().chain((&[]).into_iter().copied()) + } + SwitchInt { ref targets, .. } => { + None.into_iter().chain(targets.targets.iter().copied()) + } + } + } + + pub fn unwind(&self) -> Option<&UnwindAction> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::CoroutineDrop + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::SwitchInt { .. } => None, + TerminatorKind::Call { ref unwind, .. } + | TerminatorKind::Assert { ref unwind, .. } + | TerminatorKind::Drop { ref unwind, .. } + | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct InlineAsmOperand { pub in_value: Option, @@ -602,9 +663,9 @@ pub struct Constant { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct SwitchTarget { - pub value: u128, - pub target: usize, +pub struct SwitchTargets { + pub value: Vec, + pub targets: Vec, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index e7bca295b5a04..759c3b148dfef 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,7 +1,11 @@ use crate::crate_def::CrateDef; -use crate::mir::{Operand, Rvalue, StatementKind}; +use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction}; use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy}; use crate::{with, Body, CrateItem, Mutability}; +use std::io::Write; +use std::{io, iter}; + +use super::{AssertMessage, BinOp, TerminatorKind}; pub fn function_name(item: CrateItem) -> String { let mut pretty_name = String::new(); @@ -70,6 +74,209 @@ pub fn pretty_statement(statement: &StatementKind) -> String { pretty } +pub fn pretty_terminator(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> { + write!(w, "{}", pretty_terminator_head(terminator))?; + let successor_count = terminator.successors().count(); + let labels = pretty_successor_labels(terminator); + + let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); + let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> { + write!(fmt, "unwind ")?; + match terminator.unwind() { + None | Some(UnwindAction::Cleanup(_)) => unreachable!(), + Some(UnwindAction::Continue) => write!(fmt, "continue"), + Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"), + Some(UnwindAction::Terminate) => write!(fmt, "terminate"), + } + }; + + match (successor_count, show_unwind) { + (0, false) => Ok(()), + (0, true) => { + write!(w, " -> ")?; + fmt_unwind(w)?; + Ok(()) + } + (1, false) => { + write!(w, " -> {:?}", terminator.successors().next().unwrap())?; + Ok(()) + } + _ => { + write!(w, " -> [")?; + for (i, target) in terminator.successors().enumerate() { + if i > 0 { + write!(w, ", ")?; + } + write!(w, "{}: bb{:?}", labels[i], target)?; + } + if show_unwind { + write!(w, ", ")?; + fmt_unwind(w)?; + } + write!(w, "]") + } + }?; + + Ok(()) +} + +pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String { + use self::TerminatorKind::*; + let mut pretty = String::new(); + match terminator { + Goto { .. } => format!(" goto"), + SwitchInt { discr, .. } => { + format!(" switchInt(_{})", pretty_operand(discr)) + } + Resume => format!(" resume"), + Abort => format!(" abort"), + Return => format!(" return"), + Unreachable => format!(" unreachable"), + Drop { place, .. } => format!(" drop(_{:?})", place.local), + Call { func, args, destination, .. } => { + pretty.push_str(" "); + pretty.push_str(format!("_{} = ", destination.local).as_str()); + pretty.push_str(&pretty_operand(func)); + pretty.push_str("("); + args.iter().enumerate().for_each(|(i, arg)| { + if i > 0 { + pretty.push_str(", "); + } + pretty.push_str(&pretty_operand(arg)); + }); + pretty.push_str(")"); + pretty + } + Assert { cond, expected, msg, target: _, unwind: _ } => { + pretty.push_str(" assert("); + if !expected { + pretty.push_str("!"); + } + pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str()); + pretty.push_str(&pretty_assert_message(msg)); + pretty.push_str(")"); + pretty + } + CoroutineDrop => format!(" coroutine_drop"), + InlineAsm { .. } => todo!(), + } +} + +pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { + use self::TerminatorKind::*; + match terminator { + Resume | Abort | Return | Unreachable | CoroutineDrop => vec![], + Goto { .. } => vec!["".to_string()], + SwitchInt { targets, .. } => targets + .value + .iter() + .map(|target| format!("{}", target)) + .chain(iter::once("otherwise".into())) + .collect(), + Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Drop { unwind: _, .. } => vec!["return".into()], + Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { + vec!["return".into(), "unwind".into()] + } + Call { target: Some(_), unwind: _, .. } => vec!["return".into()], + Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()], + Call { target: None, unwind: _, .. } => vec![], + Assert { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["success".into(), "unwind".into()] + } + Assert { unwind: _, .. } => vec!["success".into()], + InlineAsm { .. } => todo!(), + } +} + +pub fn pretty_assert_message(msg: &AssertMessage) -> String { + let mut pretty = String::new(); + match msg { + AssertMessage::BoundsCheck { len, index } => { + let pretty_len = pretty_operand(len); + let pretty_index = pretty_operand(index); + pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Add, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Sub, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Mul, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Div, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Rem, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Shr, _, r) => { + let pretty_r = pretty_operand(r); + pretty.push_str( + format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}") + .as_str(), + ); + pretty + } + AssertMessage::Overflow(BinOp::Shl, _, r) => { + let pretty_r = pretty_operand(r); + pretty.push_str( + format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}") + .as_str(), + ); + pretty + } + AssertMessage::OverflowNeg(op) => { + let pretty_op = pretty_operand(op); + pretty.push_str( + format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(), + ); + pretty + } + AssertMessage::DivisionByZero(op) => { + let pretty_op = pretty_operand(op); + pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str()); + pretty + } + AssertMessage::RemainderByZero(op) => { + let pretty_op = pretty_operand(op); + pretty.push_str( + format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(), + ); + pretty + } + AssertMessage::ResumedAfterReturn(_) => { + format!("attempt to resume a generator after completion") + } + AssertMessage::ResumedAfterPanic(_) => format!("attempt to resume a panicked generator"), + AssertMessage::MisalignedPointerDereference { required, found } => { + let pretty_required = pretty_operand(required); + let pretty_found = pretty_operand(found); + pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str()); + pretty + } + _ => todo!(), + } +} + pub fn pretty_operand(operand: &Operand) -> String { let mut pretty = String::new(); match operand { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dc9098d3ade7b..fe1f43835ef3a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1821,11 +1821,8 @@ fn maybe_expand_private_type_alias<'tcx>( } _ => None, }); - if let Some(ct) = const_ { - args.insert( - param.def_id.to_def_id(), - SubstParam::Constant(clean_const(ct, cx)), - ); + if let Some(_) = const_ { + args.insert(param.def_id.to_def_id(), SubstParam::Constant); } // FIXME(const_generics_defaults) indices.consts += 1; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f079d01bd8422..7a5cf8031375d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2546,7 +2546,7 @@ pub(crate) enum TypeBindingKind { pub(crate) enum SubstParam { Type(Type), Lifetime(Lifetime), - Constant(Constant), + Constant, } impl SubstParam { diff --git a/tests/run-make/pass-linker-flags-flavor/Makefile b/tests/run-make/pass-linker-flags-flavor/Makefile new file mode 100644 index 0000000000000..bd3d3ed882fbc --- /dev/null +++ b/tests/run-make/pass-linker-flags-flavor/Makefile @@ -0,0 +1,8 @@ +# only-linux + +include ../tools.mk + +all: + $(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3' + $(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg:+verbatim=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3' + $(RUSTC) rs.rs -Z unstable-options -C linker-flavor=ld -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*"a2".*d1.*"a3"' diff --git a/tests/run-make/pass-linker-flags-flavor/rs.rs b/tests/run-make/pass-linker-flags-flavor/rs.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/tests/run-make/pass-linker-flags-flavor/rs.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/ui/match/match-tail-expr-never-type-error.rs b/tests/ui/match/match-tail-expr-never-type-error.rs new file mode 100644 index 0000000000000..786ed3fa904be --- /dev/null +++ b/tests/ui/match/match-tail-expr-never-type-error.rs @@ -0,0 +1,16 @@ +fn never() -> ! { + loop {} +} + +fn bar(a: bool) { + match a { + true => 1, + false => { + never() //~ ERROR `match` arms have incompatible types + } + } +} +fn main() { + bar(true); + bar(false); +} diff --git a/tests/ui/match/match-tail-expr-never-type-error.stderr b/tests/ui/match/match-tail-expr-never-type-error.stderr new file mode 100644 index 0000000000000..226d33daeb254 --- /dev/null +++ b/tests/ui/match/match-tail-expr-never-type-error.stderr @@ -0,0 +1,21 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/match-tail-expr-never-type-error.rs:9:13 + | +LL | fn bar(a: bool) { + | - help: try adding a return type: `-> i32` +LL | / match a { +LL | | true => 1, + | | - this is found to be of type `{integer}` +LL | | false => { +LL | | never() + | | ^^^^^^^ + | | | + | | expected integer, found `()` + | | this expression is of type `!`, but it is coerced to `()` due to its surrounding expression +LL | | } +LL | | } + | |_____- `match` arms have incompatible types + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/non_ascii_ident.rs b/tests/ui/suggestions/non_ascii_ident.rs new file mode 100644 index 0000000000000..679ac4bcb6e3f --- /dev/null +++ b/tests/ui/suggestions/non_ascii_ident.rs @@ -0,0 +1,4 @@ +fn main() { + // There shall be no suggestions here. In particular not `Ok`. + let _ = 读文; //~ ERROR cannot find value `读文` in this scope +} diff --git a/tests/ui/suggestions/non_ascii_ident.stderr b/tests/ui/suggestions/non_ascii_ident.stderr new file mode 100644 index 0000000000000..79fca3e1f612c --- /dev/null +++ b/tests/ui/suggestions/non_ascii_ident.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `读文` in this scope + --> $DIR/non_ascii_ident.rs:3:13 + | +LL | let _ = 读文; + | ^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/range-index-instead-of-colon.rs b/tests/ui/suggestions/range-index-instead-of-colon.rs new file mode 100644 index 0000000000000..3267527ecf2a7 --- /dev/null +++ b/tests/ui/suggestions/range-index-instead-of-colon.rs @@ -0,0 +1,7 @@ +// edition:2021 + +fn main() { + &[1, 2, 3][1:2]; + //~^ ERROR: expected one of + //~| HELP: you might have meant a range expression +} diff --git a/tests/ui/suggestions/range-index-instead-of-colon.stderr b/tests/ui/suggestions/range-index-instead-of-colon.stderr new file mode 100644 index 0000000000000..df29356cc16b3 --- /dev/null +++ b/tests/ui/suggestions/range-index-instead-of-colon.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `?`, `]`, or an operator, found `:` + --> $DIR/range-index-instead-of-colon.rs:4:17 + | +LL | &[1, 2, 3][1:2]; + | ^ expected one of `.`, `?`, `]`, or an operator + | +help: you might have meant a range expression + | +LL | &[1, 2, 3][1..2]; + | ~~ + +error: aborting due to 1 previous error + diff --git a/triagebot.toml b/triagebot.toml index 593386288b496..ed9d59b1bb9eb 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -18,6 +18,7 @@ allow-unauthenticated = [ "relnotes", "requires-*", "regression-*", + "rla-*", "perf-*", "AsyncAwait-OnDeck", "needs-triage",