diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 0bd65aec10f49..8dfc11b56b9b4 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; -use rustc_middle::span_bug; +use rustc_middle::{span_bug, ty}; use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; @@ -590,14 +590,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`. fn map_trait_to_async_trait(&self, def_id: DefId) -> Option { let lang_items = self.tcx.lang_items(); - if Some(def_id) == lang_items.fn_trait() { - lang_items.async_fn_trait() - } else if Some(def_id) == lang_items.fn_mut_trait() { - lang_items.async_fn_mut_trait() - } else if Some(def_id) == lang_items.fn_once_trait() { - lang_items.async_fn_once_trait() - } else { - None + match self.tcx.fn_trait_kind_from_def_id(def_id)? { + ty::ClosureKind::Fn => lang_items.async_fn_trait(), + ty::ClosureKind::FnMut => lang_items.async_fn_mut_trait(), + ty::ClosureKind::FnOnce => lang_items.async_fn_once_trait(), } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index cf735815fd2bb..0f8acadb978cb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1265,12 +1265,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && let CallKind::FnCall { fn_trait_id, self_ty } = kind && let ty::Param(_) = self_ty.kind() && ty == self_ty - && [ - self.infcx.tcx.lang_items().fn_once_trait(), - self.infcx.tcx.lang_items().fn_mut_trait(), - self.infcx.tcx.lang_items().fn_trait(), - ] - .contains(&Some(fn_trait_id)) + && self.infcx.tcx.fn_trait_kind_from_def_id(fn_trait_id).is_some() { // Do not suggest `F: FnOnce() + Clone`. false diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3b66142eb2cec..83a9827e8f81f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -702,12 +702,12 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { +impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { fn visit_after_early_statement_effect( &mut self, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, state: &BorrowckDomain, - stmt: &'a Statement<'tcx>, + stmt: &Statement<'tcx>, location: Location, ) { debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state); @@ -783,7 +783,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< &mut self, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, state: &BorrowckDomain, - term: &'a Terminator<'tcx>, + term: &Terminator<'tcx>, loc: Location, ) { debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state); @@ -896,7 +896,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< &mut self, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, state: &BorrowckDomain, - term: &'a Terminator<'tcx>, + term: &Terminator<'tcx>, loc: Location, ) { let span = term.source_info.span; @@ -1363,7 +1363,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn consume_rvalue( &mut self, location: Location, - (rvalue, span): (&'a Rvalue<'tcx>, Span), + (rvalue, span): (&Rvalue<'tcx>, Span), state: &BorrowckDomain, ) { match rvalue { @@ -1636,7 +1636,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn consume_operand( &mut self, location: Location, - (operand, span): (&'a Operand<'tcx>, Span), + (operand, span): (&Operand<'tcx>, Span), state: &BorrowckDomain, ) { match *operand { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 89fb35154b75e..692784bf1714d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -2,8 +2,7 @@ use rustc_abi::ExternAbi; use rustc_errors::DiagMessage; -use rustc_hir::{self as hir}; -use rustc_middle::bug; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; @@ -173,23 +172,22 @@ pub(crate) fn check_intrinsic_type( ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), ]); let mk_va_list_ty = |mutbl| { - tcx.lang_items().va_list().map(|did| { - let region = ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }, - ); - let env_region = ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_u32(2), - kind: ty::BoundRegionKind::ClosureEnv, - }, - ); - let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]); - (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) - }) + let did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let region = ty::Region::new_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon }, + ); + let env_region = ty::Region::new_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_u32(2), + kind: ty::BoundRegionKind::ClosureEnv, + }, + ); + let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]); + (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; let (n_tps, n_lts, n_cts, inputs, output, safety) = if name_str.starts_with("atomic_") { @@ -548,23 +546,17 @@ pub(crate) fn check_intrinsic_type( ) } - sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) { - Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], tcx.types.unit), - None => bug!("`va_list` lang item needed for C-variadic intrinsics"), - }, + sym::va_start | sym::va_end => { + (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) + } - sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) { - Some((va_list_ref_ty, va_list_ty)) => { - let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); - (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) - } - None => bug!("`va_list` lang item needed for C-variadic intrinsics"), - }, + sym::va_copy => { + let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not); + let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); + (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) + } - sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) { - Some((va_list_ref_ty, _)) => (1, 0, vec![va_list_ref_ty], param(0)), - None => bug!("`va_list` lang item needed for C-variadic intrinsics"), - }, + sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)), sym::nontemporal_store => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 8ad9d80c6b5af..52656fc2d9001 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -750,7 +750,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err ObligationCause::misc(impl_span, checker.impl_def_id), param_env, nontrivial_field_ty, - tcx.lang_items().pointer_like().unwrap(), + tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)), ); // FIXME(dyn-star): We should regionck this implementation. if ocx.select_all_or_error().is_empty() { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 02fd7367e2f29..d770937bd6616 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -37,7 +37,7 @@ pub(crate) fn check_legal_trait_for_method_call( body_id: DefId, ) -> Result<(), ErrorGuaranteed> { if tcx.is_lang_item(trait_id, LangItem::Drop) - && tcx.lang_items().fallback_surface_drop_fn() != Some(body_id) + && !tcx.is_lang_item(body_id, LangItem::FallbackSurfaceDrop) { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { errors::ExplicitDestructorCallSugg::Snippet { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index da0e8e362d663..8b2d9ab297905 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -925,7 +925,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| { if let ty::Adt(adt, _) = ty.kind() - && self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did()) + && self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull) && let hir::ExprKind::Struct( hir::QPath::LangItem(hir::LangItem::RangeFull, _), [], diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e5e4fc7f8b77f..7e7079f09ada7 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1457,15 +1457,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => (None, None), }; - let ranges = &[ - self.tcx.lang_items().range_struct(), - self.tcx.lang_items().range_from_struct(), - self.tcx.lang_items().range_to_struct(), - self.tcx.lang_items().range_full_struct(), - self.tcx.lang_items().range_inclusive_struct(), - self.tcx.lang_items().range_to_inclusive_struct(), - ]; - if type_def_id != None && ranges.contains(&type_def_id) { + let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) { + Some( + LangItem::Range + | LangItem::RangeFrom + | LangItem::RangeTo + | LangItem::RangeFull + | LangItem::RangeInclusiveStruct + | LangItem::RangeToInclusive, + ) => true, + _ => false, + }; + if is_range { if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { let msg = "constants only support matching by type, \ if you meant to match against a range of values, \ diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 5b4fc51cec885..1dbb467897b7d 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -2,9 +2,8 @@ use std::cell::RefCell; use std::ops::Deref; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{HirId, HirIdMap}; +use rustc_hir::{self as hir, HirId, HirIdMap, LangItem}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode}; @@ -137,7 +136,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { obligation.predicate.kind().skip_binder() && let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) - && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id) + && !self.tcx.is_lang_item(tpred.trait_ref.def_id, LangItem::Sized) { let new_self_ty = self.tcx.types.unit; diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index 571cab934fd6a..00fa0499556cb 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -1,4 +1,4 @@ -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::ty::{self, Ty}; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, impl_lint_pass}; @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { return; }; - if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() { + if !cx.tcx.is_lang_item(method_def_id, LangItem::IntoIterIntoIter) { return; } diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 7a91bfad4836c..0f92c1910f1bb 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -35,11 +35,10 @@ impl<'tcx> TyCtxt<'tcx> { /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option { - let items = self.lang_items(); - match Some(id) { - x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), - x if x == items.fn_mut_trait() => Some(ty::ClosureKind::FnMut), - x if x == items.fn_once_trait() => Some(ty::ClosureKind::FnOnce), + match self.as_lang_item(id)? { + LangItem::Fn => Some(ty::ClosureKind::Fn), + LangItem::FnMut => Some(ty::ClosureKind::FnMut), + LangItem::FnOnce => Some(ty::ClosureKind::FnOnce), _ => None, } } @@ -48,11 +47,10 @@ impl<'tcx> TyCtxt<'tcx> { /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option { - let items = self.lang_items(); - match Some(id) { - x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn), - x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut), - x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce), + match self.as_lang_item(id)? { + LangItem::AsyncFn => Some(ty::ClosureKind::Fn), + LangItem::AsyncFnMut => Some(ty::ClosureKind::FnMut), + LangItem::AsyncFnOnce => Some(ty::ClosureKind::FnOnce), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 301ae60457434..affb7b31ae1d8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1774,9 +1774,7 @@ impl<'tcx> Ty<'tcx> { match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) { Ok(metadata_ty) => metadata_ty, Err(tail_ty) => { - let Some(metadata_def_id) = tcx.lang_items().metadata_type() else { - bug!("No metadata_type lang item while looking at {self:?}") - }; + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); Ty::new_projection(tcx, metadata_def_id, [tail_ty]) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index c46ae9775cf68..d5005768b80bd 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -114,26 +114,11 @@ where self.reachable_blocks.insert_all() } - /// Returns the underlying `Results`. - pub fn results(&self) -> &Results<'tcx, A> { - &self.results - } - - /// Returns the underlying `Results`. - pub fn mut_results(&mut self) -> &mut Results<'tcx, A> { - &mut self.results - } - /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { &self.results.analysis } - /// Returns the `Analysis` used to generate the underlying `Results`. - pub fn mut_analysis(&mut self) -> &mut A { - &mut self.results.analysis - } - /// Resets the cursor to hold the entry set for the given basic block. /// /// For forward dataflow analyses, this is the dataflow state prior to the first statement. diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 3d7f9e2d8e71b..b8c26dad59f41 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -43,7 +43,7 @@ pub trait Direction { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut Results<'tcx, A>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, + vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>; } @@ -212,7 +212,7 @@ impl Direction for Backward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut Results<'tcx, A>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, + vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { @@ -394,7 +394,7 @@ impl Direction for Forward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut Results<'tcx, A>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, + vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 95f488a925b2c..b5e9a0b893247 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -201,11 +201,12 @@ struct Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { + body: &'mir Body<'tcx>, // The `RefCell` is used because `::node_label` - // takes `&self`, but it needs to modify the cursor. This is also the + // takes `&self`, but it needs to modify the results. This is also the // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has // the operations that involve the mutation, i.e. within the `borrow_mut`. - cursor: RefCell>, + results: RefCell<&'mir mut Results<'tcx, A>>, style: OutputStyle, reachable: DenseBitSet, } @@ -220,11 +221,7 @@ where style: OutputStyle, ) -> Self { let reachable = traversal::reachable_as_bitset(body); - Formatter { cursor: results.as_results_cursor(body).into(), style, reachable } - } - - fn body(&self) -> &'mir Body<'tcx> { - self.cursor.borrow().body() + Formatter { body, results: results.into(), style, reachable } } } @@ -253,7 +250,7 @@ where type Edge = CfgEdge; fn graph_id(&self) -> dot::Id<'_> { - let name = graphviz_safe_def_name(self.body().source.def_id()); + let name = graphviz_safe_def_name(self.body.source.def_id()); dot::Id::new(format!("graph_for_def_id_{name}")).unwrap() } @@ -262,10 +259,16 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut cursor = self.cursor.borrow_mut(); - let mut fmt = - BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; - let label = fmt.write_node_label(*block).unwrap(); + let mut results = self.results.borrow_mut(); + + let diffs = StateDiffCollector::run(self.body, *block, *results, self.style); + + let mut fmt = BlockFormatter { + cursor: results.as_results_cursor(self.body), + style: self.style, + bg: Background::Light, + }; + let label = fmt.write_node_label(*block, diffs).unwrap(); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -275,7 +278,7 @@ where } fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { - let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index]; + let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; dot::LabelText::label(label.clone()) } } @@ -288,7 +291,7 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body() + self.body .basic_blocks .indices() .filter(|&idx| self.reachable.contains(idx)) @@ -297,10 +300,10 @@ where } fn edges(&self) -> dot::Edges<'_, Self::Edge> { - let body = self.body(); - body.basic_blocks + self.body + .basic_blocks .indices() - .flat_map(|bb| dataflow_successors(body, bb)) + .flat_map(|bb| dataflow_successors(self.body, bb)) .collect::>() .into() } @@ -310,20 +313,20 @@ where } fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body()[edge.source].terminator().successors().nth(edge.index).unwrap() + self.body[edge.source].terminator().successors().nth(edge.index).unwrap() } } -struct BlockFormatter<'a, 'mir, 'tcx, A> +struct BlockFormatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - cursor: &'a mut ResultsCursor<'mir, 'tcx, A>, + cursor: ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } -impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A> +impl<'tcx, A> BlockFormatter<'_, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext, @@ -336,7 +339,11 @@ where bg } - fn write_node_label(&mut self, block: BasicBlock) -> io::Result> { + fn write_node_label( + &mut self, + block: BasicBlock, + diffs: StateDiffCollector, + ) -> io::Result> { use std::io::Write; // Sample output: @@ -392,7 +399,7 @@ where self.write_row_with_full_state(w, "", "(on start)")?; // D + E: Statement and terminator transfer functions - self.write_statements_and_terminator(w, block)?; + self.write_statements_and_terminator(w, block, diffs)?; // F: State at end of block @@ -575,14 +582,8 @@ where &mut self, w: &mut impl io::Write, block: BasicBlock, + diffs: StateDiffCollector, ) -> io::Result<()> { - let diffs = StateDiffCollector::run( - self.cursor.body(), - block, - self.cursor.mut_results(), - self.style, - ); - let mut diffs_before = diffs.before.map(|v| v.into_iter()); let mut diffs_after = diffs.after.into_iter(); @@ -709,7 +710,7 @@ impl StateDiffCollector { } } -impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector +impl<'tcx, A> ResultsVisitor<'tcx, A> for StateDiffCollector where A: Analysis<'tcx>, A::Domain: DebugWithContext, diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index 8e2c3afddb352..93dfc06a878aa 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -47,7 +47,7 @@ where &mut self, body: &'mir Body<'tcx>, blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, + vis: &mut impl ResultsVisitor<'tcx, A>, ) { visit_results(body, blocks, self, vis) } @@ -55,7 +55,7 @@ where pub fn visit_reachable_with<'mir>( &mut self, body: &'mir Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, + vis: &mut impl ResultsVisitor<'tcx, A>, ) { let blocks = traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index a03aecee7be12..c9fdf46c4f5b2 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -8,7 +8,7 @@ pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, results: &mut Results<'tcx, A>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, + vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { @@ -29,7 +29,7 @@ pub fn visit_results<'mir, 'tcx, A>( /// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in /// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain /// locations. -pub trait ResultsVisitor<'mir, 'tcx, A> +pub trait ResultsVisitor<'tcx, A> where A: Analysis<'tcx>, { @@ -40,7 +40,7 @@ where &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, - _statement: &'mir mir::Statement<'tcx>, + _statement: &mir::Statement<'tcx>, _location: Location, ) { } @@ -50,7 +50,7 @@ where &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, - _statement: &'mir mir::Statement<'tcx>, + _statement: &mir::Statement<'tcx>, _location: Location, ) { } @@ -60,7 +60,7 @@ where &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, - _terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, _location: Location, ) { } @@ -72,7 +72,7 @@ where &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, - _terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, _location: Location, ) { } diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 5d2a78acbf526..21590ff1bbad4 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -120,12 +120,12 @@ struct Visitor<'a, N: Idx> { values: SparseIntervalMatrix, } -impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N> +impl<'tcx, A, N> ResultsVisitor<'tcx, A> for Visitor<'_, N> where A: Analysis<'tcx, Domain = DenseBitSet>, N: Idx, { - fn visit_after_primary_statement_effect( + fn visit_after_primary_statement_effect<'mir>( &mut self, _results: &mut Results<'tcx, A>, state: &A::Domain, @@ -139,7 +139,7 @@ where }); } - fn visit_after_primary_terminator_effect( + fn visit_after_primary_terminator_effect<'mir>( &mut self, _results: &mut Results<'tcx, A>, state: &A::Domain, diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index e49723a6c39db..cace4cd6bba56 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -3,6 +3,7 @@ use std::ops::ControlFlow; use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; +use rustc_hir::LangItem; use rustc_hir::def::DefKind; use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind}; use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt}; @@ -44,8 +45,7 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion { if let DefKind::AssocFn = tcx.def_kind(def_id) && let Some(trait_ref) = tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) - && let Some(drop_trait) = tcx.lang_items().drop_trait() - && drop_trait == trait_ref.instantiate_identity().def_id + && tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop) // avoid erroneous `Drop` impls from causing ICEs below && let sig = tcx.fn_sig(def_id).instantiate_identity() && sig.inputs().skip_binder().len() == 1 diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 92d5e152f58e6..0eed46c72f993 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -875,14 +875,14 @@ struct StorageConflictVisitor<'a, 'tcx> { eligible_storage_live: DenseBitSet, } -impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> +impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> for StorageConflictVisitor<'a, 'tcx> { fn visit_after_early_statement_effect( &mut self, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, state: &DenseBitSet, - _statement: &'a Statement<'tcx>, + _statement: &Statement<'tcx>, loc: Location, ) { self.apply_state(state, loc); @@ -892,7 +892,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> &mut self, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, state: &DenseBitSet, - _terminator: &'a Terminator<'tcx>, + _terminator: &Terminator<'tcx>, loc: Location, ) { self.apply_state(state, loc); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 90173da17f0fc..a2103a004d2d1 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -958,13 +958,13 @@ fn try_write_constant<'tcx>( interp_ok(()) } -impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { +impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { #[instrument(level = "trace", skip(self, results, statement))] fn visit_after_early_statement_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &State>, - statement: &'mir Statement<'tcx>, + statement: &Statement<'tcx>, location: Location, ) { match &statement.kind { @@ -986,7 +986,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &State>, - statement: &'mir Statement<'tcx>, + statement: &Statement<'tcx>, location: Location, ) { match statement.kind { @@ -1011,7 +1011,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &State>, - terminator: &'mir Terminator<'tcx>, + terminator: &Terminator<'tcx>, location: Location, ) { OperandCollector { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index d7690a96e10de..6bc8a0fc88ce7 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -223,7 +223,7 @@ where match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => { - if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() { + if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) { continue; } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e7f17bb6f996d..d2502c99b9bcc 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -893,6 +893,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string + .suggestion_cr = use `cr` for a raw C-string .suggestion_str = if you meant to write a string literal, use double quotes .suggestion_whitespace = consider inserting whitespace here diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 44b4e1a3e47a0..35cf4c1b00d4b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2140,6 +2140,13 @@ pub(crate) enum UnknownPrefixSugg { style = "verbose" )] UseBr(#[primary_span] Span), + #[suggestion( + parse_suggestion_cr, + code = "cr", + applicability = "maybe-incorrect", + style = "verbose" + )] + UseCr(#[primary_span] Span), #[suggestion( parse_suggestion_whitespace, code = " ", diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index e1f19beb53aee..0b97d4e6993bb 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -1,14 +1,17 @@ use rustc_ast::token::Delimiter; use rustc_errors::Diag; +use rustc_session::parse::ParseSess; use rustc_span::Span; use rustc_span::source_map::SourceMap; use super::UnmatchedDelim; +use crate::errors::MismatchedClosingDelimiter; +use crate::pprust; #[derive(Default)] pub(super) struct TokenTreeDiagInfo { /// Stack of open delimiters and their spans. Used for error message. - pub open_braces: Vec<(Delimiter, Span)>, + pub open_delimiters: Vec<(Delimiter, Span)>, pub unmatched_delims: Vec, /// Used only for error recovery when arriving to EOF with mismatched braces. @@ -108,7 +111,7 @@ pub(super) fn report_suspicious_mismatch_block( } else { // If there is no suspicious span, give the last properly closed block may help if let Some(parent) = diag_info.matching_block_spans.last() - && diag_info.open_braces.last().is_none() + && diag_info.open_delimiters.last().is_none() && diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) { err.span_label(parent.0, "this opening brace..."); @@ -116,3 +119,24 @@ pub(super) fn report_suspicious_mismatch_block( } } } + +pub(crate) fn make_unclosed_delims_error( + unmatched: UnmatchedDelim, + psess: &ParseSess, +) -> Option> { + // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to + // `unmatched_delims` only for error recovery in the `Parser`. + let found_delim = unmatched.found_delim?; + let mut spans = vec![unmatched.found_span]; + if let Some(sp) = unmatched.unclosed_span { + spans.push(sp); + }; + let err = psess.dcx().create_err(MismatchedClosingDelimiter { + spans, + delimiter: pprust::token_kind_to_string(&found_delim.as_close_token_kind()).to_string(), + unmatched: unmatched.found_span, + opening_candidate: unmatched.candidate_span, + unclosed: unmatched.unclosed_span, + }); + Some(err) +} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index a8ec9a1e952ef..e8a5cae54cf8b 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,5 +1,6 @@ use std::ops::Range; +use diagnostics::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; @@ -17,9 +18,9 @@ use rustc_session::parse::ParseSess; use rustc_span::{BytePos, Pos, Span, Symbol}; use tracing::debug; +use crate::errors; use crate::lexer::diagnostics::TokenTreeDiagInfo; use crate::lexer::unicode_chars::UNICODE_ARRAY; -use crate::{errors, make_unclosed_delims_error}; mod diagnostics; mod tokentrees; @@ -256,7 +257,6 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let lit_start = start + BytePos(prefix_len); self.pos = lit_start; self.cursor = Cursor::new(&str_before[prefix_len as usize..]); - self.report_unknown_prefix(start); let prefix_span = self.mk_sp(start, lit_start); return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace); @@ -789,13 +789,14 @@ impl<'psess, 'src> Lexer<'psess, 'src> { fn report_unknown_prefix(&self, start: BytePos) { let prefix_span = self.mk_sp(start, self.pos); let prefix = self.str_from_to(start, self.pos); - let expn_data = prefix_span.ctxt().outer_expn_data(); if expn_data.edition.at_least_rust_2021() { // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) + } else if prefix == "rc" { + Some(errors::UnknownPrefixSugg::UseCr(prefix_span)) } else if expn_data.is_root() { if self.cursor.first() == '\'' && let Some(start) = self.last_lifetime diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 0ddd9a85df867..fbea958dcc598 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -54,8 +54,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let mut err = self.dcx().struct_span_err(self.token.span, msg); let unclosed_delimiter_show_limit = 5; - let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len()); - for &(_, span) in &self.diag_info.open_braces[..len] { + let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_delimiters.len()); + for &(_, span) in &self.diag_info.open_delimiters[..len] { err.span_label(span, "unclosed delimiter"); self.diag_info.unmatched_delims.push(UnmatchedDelim { found_delim: None, @@ -65,19 +65,19 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }); } - if let Some((_, span)) = self.diag_info.open_braces.get(unclosed_delimiter_show_limit) - && self.diag_info.open_braces.len() >= unclosed_delimiter_show_limit + 2 + if let Some((_, span)) = self.diag_info.open_delimiters.get(unclosed_delimiter_show_limit) + && self.diag_info.open_delimiters.len() >= unclosed_delimiter_show_limit + 2 { err.span_label( *span, format!( "another {} unclosed delimiters begin from here", - self.diag_info.open_braces.len() - unclosed_delimiter_show_limit + self.diag_info.open_delimiters.len() - unclosed_delimiter_show_limit ), ); } - if let Some((delim, _)) = self.diag_info.open_braces.last() { + if let Some((delim, _)) = self.diag_info.open_delimiters.last() { report_suspicious_mismatch_block( &mut err, &self.diag_info, @@ -95,7 +95,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // The span for beginning of the delimited section. let pre_span = self.token.span; - self.diag_info.open_braces.push((open_delim, self.token.span)); + self.diag_info.open_delimiters.push((open_delim, self.token.span)); // Lex the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -109,11 +109,12 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() { if close_delim == open_delim { // Correct delimiter. - let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap(); - let close_brace_span = self.token.span; + let (open_delimiter, open_delimiter_span) = + self.diag_info.open_delimiters.pop().unwrap(); + let close_delimiter_span = self.token.span; if tts.is_empty() && close_delim == Delimiter::Brace { - let empty_block_span = open_brace_span.to(close_brace_span); + let empty_block_span = open_delimiter_span.to(close_delimiter_span); if !sm.is_multiline(empty_block_span) { // Only track if the block is in the form of `{}`, otherwise it is // likely that it was written on purpose. @@ -122,9 +123,11 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } // only add braces - if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) { + if let (Delimiter::Brace, Delimiter::Brace) = (open_delimiter, open_delim) { // Add all the matching spans, we will sort by span later - self.diag_info.matching_block_spans.push((open_brace_span, close_brace_span)); + self.diag_info + .matching_block_spans + .push((open_delimiter_span, close_delimiter_span)); } // Move past the closing delimiter. @@ -140,18 +143,18 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The lexer just hasn't gotten to them yet. - if let Some(&(_, sp)) = self.diag_info.open_braces.last() { + if let Some(&(_, sp)) = self.diag_info.open_delimiters.last() { unclosed_delimiter = Some(sp); }; - for (brace, brace_span) in &self.diag_info.open_braces { - if same_indentation_level(sm, self.token.span, *brace_span) - && brace == &close_delim + for (delimiter, delimiter_span) in &self.diag_info.open_delimiters { + if same_indentation_level(sm, self.token.span, *delimiter_span) + && delimiter == &close_delim { // high likelihood of these two corresponding - candidate = Some(*brace_span); + candidate = Some(*delimiter_span); } } - let (_, _) = self.diag_info.open_braces.pop().unwrap(); + let (_, _) = self.diag_info.open_delimiters.pop().unwrap(); self.diag_info.unmatched_delims.push(UnmatchedDelim { found_delim: Some(close_delim), found_span: self.token.span, @@ -159,7 +162,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { candidate_span: candidate, }); } else { - self.diag_info.open_braces.pop(); + self.diag_info.open_delimiters.pop(); } // If the incorrect delimiter matches an earlier opening @@ -169,7 +172,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // fn foo() { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` - if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) { + if !self.diag_info.open_delimiters.iter().any(|&(d, _)| d == close_delim) { self.bump_minimal() } else { // The choice of value here doesn't matter. @@ -180,7 +183,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { assert_eq!(self.token.kind, token::Eof); // Silently recover, the EOF token will be seen again // and an error emitted then. Thus we don't pop from - // self.open_braces here. The choice of spacing value here + // self.open_delimiters here. The choice of spacing value here // doesn't matter. Spacing::Alone }; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 2edc8c83017d8..896e348a12dc1 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -32,7 +32,7 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; -use parser::{Parser, make_unclosed_delims_error}; +use parser::Parser; pub mod lexer; pub mod validate_attr; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d73adb39826f4..48df8b59d55ad 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -43,11 +43,8 @@ use token_type::TokenTypeSet; pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType}; use tracing::debug; -use crate::errors::{ - self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, -}; +use crate::errors::{self, IncorrectVisibilityRestriction, NonStringAbiLiteral}; use crate::exp; -use crate::lexer::UnmatchedDelim; #[cfg(test)] mod tests; @@ -1745,27 +1742,6 @@ impl<'a> Parser<'a> { } } -pub(crate) fn make_unclosed_delims_error( - unmatched: UnmatchedDelim, - psess: &ParseSess, -) -> Option> { - // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to - // `unmatched_delims` only for error recovery in the `Parser`. - let found_delim = unmatched.found_delim?; - let mut spans = vec![unmatched.found_span]; - if let Some(sp) = unmatched.unclosed_span { - spans.push(sp); - }; - let err = psess.dcx().create_err(MismatchedClosingDelimiter { - spans, - delimiter: pprust::token_kind_to_string(&found_delim.as_close_token_kind()).to_string(), - unmatched: unmatched.found_span, - opening_candidate: unmatched.candidate_span, - unclosed: unmatched.unclosed_span, - }); - Some(err) -} - /// A helper struct used when building an `AttrTokenStream` from /// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens /// are stored as `FlatToken::Token`. A vector of `FlatToken`s diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index 1c3e570b67695..d8b405e904c06 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -81,9 +81,7 @@ pub fn call_kind<'tcx>( } }); - let fn_call = parent.and_then(|p| { - lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) - }); + let fn_call = parent.filter(|&p| tcx.fn_trait_kind_from_def_id(p).is_some()); let operator = if !from_hir_call && let Some(p) = parent { lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 5648021f6134e..df6e8fc4503f1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && leaf_trait_predicate.def_id() != root_pred.def_id() // The root trait is not `Unsize`, as to avoid talking about it in // `tests/ui/coercion/coerce-issue-49593-box-never.rs`. - && Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait() + && !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize) { ( self.resolve_vars_if_possible( @@ -2274,10 +2274,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // auto-traits or fundamental traits that might not be exactly what // the user might expect to be presented with. Instead this is // useful for less general traits. - if peeled - && !self.tcx.trait_is_auto(def_id) - && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id) - { + if peeled && !self.tcx.trait_is_auto(def_id) && self.tcx.as_lang_item(def_id).is_none() { let impl_candidates = self.find_similar_impl_candidates(trait_pred); self.report_similar_impl_candidates( &impl_candidates, @@ -3013,8 +3010,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // This shouldn't be common unless manually implementing one of the // traits manually, but don't make it more confusing when it does // happen. - if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled - { + if !self.tcx.is_lang_item(expected_trait_ref.def_id, LangItem::Coroutine) && not_tupled { return Ok(self.report_and_explain_type_error( TypeTrace::trait_refs(&obligation.cause, expected_trait_ref, found_trait_ref), obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 7d95a7b3fed24..de251ae2893c4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3844,12 +3844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder() && let ty::ClauseKind::Trait(pred) = clause - && [ - tcx.lang_items().fn_once_trait(), - tcx.lang_items().fn_mut_trait(), - tcx.lang_items().fn_trait(), - ] - .contains(&Some(pred.def_id())) + && tcx.fn_trait_kind_from_def_id(pred.def_id()).is_some() { if let [stmt, ..] = block.stmts && let hir::StmtKind::Semi(value) = stmt.kind diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index d8dcd12aecb98..6f1a8683a657d 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -1,5 +1,6 @@ use std::ops::ControlFlow; +use rustc_hir::LangItem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ @@ -452,9 +453,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { // We do this as a separate loop so that we do not choose to tell the user about some nested // goal before we encounter a `T: FnPtr` nested goal. for nested_goal in &nested_goals { - if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait() - && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() - && poly_trait_pred.def_id() == fn_ptr_trait + if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() + && tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait) && let Err(NoSolution) = nested_goal.result() { return ControlFlow::Break(self.obligation.clone()); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0dce504903ca4..99fa791b37550 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -965,36 +965,38 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let tcx = selcx.tcx(); - let lang_items = selcx.tcx().lang_items(); - if [ - lang_items.coroutine_trait(), - lang_items.future_trait(), - lang_items.iterator_trait(), - lang_items.async_iterator_trait(), - lang_items.fn_trait(), - lang_items.fn_mut_trait(), - lang_items.fn_once_trait(), - lang_items.async_fn_trait(), - lang_items.async_fn_mut_trait(), - lang_items.async_fn_once_trait(), - ] - .contains(&Some(trait_ref.def_id)) - { - true - } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnKindHelper) { - // FIXME(async_closures): Validity constraints here could be cleaned up. - if obligation.predicate.args.type_at(0).is_ty_var() - || obligation.predicate.args.type_at(4).is_ty_var() - || obligation.predicate.args.type_at(5).is_ty_var() - { - candidate_set.mark_ambiguous(); - true - } else { - obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() - && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() + match selcx.tcx().as_lang_item(trait_ref.def_id) { + Some( + LangItem::Coroutine + | LangItem::Future + | LangItem::Iterator + | LangItem::AsyncIterator + | LangItem::Fn + | LangItem::FnMut + | LangItem::FnOnce + | LangItem::AsyncFn + | LangItem::AsyncFnMut + | LangItem::AsyncFnOnce, + ) => true, + Some(LangItem::AsyncFnKindHelper) => { + // FIXME(async_closures): Validity constraints here could be cleaned up. + if obligation.predicate.args.type_at(0).is_ty_var() + || obligation.predicate.args.type_at(4).is_ty_var() + || obligation.predicate.args.type_at(5).is_ty_var() + { + candidate_set.mark_ambiguous(); + true + } else { + obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() + && obligation + .predicate + .args + .type_at(1) + .to_opt_closure_kind() + .is_some() + } } - } else if tcx.is_lang_item(trait_ref.def_id, LangItem::DiscriminantKind) { - match self_ty.kind() { + Some(LangItem::DiscriminantKind) => match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -1031,9 +1033,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Placeholder(..) | ty::Infer(..) | ty::Error(_) => false, - } - } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncDestruct) { - match self_ty.kind() { + }, + Some(LangItem::AsyncDestruct) => match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -1068,101 +1069,104 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Placeholder(..) | ty::Infer(_) | ty::Error(_) => false, - } - } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) { - let tail = selcx.tcx().struct_tail_raw( - self_ty, - |ty| { - // We throw away any obligations we get from this, since we normalize - // and confirm these obligations once again during confirmation - normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - ) - .value - }, - || {}, - ); + }, + Some(LangItem::PointeeTrait) => { + let tail = selcx.tcx().struct_tail_raw( + self_ty, + |ty| { + // We throw away any obligations we get from this, since we normalize + // and confirm these obligations once again during confirmation + normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty, + ) + .value + }, + || {}, + ); - match tail.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Array(..) - | ty::Pat(..) - | ty::Slice(_) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Never - // Extern types have unit metadata, according to RFC 2850 - | ty::Foreign(_) - // If returned by `struct_tail` this is a unit struct - // without any fields, or not a struct, and therefore is Sized. - | ty::Adt(..) - // If returned by `struct_tail` this is the empty tuple. - | ty::Tuple(..) - // Integers and floats are always Sized, and so have unit type metadata. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) - // This happens if we reach the recursion limit when finding the struct tail. - | ty::Error(..) => true, - - // We normalize from `Wrapper::Metadata` to `Tail::Metadata` if able. - // Otherwise, type parameters, opaques, and unnormalized projections have - // unit metadata if they're known (e.g. by the param_env) to be sized. - ty::Param(_) | ty::Alias(..) - if self_ty != tail - || selcx.infcx.predicate_must_hold_modulo_regions( - &obligation.with( - selcx.tcx(), - ty::TraitRef::new( + match tail.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(..) + | ty::Pat(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + // Extern types have unit metadata, according to RFC 2850 + | ty::Foreign(_) + // If returned by `struct_tail` this is a unit struct + // without any fields, or not a struct, and therefore is Sized. + | ty::Adt(..) + // If returned by `struct_tail` this is the empty tuple. + | ty::Tuple(..) + // Integers and floats are always Sized, and so have unit type metadata. + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) + // This happens if we reach the recursion limit when finding the struct tail. + | ty::Error(..) => true, + + // We normalize from `Wrapper::Metadata` to `Tail::Metadata` if able. + // Otherwise, type parameters, opaques, and unnormalized projections have + // unit metadata if they're known (e.g. by the param_env) to be sized. + ty::Param(_) | ty::Alias(..) + if self_ty != tail + || selcx.infcx.predicate_must_hold_modulo_regions( + &obligation.with( selcx.tcx(), - selcx.tcx().require_lang_item( - LangItem::Sized, - Some(obligation.cause.span), + ty::TraitRef::new( + selcx.tcx(), + selcx.tcx().require_lang_item( + LangItem::Sized, + Some(obligation.cause.span), + ), + [self_ty], ), - [self_ty], ), - ), - ) => - { - true - } + ) => + { + true + } - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), - // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? - ty::Param(_) - | ty::Alias(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) => { - if tail.has_infer_types() { - candidate_set.mark_ambiguous(); + // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? + ty::Param(_) + | ty::Alias(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) => { + if tail.has_infer_types() { + candidate_set.mark_ambiguous(); + } + false } - false } } - } else if tcx.trait_is_auto(trait_ref.def_id) { - tcx.dcx().span_delayed_bug( - tcx.def_span(obligation.predicate.def_id), - "associated types not allowed on auto traits", - ); - false - } else { - bug!("unexpected builtin trait with associated type: {trait_ref:?}") + _ if tcx.trait_is_auto(trait_ref.def_id) => { + tcx.dcx().span_delayed_bug( + tcx.def_span(obligation.predicate.def_id), + "associated types not allowed on auto traits", + ); + false + } + _ => { + bug!("unexpected builtin trait with associated type: {trait_ref:?}") + } } } ImplSource::Param(..) => { diff --git a/library/Cargo.lock b/library/Cargo.lock index ba5e54db95d16..f7f09a11f3ac9 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.155" +version = "0.1.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "341e0830ca6170a4fcf02e92e57daf4b6f10142d48da32a547023867a6c8b35e" +checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index cedbd330cbde8..994221de86635 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.155", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.156", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index c02efd997cfcc..3536e84d58bed 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.155" } +compiler_builtins = { version = "=0.1.156" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 50f403ba411b6..7cd20c48d8939 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -353,6 +353,15 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { } } +/// Checks whether the string is valid as a file extension, or panics otherwise. +fn validate_extension(extension: &OsStr) { + for &b in extension.as_encoded_bytes() { + if is_sep_byte(b) { + panic!("extension cannot contain path separators: {extension:?}"); + } + } +} + //////////////////////////////////////////////////////////////////////////////// // The core iterators //////////////////////////////////////////////////////////////////////////////// @@ -1507,13 +1516,7 @@ impl PathBuf { } fn _set_extension(&mut self, extension: &OsStr) -> bool { - for &b in extension.as_encoded_bytes() { - if b < 128 { - if is_separator(b as char) { - panic!("extension cannot contain path separators: {:?}", extension); - } - } - } + validate_extension(extension); let file_stem = match self.file_stem() { None => return false, @@ -1541,6 +1544,11 @@ impl PathBuf { /// Returns `false` and does nothing if [`self.file_name`] is [`None`], /// returns `true` and updates the extension otherwise. /// + /// # Panics + /// + /// Panics if the passed extension contains a path separator (see + /// [`is_separator`]). + /// /// # Caveats /// /// The appended `extension` may contain dots and will be used in its entirety, @@ -1582,6 +1590,8 @@ impl PathBuf { } fn _add_extension(&mut self, extension: &OsStr) -> bool { + validate_extension(extension); + let file_name = match self.file_name() { None => return false, Some(f) => f.as_encoded_bytes(), diff --git a/tests/ui/suggestions/raw-c-string-prefix.rs b/tests/ui/suggestions/raw-c-string-prefix.rs new file mode 100644 index 0000000000000..6af72df40242c --- /dev/null +++ b/tests/ui/suggestions/raw-c-string-prefix.rs @@ -0,0 +1,10 @@ +// `rc` and `cr` are easy to confuse; check that we issue a suggestion to help. + +//@ edition:2021 + +fn main() { + rc"abc"; + //~^ ERROR: prefix `rc` is unknown + //~| HELP: use `cr` for a raw C-string + //~| ERROR: expected one of +} diff --git a/tests/ui/suggestions/raw-c-string-prefix.stderr b/tests/ui/suggestions/raw-c-string-prefix.stderr new file mode 100644 index 0000000000000..5341e3d04e8a1 --- /dev/null +++ b/tests/ui/suggestions/raw-c-string-prefix.stderr @@ -0,0 +1,21 @@ +error: prefix `rc` is unknown + --> $DIR/raw-c-string-prefix.rs:6:5 + | +LL | rc"abc"; + | ^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: use `cr` for a raw C-string + | +LL - rc"abc"; +LL + cr"abc"; + | + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"abc"` + --> $DIR/raw-c-string-prefix.rs:6:7 + | +LL | rc"abc"; + | ^^^^^ expected one of 8 possible tokens + +error: aborting due to 2 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 0f17d022fbb84..189223f2feba1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1120,6 +1120,11 @@ cc = ["@ZuseZ4"] [mentions."compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs"] cc = ["@ZuseZ4"] +[mentions."library/core/src/fmt/rt.rs"] +cc = ["@m-ou-se"] +[mentions."compiler/rustc_ast_lowering/src/format.rs"] +cc = ["@m-ou-se"] + [assign] warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"