diff options
1509 files changed, 20584 insertions, 4256 deletions
diff --git a/Cargo.lock b/Cargo.lock index 84a668b5188..4cb2a584e6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -723,6 +723,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] +name = "coverage-dump" +version = "0.1.0" +dependencies = [ + "anyhow", + "leb128", + "md-5", + "miniz_oxide", + "regex", + "rustc-demangle", +] + +[[package]] name = "coverage_test_macros" version = "0.0.0" @@ -2042,6 +2054,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] name = "levenshtein" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4157,7 +4175,7 @@ dependencies = [ name = "rustc_parse_format" version = "0.0.0" dependencies = [ - "rustc_data_structures", + "rustc_index", "rustc_lexer", ] @@ -4228,7 +4246,6 @@ dependencies = [ "measureme", "memoffset", "rustc-rayon-core", - "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_hir", @@ -4437,15 +4454,12 @@ dependencies = [ name = "rustc_traits" version = "0.0.0" dependencies = [ - "rustc_ast", "rustc_data_structures", "rustc_hir", "rustc_infer", "rustc_middle", "rustc_span", - "rustc_target", "rustc_trait_selection", - "smallvec", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index d2e84d5426f..9b11ae8744b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "src/tools/generate-windows-sys", "src/tools/rustdoc-gui-test", "src/tools/opt-dist", + "src/tools/coverage-dump", ] exclude = [ diff --git a/RELEASES.md b/RELEASES.md index 242b1c2eefd..c5ac070b317 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,9 +10,9 @@ Language - [expand: Change how `#![cfg(FALSE)]` behaves on crate root](https://github.com/rust-lang/rust/pull/110141/) - [Stabilize inline asm for LoongArch64](https://github.com/rust-lang/rust/pull/111235/) - [Uplift `clippy::undropped_manually_drops` lint](https://github.com/rust-lang/rust/pull/111530/) -- [Uplift `clippy::invalid_utf8_in_unchecked` lint](https://github.com/rust-lang/rust/pull/111543/) -- [Uplift `clippy::cast_ref_to_mut` lint](https://github.com/rust-lang/rust/pull/111567/) -- [Uplift `clippy::cmp_nan` lint](https://github.com/rust-lang/rust/pull/111818/) +- [Uplift `clippy::invalid_utf8_in_unchecked` lint](https://github.com/rust-lang/rust/pull/111543/) as `invalid_from_utf8_unchecked` and `invalid_from_utf8` +- [Uplift `clippy::cast_ref_to_mut` lint](https://github.com/rust-lang/rust/pull/111567/) as `invalid_reference_casting` +- [Uplift `clippy::cmp_nan` lint](https://github.com/rust-lang/rust/pull/111818/) as `invalid_nan_comparisons` - [resolve: Remove artificial import ambiguity errors](https://github.com/rust-lang/rust/pull/112086/) - [Don't require associated types with Self: Sized bounds in `dyn Trait` objects](https://github.com/rust-lang/rust/pull/112319/) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 571aaf631bd..b30ff058a30 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1300,12 +1300,18 @@ impl Abi { matches!(*self, Abi::Uninhabited) } - /// Returns `true` is this is a scalar type + /// Returns `true` if this is a scalar type #[inline] pub fn is_scalar(&self) -> bool { matches!(*self, Abi::Scalar(_)) } + /// Returns `true` if this is a bool + #[inline] + pub fn is_bool(&self) -> bool { + matches!(*self, Abi::Scalar(s) if s.is_bool()) + } + /// Returns the fixed alignment of this ABI, if any is mandated. pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> { Some(match *self { @@ -1348,6 +1354,23 @@ impl Abi { Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, } } + + pub fn eq_up_to_validity(&self, other: &Self) -> bool { + match (self, other) { + // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges. + // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x). + (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(), + ( + Abi::Vector { element: element_l, count: count_l }, + Abi::Vector { element: element_r, count: count_r }, + ) => element_l.primitive() == element_r.primitive() && count_l == count_r, + (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => { + l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() + } + // Everything else must be strictly identical. + _ => self == other, + } + } } #[derive(PartialEq, Eq, Hash, Clone, Debug)] @@ -1686,6 +1709,22 @@ impl LayoutS { Abi::Aggregate { sized } => sized && self.size.bytes() == 0, } } + + /// Checks if these two `Layout` are equal enough to be considered "the same for all function + /// call ABIs". Note however that real ABIs depend on more details that are not reflected in the + /// `Layout`; the `PassMode` need to be compared as well. + pub fn eq_abi(&self, other: &Self) -> bool { + // The one thing that we are not capturing here is that for unsized types, the metadata must + // also have the same ABI, and moreover that the same metadata leads to the same size. The + // 2nd point is quite hard to check though. + self.size == other.size + && self.is_sized() == other.is_sized() + && self.abi.eq_up_to_validity(&other.abi) + && self.abi.is_bool() == other.abi.is_bool() + && self.align.abi == other.align.abi + && self.max_repr_align == other.max_repr_align + && self.unadjusted_abi_align == other.unadjusted_abi_align + } } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index e9591c7c8db..1e18b1232de 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -213,14 +213,10 @@ impl AttrTokenStream { .into_iter() } AttrTokenTree::Attributes(data) => { - let mut outer_attrs = Vec::new(); - let mut inner_attrs = Vec::new(); - for attr in &data.attrs { - match attr.style { - crate::AttrStyle::Outer => outer_attrs.push(attr), - crate::AttrStyle::Inner => inner_attrs.push(attr), - } - } + let idx = data + .attrs + .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); + let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); let mut target_tokens: Vec<_> = data .tokens @@ -265,10 +261,10 @@ impl AttrTokenStream { "Failed to find trailing delimited group in: {target_tokens:?}" ); } - let mut flat: SmallVec<[_; 1]> = SmallVec::new(); + let mut flat: SmallVec<[_; 1]> = + SmallVec::with_capacity(target_tokens.len() + outer_attrs.len()); for attr in outer_attrs { - // FIXME: Make this more efficient - flat.extend(attr.tokens().0.clone().iter().cloned()); + flat.extend(attr.tokens().0.iter().cloned()); } flat.extend(target_tokens); flat.into_iter() diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index ce847906fb9..eff362f3ff0 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -2,19 +2,17 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::definitions; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; use rustc_index::{Idx, IndexVec}; use rustc_middle::span_bug; -use rustc_session::Session; -use rustc_span::source_map::SourceMap; +use rustc_middle::ty::TyCtxt; use rustc_span::{Span, DUMMY_SP}; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { - /// Source map - source_map: &'a SourceMap, + tcx: TyCtxt<'hir>, + bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>, /// Outputs @@ -25,14 +23,11 @@ pub(super) struct NodeCollector<'a, 'hir> { parent_node: hir::ItemLocalId, owner: OwnerId, - - definitions: &'a definitions::Definitions, } -#[instrument(level = "debug", skip(sess, definitions, bodies))] +#[instrument(level = "debug", skip(tcx, bodies))] pub(super) fn index_hir<'hir>( - sess: &Session, - definitions: &definitions::Definitions, + tcx: TyCtxt<'hir>, item: hir::OwnerNode<'hir>, bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>, ) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) { @@ -42,8 +37,7 @@ pub(super) fn index_hir<'hir>( // used. nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() })); let mut collector = NodeCollector { - source_map: sess.source_map(), - definitions, + tcx, owner: item.def_id(), parent_node: ItemLocalId::new(0), nodes, @@ -79,11 +73,17 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { span, "inconsistent HirId at `{:?}` for `{:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.source_map.span_to_diagnostic_string(span), + self.tcx.sess.source_map().span_to_diagnostic_string(span), node, - self.definitions.def_path(self.owner.def_id).to_string_no_crate_verbose(), + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), self.owner, - self.definitions.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(), + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), hir_id.owner, ) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a6d1ef33f40..32046b0febf 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -671,8 +671,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { (None, None) }; - let (nodes, parenting) = - index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); + let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; @@ -771,7 +770,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - if self.tcx.sess.opts.incremental_relative_spans() { + if self.tcx.sess.opts.incremental.is_some() { span.with_parent(Some(self.current_hir_id_owner.def_id)) } else { // Do not make spans relative when not using incremental compilation. diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 67fdb671742..d8ca62565fa 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -166,6 +166,8 @@ borrowck_returned_lifetime_wrong = borrowck_returned_ref_escaped = returns a reference to a captured variable which escapes the closure body +borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item + borrowck_suggest_create_freash_reborrow = consider reborrowing the `Pin` instead of moving it diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fe4a45b3898..48d09f2c2b2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`. /// We could expand the analysis to suggest hoising all of the relevant parts of /// the users' code to make the code compile, but that could be too much. - struct NestedStatementVisitor { + /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`, + /// which is a special case since it's generated by the compiler. + struct NestedStatementVisitor<'tcx> { span: Span, current: usize, found: usize, + prop_expr: Option<&'tcx hir::Expr<'tcx>>, } - impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { - fn visit_block(&mut self, block: &hir::Block<'tcx>) { + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { self.current += 1; walk_block(self, block); self.current -= 1; } - fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if self.span == expr.span.source_callsite() { self.found = self.current; + if self.prop_expr.is_none() { + self.prop_expr = Some(expr); + } } walk_expr(self, expr); } @@ -2162,22 +2168,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span: proper_span, current: 0, found: 0, + prop_expr: None, }; visitor.visit_stmt(stmt); + + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); + + let is_format_arguments_item = + if let Some(expr_ty) = expr_ty + && let ty::Adt(adt, _) = expr_ty.kind() { + self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did()) + } else { + false + }; + if visitor.found == 0 && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); - err.multipart_suggestion_verbose( - msg, - vec![ - (stmt.span.shrink_to_lo(), addition), - (proper_span, "binding".to_string()), - ], - Applicability::MaybeIncorrect, - ); + if !is_format_arguments_item { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used"); + err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>"); + } suggested = true; break; } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 31e863b8a4e..54a557c5145 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,9 +1,10 @@ +use hir::ExprKind; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, @@ -491,6 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), ); + self.suggest_using_iter_mut(&mut err); self.suggest_make_local_mut(&mut err, local, name); } _ => { @@ -953,6 +955,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) { + let source = self.body.source; + let hir = self.infcx.tcx.hir(); + if let InstanceDef::Item(def_id) = source.instance + && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id) + && let ExprKind::Closure(closure) = kind && closure.movability == None + && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { + let mut cur_expr = expr; + while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { + if path_segment.ident.name == sym::iter { + // check `_ty` has `iter_mut` method + let res = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner.def_id) + .type_dependent_def_id(cur_expr.hir_id) + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) + .map(|def_id| self.infcx.tcx.associated_items(def_id)) + .map(|assoc_items| { + assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() + }); + + if let Some(mut res) = res && res.peek().is_some() { + err.span_suggestion_verbose( + path_segment.ident.span, + "you may want to use `iter_mut` here", + "iter_mut", + Applicability::MaybeIncorrect, + ); + } + break; + } else { + cur_expr = recv; + } + } + } + } + fn suggest_make_local_mut( &self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 770c180ff2c..8115c61e89d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -603,7 +603,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro fn visit_statement_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, flow_state: &Flows<'cx, 'tcx>, stmt: &'cx Statement<'tcx>, location: Location, @@ -673,7 +673,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro fn visit_terminator_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, flow_state: &Flows<'cx, 'tcx>, term: &'cx Terminator<'tcx>, loc: Location, @@ -784,7 +784,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro fn visit_terminator_after_primary_effect( &mut self, - _results: &R, + _results: &mut R, flow_state: &Flows<'cx, 'tcx>, term: &'cx Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 679a19710a7..3f60f5aca71 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -10,6 +10,7 @@ use rustc_middle::mir::{ Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, START_BLOCK, }; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; use rustc_span::symbol::sym; use std::env; @@ -441,7 +442,10 @@ fn for_each_region_constraint<'tcx>( let subject = match req.subject { ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"), ClosureOutlivesSubject::Ty(ty) => { - format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))) + with_no_trimmed_paths!(format!( + "{}", + ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)) + )) } }; with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index d1d8cfa74aa..ca3ccf439f2 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -452,3 +452,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> { #[note(borrowck_ty_no_impl_copy)] Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str }, } + +#[derive(Diagnostic)] +#[diag(borrowck_simd_shuffle_last_const)] +pub(crate) struct SimdShuffleLastConst { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 28286243e82..0f661421cdc 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -50,7 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; -use crate::session_diagnostics::MoveUnsized; +use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; use crate::{ borrow_set::BorrowSet, constraints::{OutlivesConstraint, OutlivesConstraintSet}, @@ -1426,7 +1426,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .add_element(region_vid, term_location); } - self.check_call_inputs(body, term, &sig, args, term_location, *call_source); + self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source); } TerminatorKind::Assert { cond, msg, .. } => { self.check_operand(cond, term_location); @@ -1546,25 +1546,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))] fn check_call_inputs( &mut self, body: &Body<'tcx>, term: &Terminator<'tcx>, + func: &Operand<'tcx>, sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], term_location: Location, call_source: CallSource, ) { - debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind { - Some(func.ty(body, self.infcx.tcx)) - } else { - None - }; + let func_ty = func.ty(body, self.infcx.tcx); + if let ty::FnDef(def_id, _) = *func_ty.kind() { + if self.tcx().is_intrinsic(def_id) { + match self.tcx().item_name(def_id) { + sym::simd_shuffle => { + if !matches!(args[2], Operand::Constant(_)) { + self.tcx() + .sess + .emit_err(SimdShuffleLastConst { span: term.source_info.span }); + } + } + _ => {} + } + } + } debug!(?func_ty); for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { @@ -1572,7 +1583,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) + ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) } else { ConstraintCategory::Boring }; diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 56945f43fcd..3b5f1178db5 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -21,6 +21,7 @@ use rustc_hir::BodyOwnerKind; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_span::symbol::{kw, sym}; @@ -332,10 +333,16 @@ impl<'tcx> UniversalRegions<'tcx> { pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { match self.defining_ty { DefiningTy::Closure(def_id, args) => { + let v = with_no_trimmed_paths!( + args[tcx.generics_of(def_id).parent_count..] + .iter() + .map(|arg| arg.to_string()) + .collect::<Vec<_>>() + ); err.note(format!( - "defining type: {} with closure args {:#?}", + "defining type: {} with closure args [\n {},\n]", tcx.def_path_str_with_args(def_id, args), - &args[tcx.generics_of(def_id).parent_count..], + v.join(",\n "), )); // FIXME: It'd be nice to print the late-bound regions @@ -348,10 +355,16 @@ impl<'tcx> UniversalRegions<'tcx> { }); } DefiningTy::Generator(def_id, args, _) => { + let v = with_no_trimmed_paths!( + args[tcx.generics_of(def_id).parent_count..] + .iter() + .map(|arg| arg.to_string()) + .collect::<Vec<_>>() + ); err.note(format!( - "defining type: {} with generator args {:#?}", + "defining type: {} with generator args [\n {},\n]", tcx.def_path_str_with_args(def_id, args), - &args[tcx.generics_of(def_id).parent_count..], + v.join(",\n "), )); // FIXME: As above, we'd like to print out the region diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md index c6210f958d6..135a51ce392 100644 --- a/compiler/rustc_codegen_cranelift/docs/usage.md +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic } function jit() { diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml index fa175edcae6..5b79d6569bb 100644 --- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml +++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "compiler_builtins", "gimli", @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "compiler_builtins", "memchr", diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 5689bdee64d..2cc5d7777a6 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-08-08" +channel = "nightly-2023-09-06" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index c163b854384..3fc462a39cc 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -45,6 +45,7 @@ rm tests/ui/proc-macro/quote-debug.rs rm tests/ui/proc-macro/no-missing-docs.rs rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs rm tests/ui/proc-macro/allowed-signatures.rs +rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs # vendor intrinsics rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected @@ -114,6 +115,7 @@ rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/layout/valid_range_oob.rs # different ICE message +rm tests/ui/const-generics/generic_const_exprs/issue-80742.rs # gives error instead of ICE with cg_clif rm tests/ui/consts/issue-miri-1910.rs # different error message rm tests/ui/consts/offset_ub.rs # same diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 50bc7a127af..b19b935a0fe 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -81,13 +81,10 @@ impl DebugContext { match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.lines(|lines| lines[line]); + let line_pos = file.lines()[line]; + let col = file.relative_position(span.lo()) - line_pos; - ( - file, - u64::try_from(line).unwrap() + 1, - u64::from((span.lo() - line_pos).to_u32()) + 1, - ) + (file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) } Err(file) => (file, 0, 0), } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index fdd27a454e0..e62de6b6147 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -177,244 +177,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane) }); } - "llvm.x86.sse2.psrli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrai.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrai.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.pslli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.pslli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrai.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.psrai.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.pslli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.sse2.pslli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx.psrli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx.psrai.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrai.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.psrli.q" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrli.q imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 64 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.sse2.pslli.q" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.pslli.q imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 64 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx.pslli.d" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.pslli.d imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx2.psrli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrli.w imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx2.psrai.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.psrai.w imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().sshr_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } - "llvm.x86.avx2.pslli.w" => { - let (a, imm8) = match args { - [a, imm8] => (a, imm8), - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); - let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8) - .expect("llvm.x86.avx.pslli.w imm8 not const"); - - simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8 - .try_to_bits(Size::from_bytes(4)) - .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) - { - imm8 if imm8 < 16 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), - _ => fx.bcx.ins().iconst(types::I32, 0), - }); - } "llvm.x86.ssse3.pshuf.b.128" | "llvm.x86.avx2.pshuf.b" => { let (a, b) = match args { [a, b] => (a, b), @@ -506,14 +268,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.place_lane(fx, 2).to_ptr().store(fx, res_2, MemFlags::trusted()); ret.place_lane(fx, 3).to_ptr().store(fx, res_3, MemFlags::trusted()); } - "llvm.x86.sse2.storeu.dq" | "llvm.x86.sse2.storeu.pd" => { - intrinsic_args!(fx, args => (mem_addr, a); intrinsic); - let mem_addr = mem_addr.load_scalar(fx); - - // FIXME correctly handle the unalignment - let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout()); - dest.write_cvalue(fx, a); - } "llvm.x86.ssse3.pabs.b.128" | "llvm.x86.ssse3.pabs.w.128" | "llvm.x86.ssse3.pabs.d.128" => { let a = match args { [a] => a, @@ -571,8 +325,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // llvm.x86.avx2.vperm2i128 // llvm.x86.ssse3.pshuf.b.128 // llvm.x86.avx2.pshuf.b -// llvm.x86.avx2.psrli.w -// llvm.x86.sse2.psrli.w fn llvm_add_sub<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index a81585d4128..d1bfd833cd8 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>, - ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> { + ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> { // TODO(antoyo) None } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index aed4a8f3c85..ddaff36f24b 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -83,6 +83,8 @@ codegen_llvm_unknown_ctarget_feature_prefix = unknown feature specified for `-Ctarget-feature`: `{$feature}` .note = features must begin with a `+` to enable or `-` to disable it +codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo + codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} codegen_llvm_write_ir = failed to write LLVM IR to {$path} diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 863cb7068f8..64587f98b8a 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -340,15 +340,50 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { }; for arg in args { + // Note that the exact number of arguments pushed here is carefully synchronized with + // code all over the place, both in the codegen_llvm and codegen_ssa crates. That's how + // other code then knows which LLVM argument(s) correspond to the n-th Rust argument. let llarg_ty = match &arg.mode { PassMode::Ignore => continue, - PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), + PassMode::Direct(_) => { + // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges), + // and for Scalar ABIs the LLVM type is fully determined by `layout.abi`, + // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for + // aggregates... + if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) { + // This really shouldn't happen, since `immediate_llvm_type` will use + // `layout.fields` to turn this Rust type into an LLVM type. This means all + // sorts of Rust type details leak into the ABI. However wasm sadly *does* + // currently use this mode so we have to allow it -- but we absolutely + // shouldn't let any more targets do that. + // (Also see <https://github.com/rust-lang/rust/issues/115666>.) + assert!( + matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"), + "`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}", + arg.layout, + ); + } + arg.layout.immediate_llvm_type(cx) + } PassMode::Pair(..) => { + // ABI-compatible Rust types have the same `layout.abi` (up to validity ranges), + // so for ScalarPair we can easily be sure that we are generating ABI-compatible + // LLVM IR. + assert!( + matches!(arg.layout.abi, abi::Abi::ScalarPair(..)), + "PassMode::Pair for type {}", + arg.layout.ty + ); llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + assert!(arg.layout.is_unsized()); + // Construct the type of a (wide) pointer to `ty`, and pass its two fields. + // Any two ABI-compatible unsized types have the same metadata type and + // moreover the same metadata value leads to the same dynamic size and + // alignment, so this respects ABI compatibility. let ptr_ty = Ty::new_mut_ptr(cx.tcx, arg.layout.ty); let ptr_layout = cx.layout_of(ptr_ty); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); @@ -360,6 +395,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if *pad_i32 { llargument_tys.push(Reg::i32().llvm_type(cx)); } + // Compute the LLVM type we use for this function from the cast type. + // We assume here that ABI-compatible Rust types have the same cast type. cast.llvm_type(cx) } PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index a82d2c5771a..f33075a8879 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -367,7 +367,7 @@ impl<'a> LlvmArchiveBuilder<'a> { match addition { Addition::File { path, name_in_archive } => { let path = CString::new(path.to_str().unwrap())?; - let name = CString::new(name_in_archive.clone())?; + let name = CString::new(name_in_archive.as_bytes())?; members.push(llvm::LLVMRustArchiveMemberNew( path.as_ptr(), name.as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index b2d28cef899..5cf83b1accb 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -1,4 +1,6 @@ -use crate::back::write::{self, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers}; +use crate::back::write::{ + self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers, +}; use crate::errors::{ DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, }; @@ -120,6 +122,7 @@ fn prepare_lto( info!("adding bitcode from {}", name); match get_bitcode_slice_from_object_data( child.data(&*archive_data).expect("corrupt rlib"), + cgcx, ) { Ok(data) => { let module = SerializedModule::FromRlib(data.to_vec()); @@ -141,10 +144,29 @@ fn prepare_lto( Ok((symbols_below_threshold, upstream_modules)) } -fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFromRlib> { +fn get_bitcode_slice_from_object_data<'a>( + obj: &'a [u8], + cgcx: &CodegenContext<LlvmCodegenBackend>, +) -> Result<&'a [u8], LtoBitcodeFromRlib> { + // We're about to assume the data here is an object file with sections, but if it's raw LLVM IR that + // won't work. Fortunately, if that's what we have we can just return the object directly, so we sniff + // the relevant magic strings here and return. + if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") { + return Ok(obj); + } + // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment name" + // which in the public API for sections gets treated as part of the section name, but internally + // in MachOObjectFile.cpp gets treated separately. + let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,"); let mut len = 0; - let data = - unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) }; + let data = unsafe { + llvm::LLVMRustGetSliceFromObjectDataByName( + obj.as_ptr(), + obj.len(), + section_name.as_ptr(), + &mut len, + ) + }; if !data.is_null() { assert!(len != 0); let bc = unsafe { slice::from_raw_parts(data, len) }; @@ -441,7 +463,7 @@ fn thin_lto( for (i, (name, buffer)) in modules.into_iter().enumerate() { info!("local module: {} - {}", i, name); - let cname = CString::new(name.clone()).unwrap(); + let cname = CString::new(name.as_bytes()).unwrap(); thin_modules.push(llvm::ThinLTOModule { identifier: cname.as_ptr(), data: buffer.data().as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 47cc5bd52e2..1f394a7335c 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -5,13 +5,17 @@ use crate::back::profiling::{ use crate::base; use crate::common; use crate::errors::{ - CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode, + CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression, + WithLlvmError, WriteBytecode, }; use crate::llvm::{self, DiagnosticInfo, PassManager}; use crate::llvm_util; use crate::type_::Type; use crate::LlvmCodegenBackend; use crate::ModuleLlvm; +use llvm::{ + LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols, +}; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::write::{ BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, @@ -216,6 +220,40 @@ pub fn target_machine_factory( let force_emulated_tls = sess.target.force_emulated_tls; + // copy the exe path, followed by path all into one buffer + // null terminating them so we can use them as null terminated strings + let args_cstr_buff = { + let mut args_cstr_buff: Vec<u8> = Vec::new(); + let exe_path = std::env::current_exe().unwrap_or_default(); + let exe_path_str = exe_path.into_os_string().into_string().unwrap_or_default(); + + args_cstr_buff.extend_from_slice(exe_path_str.as_bytes()); + args_cstr_buff.push(0); + + for arg in sess.expanded_args.iter() { + args_cstr_buff.extend_from_slice(arg.as_bytes()); + args_cstr_buff.push(0); + } + + args_cstr_buff + }; + + let debuginfo_compression = sess.opts.debuginfo_compression.to_string(); + match sess.opts.debuginfo_compression { + rustc_session::config::DebugInfoCompression::Zlib => { + if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } { + sess.emit_warning(UnknownCompression { algorithm: "zlib" }); + } + } + rustc_session::config::DebugInfoCompression::Zstd => { + if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } { + sess.emit_warning(UnknownCompression { algorithm: "zstd" }); + } + } + rustc_session::config::DebugInfoCompression::None => {} + }; + let debuginfo_compression = SmallCStr::new(&debuginfo_compression); + Arc::new(move |config: TargetMachineFactoryConfig| { let split_dwarf_file = path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0; @@ -241,7 +279,10 @@ pub fn target_machine_factory( relax_elf_relocations, use_init_array, split_dwarf_file.as_ptr(), + debuginfo_compression.as_ptr(), force_emulated_tls, + args_cstr_buff.as_ptr() as *const c_char, + args_cstr_buff.len(), ) }; @@ -853,6 +894,27 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: asm } +fn target_is_apple(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool { + cgcx.opts.target_triple.triple().contains("-ios") + || cgcx.opts.target_triple.triple().contains("-darwin") + || cgcx.opts.target_triple.triple().contains("-tvos") + || cgcx.opts.target_triple.triple().contains("-watchos") +} + +fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool { + cgcx.opts.target_triple.triple().contains("-aix") +} + +pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str { + if target_is_apple(cgcx) { + "__LLVM,__bitcode\0" + } else if target_is_aix(cgcx) { + ".ipa\0" + } else { + ".llvmbc\0" + } +} + /// Embed the bitcode of an LLVM module in the LLVM module itself. /// /// This is done primarily for iOS where it appears to be standard to compile C @@ -913,11 +975,8 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - let is_aix = cgcx.opts.target_triple.triple().contains("-aix"); - let is_apple = cgcx.opts.target_triple.triple().contains("-ios") - || cgcx.opts.target_triple.triple().contains("-darwin") - || cgcx.opts.target_triple.triple().contains("-tvos") - || cgcx.opts.target_triple.triple().contains("-watchos"); + let is_aix = target_is_aix(cgcx); + let is_apple = target_is_apple(cgcx); if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") @@ -932,13 +991,7 @@ unsafe fn embed_bitcode( ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { - "__LLVM,__bitcode\0" - } else if is_aix { - ".ipa\0" - } else { - ".llvmbc\0" - }; + let section = bitcode_section_name(cgcx); llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index d174a3593b9..5ca2942ac4e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, mir: &Body<'tcx>, - debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, + debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, ) { // Find all scopes with variables defined in them. let variables = if cx.sess().opts.debuginfo == DebugInfo::Full { @@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>( instance: Instance<'tcx>, mir: &Body<'tcx>, variables: &Option<BitSet<SourceScope>>, - debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>, + debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, instantiated: &mut BitSet<SourceScope>, scope: SourceScope, ) { @@ -68,7 +68,7 @@ fn make_mir_scope<'ll, 'tcx>( let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); debug_context.scopes[scope] = DebugScope { file_start_pos: file.start_pos, - file_end_pos: file.end_pos, + file_end_pos: file.end_position(), ..debug_context.scopes[scope] }; instantiated.insert(scope); @@ -86,7 +86,7 @@ fn make_mir_scope<'ll, 'tcx>( let loc = cx.lookup_debug_loc(scope_data.span.lo()); let file_metadata = file_metadata(cx, &loc.file); - let dbg_scope = match scope_data.inlined { + let parent_dbg_scope = match scope_data.inlined { Some((callee, _)) => { // FIXME(eddyb) this would be `self.monomorphize(&callee)` // if this is moved to `rustc_codegen_ssa::mir::debuginfo`. @@ -95,18 +95,22 @@ fn make_mir_scope<'ll, 'tcx>( ty::ParamEnv::reveal_all(), ty::EarlyBinder::bind(callee), ); - let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); - cx.dbg_scope_fn(callee, callee_fn_abi, None) + debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { + let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); + cx.dbg_scope_fn(callee, callee_fn_abi, None) + }) } - None => unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope.dbg_scope, - file_metadata, - loc.line, - loc.col, - ) - }, + None => parent_scope.dbg_scope, + }; + + let dbg_scope = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_dbg_scope, + file_metadata, + loc.line, + loc.col, + ) }; let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { @@ -120,7 +124,7 @@ fn make_mir_scope<'ll, 'tcx>( dbg_scope, inlined_at: inlined_at.or(parent_scope.inlined_at), file_start_pos: loc.file.start_pos, - file_end_pos: loc.file.end_pos, + file_end_pos: loc.file.end_position(), }; instantiated.insert(scope); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 40714a0afe9..52481a1090c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -263,11 +263,11 @@ impl CodegenCx<'_, '_> { pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc { let (file, line, col) = match self.sess().source_map().lookup_line(pos) { Ok(SourceFileAndLine { sf: file, line }) => { - let line_pos = file.lines(|lines| lines[line]); + let line_pos = file.lines()[line]; // Use 1-based indexing. let line = (line + 1) as u32; - let col = (pos - line_pos).to_u32() + 1; + let col = (file.relative_position(pos) - line_pos).to_u32() + 1; (file, line, col) } @@ -292,7 +292,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: &'ll Value, mir: &mir::Body<'tcx>, - ) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> { + ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> { if self.sess().opts.debuginfo == DebugInfo::None { return None; } @@ -304,8 +304,10 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_start_pos: BytePos(0), file_end_pos: BytePos(0), }; - let mut fn_debug_context = - FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) }; + let mut fn_debug_context = FunctionDebugContext { + scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes), + inlined_function_scopes: Default::default(), + }; // Fill in all the scopes, with the information from the MIR body. compute_mir_scopes(self, instance, mir, &mut fn_debug_context); diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index fced6d504d2..264c273ba30 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -226,3 +226,9 @@ pub(crate) struct WriteBytecode<'a> { pub(crate) struct CopyBitcode { pub err: std::io::Error, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_unknown_debuginfo_compression)] +pub struct UnknownCompression { + pub algorithm: &'static str, +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 01cbf7d3b11..2ebfdae39e8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2131,8 +2131,12 @@ extern "C" { RelaxELFRelocations: bool, UseInitArray: bool, SplitDwarfFile: *const c_char, + DebugInfoCompression: *const c_char, ForceEmulatedTls: bool, + ArgsCstrBuff: *const c_char, + ArgsCstrBuffLen: usize, ) -> Option<&'static mut TargetMachine>; + pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); pub fn LLVMRustAddLibraryInfo<'a>( PM: &PassManager<'a>, @@ -2319,6 +2323,12 @@ extern "C" { len: usize, out_len: &mut usize, ) -> *const u8; + pub fn LLVMRustGetSliceFromObjectDataByName( + data: *const u8, + len: usize, + name: *const u8, + out_len: &mut usize, + ) -> *const u8; pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>; pub fn LLVMRustLinkerAdd( @@ -2357,6 +2367,10 @@ extern "C" { pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool; + pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool; + + pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool; + pub fn LLVMRustGetSymbols( buf_ptr: *const u8, buf_len: usize, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f485af00bca..3bf98c46dea 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -343,6 +343,12 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec<String>, + /// Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, /// LLVM optimizations for which we want to print remarks. @@ -1108,6 +1114,7 @@ fn start_executing_work<B: ExtraBackendMethods>( incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(), coordinator_send, + expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), output_filenames: tcx.output_filenames(()).clone(), regular_module_config: regular_config, diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 526c16a59de..ac705a5f35c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,10 +1,12 @@ use crate::traits::*; +use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::Instance; use rustc_middle::ty::Ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; @@ -17,10 +19,13 @@ use super::{FunctionCx, LocalRef}; use std::ops::Range; -pub struct FunctionDebugContext<S, L> { +pub struct FunctionDebugContext<'tcx, S, L> { + /// Maps from source code to the corresponding debug info scope. pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, -} + /// Maps from an inlined function to its debug info declaration. + pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>, +} #[derive(Copy, Clone)] pub enum VariableKind { ArgumentVariable(usize /*index*/), @@ -484,54 +489,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None }; - let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (var_ty, var_kind) = match var.value { + let var_ty = if let Some(ref fragment) = var.composite { + self.monomorphize(fragment.ty) + } else { + match var.value { mir::VarDebugInfoContents::Place(place) => { - let var_ty = self.monomorphized_place_ty(place.as_ref()); - let var_kind = if let Some(arg_index) = var.argument_index - && place.projection.is_empty() - { - let arg_index = arg_index as usize; - if target_is_msvc { - // ScalarPair parameters are spilled to the stack so they need to - // be marked as a `LocalVariable` for MSVC debuggers to visualize - // their data correctly. (See #81894 & #88625) - let var_ty_layout = self.cx.layout_of(var_ty); - if let Abi::ScalarPair(_, _) = var_ty_layout.abi { - VariableKind::LocalVariable - } else { - VariableKind::ArgumentVariable(arg_index) - } - } else { - // FIXME(eddyb) shouldn't `ArgumentVariable` indices be - // offset in closures to account for the hidden environment? - VariableKind::ArgumentVariable(arg_index) - } - } else { - VariableKind::LocalVariable - }; - (var_ty, var_kind) - } - mir::VarDebugInfoContents::Const(c) => { - let ty = self.monomorphize(c.ty()); - (ty, VariableKind::LocalVariable) + self.monomorphized_place_ty(place.as_ref()) } - mir::VarDebugInfoContents::Composite { ty, fragments: _ } => { - let ty = self.monomorphize(ty); - (ty, VariableKind::LocalVariable) + mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()), + } + }; + + let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { + let var_kind = if let Some(arg_index) = var.argument_index + && var.composite.is_none() + && let mir::VarDebugInfoContents::Place(place) = var.value + && place.projection.is_empty() + { + let arg_index = arg_index as usize; + if target_is_msvc { + // ScalarPair parameters are spilled to the stack so they need to + // be marked as a `LocalVariable` for MSVC debuggers to visualize + // their data correctly. (See #81894 & #88625) + let var_ty_layout = self.cx.layout_of(var_ty); + if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + VariableKind::LocalVariable + } else { + VariableKind::ArgumentVariable(arg_index) + } + } else { + // FIXME(eddyb) shouldn't `ArgumentVariable` indices be + // offset in closures to account for the hidden environment? + VariableKind::ArgumentVariable(arg_index) } + } else { + VariableKind::LocalVariable }; self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); + let fragment = if let Some(ref fragment) = var.composite { + let var_layout = self.cx.layout_of(var_ty); + + let mut fragment_start = Size::ZERO; + let mut fragment_layout = var_layout; + + for elem in &fragment.projection { + match *elem { + mir::ProjectionElem::Field(field, _) => { + let i = field.index(); + fragment_start += fragment_layout.fields.offset(i); + fragment_layout = fragment_layout.field(self.cx, i); + } + _ => span_bug!( + var.source_info.span, + "unsupported fragment projection `{:?}`", + elem, + ), + } + } + + if fragment_layout.size == Size::ZERO { + // Fragment is a ZST, so does not represent anything. Avoid generating anything + // as this may conflict with a fragment that covers the entire variable. + continue; + } else if fragment_layout.size == var_layout.size { + // Fragment covers entire variable, so as far as + // DWARF is concerned, it's not really a fragment. + None + } else { + Some(fragment_start..fragment_start + fragment_layout.size) + } + } else { + None + }; + match var.value { mir::VarDebugInfoContents::Place(place) => { per_local[place.local].push(PerLocalVarDebugInfo { name: var.name, source_info: var.source_info, dbg_var, - fragment: None, + fragment, projection: place.projection, }); } @@ -547,51 +587,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, ); - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None); - } - } - } - mir::VarDebugInfoContents::Composite { ty, ref fragments } => { - let var_ty = self.monomorphize(ty); - let var_layout = self.cx.layout_of(var_ty); - for fragment in fragments { - let mut fragment_start = Size::ZERO; - let mut fragment_layout = var_layout; - - for elem in &fragment.projection { - match *elem { - mir::ProjectionElem::Field(field, _) => { - let i = field.index(); - fragment_start += fragment_layout.fields.offset(i); - fragment_layout = fragment_layout.field(self.cx, i); - } - _ => span_bug!( - var.source_info.span, - "unsupported fragment projection `{:?}`", - elem, - ), - } + bx.dbg_var_addr( + dbg_var, + dbg_loc, + base.llval, + Size::ZERO, + &[], + fragment, + ); } - - let place = fragment.contents; - let fragment = if fragment_layout.size == Size::ZERO { - // Fragment is a ZST, so does not represent anything. - continue; - } else if fragment_layout.size == var_layout.size { - // Fragment covers entire variable, so as far as - // DWARF is concerned, it's not really a fragment. - None - } else { - Some(fragment_start..fragment_start + fragment_layout.size) - }; - - per_local[place.local].push(PerLocalVarDebugInfo { - name: var.name, - source_info: var.source_info, - dbg_var, - fragment, - projection: place.projection, - }); } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index bf937c2fc7c..c4408f2db4c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -46,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { mir: &'tcx mir::Body<'tcx>, - debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>, + debug_context: Option<FunctionDebugContext<'tcx, Bx::DIScope, Bx::DILocation>>, llfn: Bx::Function, diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 63fecaf34fd..4acc0ea076c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Function, mir: &mir::Body<'tcx>, - ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>; + ) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>>; // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index fc0dba6b67b..9df3e4030ff 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -79,7 +79,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( intern_const_alloc_recursive(ecx, intern_kind, &ret)?; // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway - debug!("eval_body_using_ecx done: {:?}", *ret); + debug!("eval_body_using_ecx done: {:?}", ret); Ok(ret) } @@ -147,7 +147,7 @@ pub(super) fn op_to_const<'tcx>( // We know `offset` is relative to the allocation, so we can use `into_parts`. let to_const_value = |mplace: &MPlaceTy<'_>| { debug!("to_const_value(mplace: {:?})", mplace); - match mplace.ptr.into_parts() { + match mplace.ptr().into_parts() { (Some(alloc_id), offset) => { let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); ConstValue::ByRef { alloc, offset } @@ -370,7 +370,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( inner = true; } }; - let alloc_id = mplace.ptr.provenance.unwrap(); + let alloc_id = mplace.ptr().provenance.unwrap(); // Validation failed, report an error. This is always a hard error. if let Err(error) = validation { diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index ef31155215a..5327fa5ce39 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -30,7 +30,7 @@ pub(crate) fn const_caller_location( if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { bug!("intern_const_alloc_recursive should not error in this case") } - ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx)) + ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx)) } // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index b15a65d67a3..572d7f9ac2f 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -5,7 +5,7 @@ use crate::const_eval::CanAccessStatics; use crate::interpret::MPlaceTy; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, - MemoryKind, Place, Projectable, Scalar, + MemoryKind, PlaceTy, Projectable, Scalar, }; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; @@ -318,7 +318,7 @@ fn valtree_into_mplace<'tcx>( let len_scalar = Scalar::from_target_usize(len as u64, &tcx); Immediate::ScalarPair( - Scalar::from_maybe_pointer((*pointee_place).ptr, &tcx), + Scalar::from_maybe_pointer(pointee_place.ptr(), &tcx), len_scalar, ) } @@ -383,5 +383,5 @@ fn valtree_into_mplace<'tcx>( } fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) { - trace!("{:?}", ecx.dump_place(Place::Ptr(**place))); + trace!("{:?}", ecx.dump_place(&PlaceTy::from(place.clone()))); } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 1c90ce29b02..db1eaf58621 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -21,8 +21,8 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou use super::{ AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, - MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, PointerArithmetic, Provenance, - Scalar, StackPopJump, + MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, PointerArithmetic, + Projectable, Provenance, Scalar, StackPopJump, }; use crate::errors::{self, ErroneousConstUsed}; use crate::util; @@ -155,17 +155,26 @@ pub enum StackPopCleanup { } /// State of a local variable including a memoized layout -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct LocalState<'tcx, Prov: Provenance = AllocId> { - pub value: LocalValue<Prov>, + value: LocalValue<Prov>, /// Don't modify if `Some`, this is only used to prevent computing the layout twice. /// Avoids computing the layout of locals that are never actually initialized. - pub layout: Cell<Option<TyAndLayout<'tcx>>>, + layout: Cell<Option<TyAndLayout<'tcx>>>, +} + +impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("LocalState") + .field("value", &self.value) + .field("ty", &self.layout.get().map(|l| l.ty)) + .finish() + } } /// Current value of a local variable #[derive(Copy, Clone, Debug)] // Miri debug-prints these -pub enum LocalValue<Prov: Provenance = AllocId> { +pub(super) enum LocalValue<Prov: Provenance = AllocId> { /// This local is not currently alive, and cannot be used at all. Dead, /// A normal, live local. @@ -176,10 +185,27 @@ pub enum LocalValue<Prov: Provenance = AllocId> { Live(Operand<Prov>), } -impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { +impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { + pub fn make_live_uninit(&mut self) { + self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit)); + } + + /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState` + /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type + /// private. + pub fn as_mplace_or_imm( + &self, + ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> { + match self.value { + LocalValue::Dead => None, + LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))), + LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)), + } + } + /// Read the local's value or error if the local is not yet live or not live anymore. #[inline(always)] - pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> { + pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> { match &self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), @@ -189,10 +215,10 @@ impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { /// Overwrite the local. If the local can be overwritten in place, return a reference /// to do so; otherwise return the `MemPlace` to consult instead. /// - /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from - /// anywhere else. You may be invalidating machine invariants if you do! + /// Note: Before calling this, call the `before_access_local_mut` machine hook! You may be + /// invalidating machine invariants otherwise! #[inline(always)] - pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> { + pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> { match &mut self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), @@ -694,7 +720,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, mplace: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { - self.size_and_align_of(&mplace.meta, &mplace.layout) + self.size_and_align_of(&mplace.meta(), &mplace.layout) } #[instrument(skip(self, body, return_place, return_to_block), level = "debug")] @@ -826,7 +852,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .expect("return place should always be live"); let dest = self.frame().return_place.clone(); let err = self.copy_op(&op, &dest, /*allow_transmute*/ true); - trace!("return value: {:?}", self.dump_place(*dest)); + trace!("return value: {:?}", self.dump_place(&dest)); // We delay actually short-circuiting on this error until *after* the stack frame is // popped, since we want this error to be attributed to the caller, whose type defines // this transmute. @@ -974,7 +1000,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized. let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?; - Operand::Indirect(*dest_place) + Operand::Indirect(*dest_place.mplace()) } else { assert!(!meta.has_meta()); // we're dropping the metadata // Just make this an efficient immediate. @@ -1068,8 +1094,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[must_use] - pub fn dump_place(&self, place: Place<M::Provenance>) -> PlacePrinter<'_, 'mir, 'tcx, M> { - PlacePrinter { ecx: self, place } + pub fn dump_place( + &self, + place: &PlaceTy<'tcx, M::Provenance>, + ) -> PlacePrinter<'_, 'mir, 'tcx, M> { + PlacePrinter { ecx: self, place: *place.place() } } #[must_use] diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 42950d1ffb0..562f7c610fd 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -25,7 +25,7 @@ use rustc_ast::Mutability; use super::{ AllocId, Allocation, ConstAllocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, - ValueVisitor, + Projectable, ValueVisitor, }; use crate::const_eval; use crate::errors::{DanglingPtrInFinal, UnsupportedUntypedPointer}; @@ -177,7 +177,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory if let ty::Dynamic(_, _, ty::Dyn) = tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() { - let ptr = mplace.meta.unwrap_meta().to_pointer(&tcx)?; + let ptr = mplace.meta().unwrap_meta().to_pointer(&tcx)?; if let Some(alloc_id) = ptr.provenance { // Explicitly choose const mode here, since vtables are immutable, even // if the reference of the fat pointer is mutable. @@ -191,7 +191,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory } // Check if we have encountered this pointer+layout combination before. // Only recurse for allocation-backed pointers. - if let Some(alloc_id) = mplace.ptr.provenance { + if let Some(alloc_id) = mplace.ptr().provenance { // Compute the mode with which we intern this. Our goal here is to make as many // statics as we can immutable so they can be placed in read-only memory by LLVM. let ref_mode = match self.mode { @@ -267,7 +267,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory // If there is no provenance in this allocation, it does not contain references // that point to another allocation, and we can avoid the interning walk. - if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? { + if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr(), size, align)? { if !alloc.has_provenance() { return Ok(false); } @@ -353,7 +353,7 @@ pub fn intern_const_alloc_recursive< leftover_allocations, // The outermost allocation must exist, because we allocated it with // `Memory::allocate`. - ret.ptr.provenance.unwrap(), + ret.ptr().provenance.unwrap(), base_intern_mode, Some(ret.layout.ty), ); @@ -466,7 +466,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> ) -> InterpResult<'tcx, ConstAllocation<'tcx>> { let dest = self.allocate(layout, MemoryKind::Stack)?; f(self, &dest.clone().into())?; - let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1; + let mut alloc = self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap()).unwrap().1; alloc.mutability = Mutability::Not; Ok(self.tcx.mk_const_alloc(alloc)) } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d6ca6fe73a6..7feed74ceae 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -466,7 +466,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => return Ok(false), } - trace!("{:?}", self.dump_place(**dest)); + trace!("{:?}", self.dump_place(dest)); self.go_to_block(ret); Ok(true) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 91c07d73fce..9fda6b037c8 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment; use super::{ AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx, - InterpResult, MPlaceTy, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, + InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, Scalar, }; /// Data returned by Machine::stack_pop, @@ -237,22 +237,22 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { right: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>; - /// Called to write the specified `local` from the `frame`. + /// Called before writing the specified `local` of the `frame`. /// Since writing a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. /// /// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut /// Frame`. - #[inline] - fn access_local_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - frame: usize, - local: mir::Local, - ) -> InterpResult<'tcx, &'a mut Operand<Self::Provenance>> + #[inline(always)] + fn before_access_local_mut<'a>( + _ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + _frame: usize, + _local: mir::Local, + ) -> InterpResult<'tcx> where 'tcx: 'mir, { - ecx.stack_mut()[frame].locals[local].access_mut() + Ok(()) } /// Called before a basic block terminator is executed. diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index b0b553c45d4..69eb22028fa 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -20,16 +20,21 @@ mod visitor; pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here -pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup}; +pub use self::eval_context::{Frame, FrameInfo, InterpCx, StackPopCleanup}; pub use self::intern::{intern_const_alloc_recursive, InternKind}; pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; -pub use self::operand::{ImmTy, Immediate, OpTy, Operand, Readable}; -pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy, Writeable}; +pub use self::operand::{ImmTy, Immediate, OpTy, Readable}; +pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; pub use self::projection::Projectable; pub use self::terminator::FnArg; pub use self::validity::{CtfeValidationMode, RefTracking}; pub use self::visitor::ValueVisitor; +use self::{ + operand::Operand, + place::{MemPlace, Place}, +}; + pub(crate) use self::intrinsics::eval_nullary_intrinsic; use eval_context::{from_known_layout, mir_assign_valid_types}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 8d948eb10a7..26dd9098bb5 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -88,7 +88,7 @@ impl<Prov: Provenance> Immediate<Prov> { // ScalarPair needs a type to interpret, so we often have an immediate and a type together // as input for binary and cast operations. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ImmTy<'tcx, Prov: Provenance = AllocId> { imm: Immediate<Prov>, pub layout: TyAndLayout<'tcx>, @@ -134,6 +134,12 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> { } } +impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ImmTy").field("imm", &self.imm).field("ty", &self.layout.ty).finish() + } +} + impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { type Target = Immediate<Prov>; #[inline(always)] @@ -142,51 +148,6 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { } } -/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, -/// or still in memory. The latter is an optimization, to delay reading that chunk of -/// memory and to avoid having to store arbitrary-sized data here. -#[derive(Copy, Clone, Debug)] -pub enum Operand<Prov: Provenance = AllocId> { - Immediate(Immediate<Prov>), - Indirect(MemPlace<Prov>), -} - -#[derive(Clone, Debug)] -pub struct OpTy<'tcx, Prov: Provenance = AllocId> { - op: Operand<Prov>, // Keep this private; it helps enforce invariants. - pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for an `OpTy`! - /// `None` means "alignment does not matter since this is a by-value operand" - /// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`. - /// Also CTFE ignores alignment anyway, so this is for Miri only. - pub align: Option<Align>, -} - -impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> { - type Target = Operand<Prov>; - #[inline(always)] - fn deref(&self) -> &Operand<Prov> { - &self.op - } -} - -impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { - #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) } - } -} - -impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> { - #[inline(always)] - fn from(val: ImmTy<'tcx, Prov>) -> Self { - OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } - } -} - impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self { @@ -319,7 +280,61 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { } } -impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { +/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, +/// or still in memory. The latter is an optimization, to delay reading that chunk of +/// memory and to avoid having to store arbitrary-sized data here. +#[derive(Copy, Clone, Debug)] +pub(super) enum Operand<Prov: Provenance = AllocId> { + Immediate(Immediate<Prov>), + Indirect(MemPlace<Prov>), +} + +#[derive(Clone)] +pub struct OpTy<'tcx, Prov: Provenance = AllocId> { + op: Operand<Prov>, // Keep this private; it helps enforce invariants. + pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for an `OpTy`! + /// `None` means "alignment does not matter since this is a by-value operand" + /// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`. + /// Also CTFE ignores alignment anyway, so this is for Miri only. + pub align: Option<Align>, +} + +impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("OpTy").field("op", &self.op).field("ty", &self.layout.ty).finish() + } +} + +impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> { + #[inline(always)] + fn from(val: ImmTy<'tcx, Prov>) -> Self { + OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } + } +} + +impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { + #[inline(always)] + fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { + OpTy { + op: Operand::Indirect(*mplace.mplace()), + layout: mplace.layout, + align: Some(mplace.align), + } + } +} + +impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { + #[inline(always)] + pub(super) fn op(&self) -> &Operand<Prov> { + &self.op + } +} + +impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { self.layout @@ -328,7 +343,7 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Pr #[inline] fn meta(&self) -> MemPlaceMeta<Prov> { match self.as_mplace_or_imm() { - Left(mplace) => mplace.meta, + Left(mplace) => mplace.meta(), Right(_) => { debug_assert!(self.layout.is_sized(), "unsized immediates are not a thing"); MemPlaceMeta::None @@ -362,18 +377,19 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for OpTy<'tcx, Pr } } +/// The `Readable` trait describes interpreter values that one can read from. pub trait Readable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>>; } -impl<'tcx, Prov: Provenance + 'static> Readable<'tcx, Prov> for OpTy<'tcx, Prov> { +impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for OpTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> { self.as_mplace_or_imm() } } -impl<'tcx, Prov: Provenance + 'static> Readable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { +impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> { Left(self.clone()) @@ -535,7 +551,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Turn the wide MPlace into a string (must already be dereferenced!) pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; - let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len))?; + let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?; let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; Ok(str) } @@ -630,7 +646,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { op = self.project(&op, elem)? } - trace!("eval_place_to_op: got {:?}", *op); + trace!("eval_place_to_op: got {:?}", op); // Sanity-check the type we ended up with. debug_assert!( mir_assign_valid_types( @@ -673,7 +689,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_mir_constant(&c, Some(constant.span), layout)? } }; - trace!("{:?}: {:?}", mir_op, *op); + trace!("{:?}: {:?}", mir_op, op); Ok(op) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 65c5cd656cb..90f2b470179 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -51,7 +51,7 @@ impl<Prov: Provenance> MemPlaceMeta<Prov> { } #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] -pub struct MemPlace<Prov: Provenance = AllocId> { +pub(super) struct MemPlace<Prov: Provenance = AllocId> { /// The pointer can be a pure integer, with the `None` provenance. pub ptr: Pointer<Option<Prov>>, /// Metadata for unsized places. Interpretation is up to the type. @@ -60,68 +60,6 @@ pub struct MemPlace<Prov: Provenance = AllocId> { pub meta: MemPlaceMeta<Prov>, } -/// A MemPlace with its layout. Constructing it is only possible in this module. -#[derive(Clone, Hash, Eq, PartialEq, Debug)] -pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { - mplace: MemPlace<Prov>, - pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `MPlaceTy`! - pub align: Align, -} - -impl<'tcx, Prov: Provenance> std::ops::Deref for MPlaceTy<'tcx, Prov> { - type Target = MemPlace<Prov>; - #[inline(always)] - fn deref(&self) -> &MemPlace<Prov> { - &self.mplace - } -} - -#[derive(Copy, Clone, Debug)] -pub enum Place<Prov: Provenance = AllocId> { - /// A place referring to a value allocated in the `Memory` system. - Ptr(MemPlace<Prov>), - - /// To support alloc-free locals, we are able to write directly to a local. The offset indicates - /// where in the local this place is located; if it is `None`, no projection has been applied. - /// Such projections are meaningful even if the offset is 0, since they can change layouts. - /// (Without that optimization, we'd just always be a `MemPlace`.) - /// Note that this only stores the frame index, not the thread this frame belongs to -- that is - /// implicit. This means a `Place` must never be moved across interpreter thread boundaries! - /// - /// This variant shall not be used for unsized types -- those must always live in memory. - Local { frame: usize, local: mir::Local, offset: Option<Size> }, -} - -#[derive(Clone, Debug)] -pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { - place: Place<Prov>, // Keep this private; it helps enforce invariants. - pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `PlaceTy`! - pub align: Align, -} - -impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> { - type Target = Place<Prov>; - #[inline(always)] - fn deref(&self) -> &Place<Prov> { - &self.place - } -} - -impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { - #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align } - } -} - impl<Prov: Provenance> MemPlace<Prov> { #[inline(always)] pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self { @@ -165,6 +103,27 @@ impl<Prov: Provenance> MemPlace<Prov> { } } +/// A MemPlace with its layout. Constructing it is only possible in this module. +#[derive(Clone, Hash, Eq, PartialEq)] +pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { + mplace: MemPlace<Prov>, + pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for a `MPlaceTy`! + pub align: Align, +} + +impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MPlaceTy") + .field("mplace", &self.mplace) + .field("ty", &self.layout.ty) + .finish() + } +} + impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { /// Produces a MemPlace that works for ZST but nothing else. /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you @@ -194,9 +153,29 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { align: layout.align.abi, } } + + /// Adjust the provenance of the main pointer (metadata is unaffected). + pub fn map_provenance(self, f: impl FnOnce(Option<Prov>) -> Option<Prov>) -> Self { + MPlaceTy { mplace: self.mplace.map_provenance(f), ..self } + } + + #[inline(always)] + pub(super) fn mplace(&self) -> &MemPlace<Prov> { + &self.mplace + } + + #[inline(always)] + pub fn ptr(&self) -> Pointer<Option<Prov>> { + self.mplace.ptr + } + + #[inline(always)] + pub fn to_ref(&self, cx: &impl HasDataLayout) -> Immediate<Prov> { + self.mplace.to_ref(cx) + } } -impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { +impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { self.layout @@ -204,7 +183,7 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx #[inline(always)] fn meta(&self) -> MemPlaceMeta<Prov> { - self.meta + self.mplace.meta } fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( @@ -229,7 +208,76 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for MPlaceTy<'tcx } } -impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { +#[derive(Copy, Clone, Debug)] +pub(super) enum Place<Prov: Provenance = AllocId> { + /// A place referring to a value allocated in the `Memory` system. + Ptr(MemPlace<Prov>), + + /// To support alloc-free locals, we are able to write directly to a local. The offset indicates + /// where in the local this place is located; if it is `None`, no projection has been applied. + /// Such projections are meaningful even if the offset is 0, since they can change layouts. + /// (Without that optimization, we'd just always be a `MemPlace`.) + /// Note that this only stores the frame index, not the thread this frame belongs to -- that is + /// implicit. This means a `Place` must never be moved across interpreter thread boundaries! + /// + /// This variant shall not be used for unsized types -- those must always live in memory. + Local { frame: usize, local: mir::Local, offset: Option<Size> }, +} + +#[derive(Clone)] +pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { + place: Place<Prov>, // Keep this private; it helps enforce invariants. + pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for a `PlaceTy`! + pub align: Align, +} + +impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PlaceTy").field("place", &self.place).field("ty", &self.layout.ty).finish() + } +} + +impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { + #[inline(always)] + fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { + PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout, align: mplace.align } + } +} + +impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { + #[inline(always)] + pub(super) fn place(&self) -> &Place<Prov> { + &self.place + } + + /// A place is either an mplace or some local. + #[inline(always)] + pub fn as_mplace_or_local( + &self, + ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>)> { + match self.place { + Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout, align: self.align }), + Place::Local { frame, local, offset } => Right((frame, local, offset)), + } + } + + #[inline(always)] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) + pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { + self.as_mplace_or_local().left().unwrap_or_else(|| { + bug!( + "PlaceTy of type {} was a local when it was expected to be an MPlace", + self.layout.ty + ) + }) + } +} + +impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { self.layout @@ -238,7 +286,7 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for PlaceTy<'tcx, #[inline] fn meta(&self) -> MemPlaceMeta<Prov> { match self.as_mplace_or_local() { - Left(mplace) => mplace.meta, + Left(mplace) => mplace.meta(), Right(_) => { debug_assert!(self.layout.is_sized(), "unsized locals should live in memory"); MemPlaceMeta::None @@ -286,11 +334,11 @@ impl<'tcx, Prov: Provenance + 'static> Projectable<'tcx, Prov> for PlaceTy<'tcx, impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[inline(always)] pub fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> { - match **self { + match self.op() { Operand::Indirect(mplace) => { - Left(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() }) + Left(MPlaceTy { mplace: *mplace, layout: self.layout, align: self.align.unwrap() }) } - Operand::Immediate(imm) => Right(ImmTy::from_immediate(imm, self.layout)), + Operand::Immediate(imm) => Right(ImmTy::from_immediate(*imm, self.layout)), } } @@ -306,30 +354,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { } } -impl<'tcx, Prov: Provenance + 'static> PlaceTy<'tcx, Prov> { - /// A place is either an mplace or some local. - #[inline(always)] - pub fn as_mplace_or_local( - &self, - ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>)> { - match **self { - Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout, align: self.align }), - Place::Local { frame, local, offset } => Right((frame, local, offset)), - } - } - - #[inline(always)] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> { - self.as_mplace_or_local().left().unwrap_or_else(|| { - bug!( - "PlaceTy of type {} was a local when it was expected to be an MPlace", - self.layout.ty - ) - }) - } -} - +/// The `Weiteable` trait describes interpreter values that can be written to. pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { fn as_mplace_or_local( &self, @@ -341,7 +366,7 @@ pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>>; } -impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { +impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_local( &self, @@ -360,7 +385,7 @@ impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for PlaceTy<'tcx, P } } -impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { +impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_local( &self, @@ -381,7 +406,7 @@ impl<'tcx, Prov: Provenance + 'static> Writeable<'tcx, Prov> for MPlaceTy<'tcx, // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> where - Prov: Provenance + 'static, + Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>, { /// Take a value, which represents a (thin or wide) reference, and make it a place. @@ -415,7 +440,7 @@ where &self, mplace: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let imm = mplace.to_ref(self); + let imm = mplace.mplace.to_ref(self); let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?; Ok(ImmTy::from_immediate(imm, layout)) } @@ -449,7 +474,7 @@ where .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); // Due to packed places, only `mplace.align` matters. - self.get_ptr_alloc(mplace.ptr, size, mplace.align) + self.get_ptr_alloc(mplace.ptr(), size, mplace.align) } #[inline] @@ -462,7 +487,7 @@ where .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); // Due to packed places, only `mplace.align` matters. - self.get_ptr_alloc_mut(mplace.ptr, size, mplace.align) + self.get_ptr_alloc_mut(mplace.ptr(), size, mplace.align) } /// Check if this mplace is dereferenceable and sufficiently aligned. @@ -473,7 +498,7 @@ where // Due to packed places, only `mplace.align` matters. let align = if M::enforce_alignment(self).should_check() { mplace.align } else { Align::ONE }; - self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?; + self.check_ptr_access_align(mplace.ptr(), size, align, CheckInAllocMsg::DerefTest)?; Ok(()) } @@ -542,7 +567,7 @@ where place = self.project(&place, elem)? } - trace!("{:?}", self.dump_place(place.place)); + trace!("{:?}", self.dump_place(&place)); // Sanity-check the type we ended up with. debug_assert!( mir_assign_valid_types( @@ -618,7 +643,8 @@ where // just fall back to the indirect path. dest.force_mplace(self)? } else { - match M::access_local_mut(self, frame, local)? { + M::before_access_local_mut(self, frame, local)?; + match self.stack_mut()[frame].locals[local].access_mut()? { Operand::Immediate(local_val) => { // Local can be updated in-place. *local_val = src; @@ -738,7 +764,8 @@ where // FIXME: share the logic with `write_immediate_no_validate`. dest.force_mplace(self)? } else { - match M::access_local_mut(self, frame, local)? { + M::before_access_local_mut(self, frame, local)?; + match self.stack_mut()[frame].locals[local].access_mut()? { Operand::Immediate(local) => { *local = Immediate::Uninit; return Ok(()); @@ -769,6 +796,13 @@ where dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, ) -> InterpResult<'tcx> { + // Generally for transmutation, data must be valid both at the old and new type. + // But if the types are the same, the 2nd validation below suffices. + if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { + self.validate_operand(&src.to_op(self)?)?; + } + + // Do the actual copy. self.copy_op_no_validate(src, dest, allow_transmute)?; if M::enforce_validity(self, dest.layout()) { @@ -832,7 +866,7 @@ where *src_val, src.layout(), dest_mem.align, - *dest_mem, + dest_mem.mplace, ) }; } @@ -859,7 +893,12 @@ where // (Or as the `Assign` docs put it, assignments "not producing primitives" must be // non-overlapping.) self.mem_copy( - src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ true, + src.ptr(), + src.align, + dest.ptr(), + dest.align, + dest_size, + /*nonoverlapping*/ true, ) } @@ -874,7 +913,8 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let mplace = match place.place { Place::Local { frame, local, offset } => { - let whole_local = match M::access_local_mut(self, frame, local)? { + M::before_access_local_mut(self, frame, local)?; + let whole_local = match self.stack_mut()[frame].locals[local].access_mut()? { &mut Operand::Immediate(local_val) => { // We need to make an allocation. @@ -894,16 +934,16 @@ where local_val, local_layout, local_layout.align.abi, - *mplace, + mplace.mplace, )?; } M::after_local_allocated(self, frame, local, &mplace)?; // Now we can call `access_mut` again, asserting it goes well, and actually // overwrite things. This points to the entire allocation, not just the part // the place refers to, i.e. we do this before we apply `offset`. - *M::access_local_mut(self, frame, local).unwrap() = - Operand::Indirect(*mplace); - *mplace + *self.stack_mut()[frame].locals[local].access_mut().unwrap() = + Operand::Indirect(mplace.mplace); + mplace.mplace } &mut Operand::Indirect(mplace) => mplace, // this already was an indirect local }; @@ -1011,12 +1051,12 @@ where matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)), "`unpack_dyn_trait` only makes sense on `dyn*` types" ); - let vtable = mplace.meta.unwrap_meta().to_pointer(self)?; + let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; let (ty, _) = self.get_ptr_vtable(vtable)?; let layout = self.layout_of(ty)?; let mplace = MPlaceTy { - mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, + mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout, align: layout.align.abi, }; diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index c69321d109e..6c720ac4a57 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -89,7 +89,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { } /// A type representing iteration over the elements of an array. -pub struct ArrayIterator<'tcx, 'a, Prov: Provenance + 'static, P: Projectable<'tcx, Prov>> { +pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> { base: &'a P, range: Range<u64>, stride: Size, @@ -97,9 +97,7 @@ pub struct ArrayIterator<'tcx, 'a, Prov: Provenance + 'static, P: Projectable<'t _phantom: PhantomData<Prov>, // otherwise it says `Prov` is never used... } -impl<'tcx, 'a, Prov: Provenance + 'static, P: Projectable<'tcx, Prov>> - ArrayIterator<'tcx, 'a, Prov, P> -{ +impl<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'tcx, 'a, Prov, P> { /// Should be the same `ecx` on each call, and match the one used to create the iterator. pub fn next<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &mut self, @@ -113,7 +111,7 @@ impl<'tcx, 'a, Prov: Provenance + 'static, P: Projectable<'tcx, Prov>> // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> where - Prov: Provenance + 'static, + Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>, { /// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 0740894a4ff..57f99bd8f61 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -204,7 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // avoid writing each operand individually and instead just make many copies // of the first element. let elem_size = first.layout.size; - let first_ptr = first.ptr; + let first_ptr = first.ptr(); let rest_ptr = first_ptr.offset(elem_size, self)?; // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as // that place might be more aligned than its type mandates (a `u8` array could @@ -305,7 +305,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - trace!("{:?}", self.dump_place(*dest)); + trace!("{:?}", self.dump_place(&dest)); Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index a016bfa5cf8..eb4673c0edc 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -10,7 +10,7 @@ use rustc_middle::{ Instance, Ty, }, }; -use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode}; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::abi::{self, FieldIdx}; use rustc_target::spec::abi::Abi; @@ -254,6 +254,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } /// Find the wrapped inner type of a transparent wrapper. + /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field"). fn unfold_transparent(&self, layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx> { match layout.ty.kind() { ty::Adt(adt_def, _) if adt_def.repr().transparent() => { @@ -263,11 +264,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let field = layout.field(self, idx); if field.is_1zst() { None } else { Some(field) } }); - let Some(first) = non_1zst_fields.next() else { - // All fields are 1-ZST, so this is basically the same as `()`. - // (We still also compare the `PassMode`, so if this target does something strange with 1-ZST there, we'll know.) - return self.layout_of(self.tcx.types.unit).unwrap(); - }; + let first = non_1zst_fields.next().expect("`unfold_transparent` called on 1-ZST"); assert!( non_1zst_fields.next().is_none(), "more than one non-1-ZST field in a transparent type" @@ -289,50 +286,34 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_layout: TyAndLayout<'tcx>, callee_layout: TyAndLayout<'tcx>, ) -> bool { - fn primitive_abi_compat(a1: abi::Primitive, a2: abi::Primitive) -> bool { - match (a1, a2) { - // For integers, ignore the sign. - (abi::Primitive::Int(int_ty1, _sign1), abi::Primitive::Int(int_ty2, _sign2)) => { - int_ty1 == int_ty2 - } - // For everything else we require full equality. - _ => a1 == a2, - } - } - if caller_layout.ty == callee_layout.ty { // Fast path: equal types are definitely compatible. return true; } - match (caller_layout.abi, callee_layout.abi) { - // If both sides have Scalar/Vector/ScalarPair ABI, we can easily directly compare them. - // Different valid ranges are okay (the validity check will complain if this leads to - // invalid transmutes). - (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => { - primitive_abi_compat(caller.primitive(), callee.primitive()) + match caller_layout.abi { + // For Scalar/Vector/ScalarPair ABI, we directly compare them. + // NOTE: this is *not* a stable guarantee! It just reflects a property of our current + // ABIs. It's also fragile; the same pair of types might be considered ABI-compatible + // when used directly by-value but not considered compatible as a struct field or array + // element. + abi::Abi::Scalar(..) | abi::Abi::ScalarPair(..) | abi::Abi::Vector { .. } => { + caller_layout.abi.eq_up_to_validity(&callee_layout.abi) } - ( - abi::Abi::Vector { element: caller_element, count: caller_count }, - abi::Abi::Vector { element: callee_element, count: callee_count }, - ) => { - primitive_abi_compat(caller_element.primitive(), callee_element.primitive()) - && caller_count == callee_count - } - (abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2)) => { - primitive_abi_compat(caller1.primitive(), callee1.primitive()) - && primitive_abi_compat(caller2.primitive(), callee2.primitive()) - } - (abi::Abi::Aggregate { .. }, abi::Abi::Aggregate { .. }) => { - // Aggregates are compatible only if they newtype-wrap the same type. + _ => { + // Everything else is compatible only if they newtype-wrap the same type, or if they are both 1-ZST. + // (The latter part is needed to ensure e.g. that `struct Zst` is compatible with `struct Wrap((), Zst)`.) // This is conservative, but also means that our check isn't quite so heavily dependent on the `PassMode`, // which means having ABI-compatibility on one target is much more likely to imply compatibility for other targets. - self.unfold_transparent(caller_layout).ty - == self.unfold_transparent(callee_layout).ty + if caller_layout.is_1zst() || callee_layout.is_1zst() { + // If either is a 1-ZST, both must be. + caller_layout.is_1zst() && callee_layout.is_1zst() + } else { + // Neither is a 1-ZST, so we can check what they are wrapping. + self.unfold_transparent(caller_layout).ty + == self.unfold_transparent(callee_layout).ty + } } - // What remains is `Abi::Uninhabited` (which can never be passed anyway) and - // mismatching ABIs, that should all be rejected. - _ => false, } } @@ -341,40 +322,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, ) -> bool { - // When comparing the PassMode, we have to be smart about comparing the attributes. - let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| { - // There's only one regular attribute that matters for the call ABI: InReg. - // Everything else is things like noalias, dereferenceable, nonnull, ... - // (This also applies to pointee_size, pointee_align.) - if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg) - { - return false; - } - // We also compare the sign extension mode -- this could let the callee make assumptions - // about bits that conceptually were not even passed. - if a1.arg_ext != a2.arg_ext { - return false; - } - return true; - }; - let mode_compat = || match (&caller_abi.mode, &callee_abi.mode) { - (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type - (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2), - (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => { - arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2) - } - (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1 == c2 && pad1 == pad2, - ( - PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, - PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, - ) => arg_attr_compat(a1, a2) && s1 == s2, - ( - PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 }, - PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 }, - ) => arg_attr_compat(a1, a2) && arg_attr_compat(e1, e2) && s1 == s2, - _ => false, - }; - // Ideally `PassMode` would capture everything there is about argument passing, but that is // not the case: in `FnAbi::llvm_type`, also parts of the layout and type information are // used. So we need to check that *both* sufficiently agree to ensures the arguments are @@ -382,13 +329,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // For instance, `layout_compat` is needed to reject `i32` vs `f32`, which is not reflected // in `PassMode`. `mode_compat` is needed to reject `u8` vs `bool`, which have the same // `abi::Primitive` but different `arg_ext`. - if self.layout_compat(caller_abi.layout, callee_abi.layout) && mode_compat() { - // Something went very wrong if our checks don't even imply that the layout is the same. - assert!( - caller_abi.layout.size == callee_abi.layout.size - && caller_abi.layout.align.abi == callee_abi.layout.align.abi - && caller_abi.layout.is_sized() == callee_abi.layout.is_sized() - ); + if self.layout_compat(caller_abi.layout, callee_abi.layout) + && caller_abi.mode.eq_abi(&callee_abi.mode) + { + // Something went very wrong if our checks don't imply layout ABI compatibility. + assert!(caller_abi.layout.eq_abi(&callee_abi.layout)); return true; } else { trace!( @@ -794,7 +739,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_ub_custom!(fluent::const_eval_dyn_star_call_vtable_mismatch); } - (vptr, dyn_ty, recv.ptr) + (vptr, dyn_ty, recv.ptr()) } else { // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. // (For that reason we also cannot use `unpack_dyn_trait`.) @@ -811,7 +756,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(receiver_place.layout.is_unsized()); // Get the required information from the vtable. - let vptr = receiver_place.meta.unwrap_meta().to_pointer(self)?; + let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; if dyn_trait != data.principal() { throw_ub_custom!(fluent::const_eval_dyn_call_vtable_mismatch); @@ -820,7 +765,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // It might be surprising that we use a pointer as the receiver even if this // is a by-val case; this works because by-val passing of an unsized `dyn // Trait` to a function is actually desugared to a pointer. - (vptr, dyn_ty, receiver_place.ptr) + (vptr, dyn_ty, receiver_place.ptr()) }; // Now determine the actual method to call. We can do that in two different ways and diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 0d08d6be919..8e2b35fd5b6 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -360,7 +360,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Handle wide pointers. // Check metadata early, for better diagnostics if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; + self.check_wide_ptr_meta(place.meta(), place.layout)?; } // Make sure this is dereferenceable and all. let size_and_align = try_validation!( @@ -379,7 +379,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. try_validation!( self.ecx.check_ptr_access_align( - place.ptr, + place.ptr(), size, align, CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message @@ -414,7 +414,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. - if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) { + if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) { // Let's see what kind of memory this points to. let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id); match alloc_kind { @@ -521,7 +521,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ExpectedKind::RawPtr)?)?; if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; + self.check_wide_ptr_meta(place.meta(), place.layout)?; } Ok(true) } @@ -739,7 +739,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> let mplace = op.assert_mem_place(); // strings are unsized and hence never immediate let len = mplace.len(self.ecx)?; try_validation!( - self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len)), + self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len)), self.path, Ub(InvalidUninitBytes(..)) => Uninit { expected: ExpectedKind::Str }, Unsup(ReadPointerAsInt(_)) => PointerAsInt { expected: ExpectedKind::Str } @@ -789,7 +789,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // to reject those pointers, we just do not have the machinery to // talk about parts of a pointer. // We also accept uninit, for consistency with the slow path. - let alloc = self.ecx.get_ptr_alloc(mplace.ptr, size, mplace.align)?.expect("we already excluded size 0"); + let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size, mplace.align)?.expect("we already excluded size 0"); match alloc.get_bytes_strip_provenance() { // In the happy case, we needn't check anything else. diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 770c3f7f02c..2f5f2ad6534 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -6,13 +6,7 @@ use rustc_index::IndexVec; use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{ - traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, - MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef, - ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, - Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo, - VarDebugInfoContents, START_BLOCK, -}; +use rustc_middle::mir::*; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -757,37 +751,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { - let check_place = |this: &mut Self, place: Place<'_>| { - if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { - this.fail( + if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite { + if ty.is_union() || ty.is_enum() { + self.fail( START_BLOCK.start_location(), - format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name), ); } - }; + if projection.is_empty() { + self.fail( + START_BLOCK.start_location(), + format!("invalid empty projection in debuginfo for {:?}", debuginfo.name), + ); + } + if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { + self.fail( + START_BLOCK.start_location(), + format!( + "illegal projection {:?} in debuginfo for {:?}", + projection, debuginfo.name + ), + ); + } + } match debuginfo.value { VarDebugInfoContents::Const(_) => {} VarDebugInfoContents::Place(place) => { - check_place(self, place); - } - VarDebugInfoContents::Composite { ty, ref fragments } => { - for f in fragments { - check_place(self, f.contents); - if ty.is_union() || ty.is_enum() { - self.fail( - START_BLOCK.start_location(), - format!("invalid type {ty:?} for composite debuginfo"), - ); - } - if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { - self.fail( - START_BLOCK.start_location(), - format!( - "illegal projection {:?} in debuginfo for {:?}", - f.projection, debuginfo.name - ), - ); - } + if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { + self.fail( + START_BLOCK.start_location(), + format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + ); } } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 2d1970791ca..e9e0690f07d 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -54,7 +54,7 @@ fn might_permit_raw_init_strict<'tcx>( if kind == ValidityRequirement::Zero { cx.write_bytes_ptr( - allocated.ptr, + allocated.ptr(), std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()), ) .expect("failed to write bytes for zero valid check"); diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 0f769c1f3bf..29516fffd6a 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,7 +1,7 @@ use crate::fx::{FxHashMap, FxHasher}; #[cfg(parallel_compiler)] use crate::sync::{is_dyn_thread_safe, CacheAligned}; -use crate::sync::{Lock, LockGuard}; +use crate::sync::{Lock, LockGuard, Mode}; #[cfg(parallel_compiler)] use itertools::Either; use std::borrow::Borrow; @@ -73,6 +73,56 @@ impl<T> Sharded<T> { } } + /// The shard is selected by hashing `val` with `FxHasher`. + #[inline] + #[track_caller] + pub fn lock_shard_by_value<K: Hash + ?Sized>(&self, _val: &K) -> LockGuard<'_, T> { + match self { + Self::Single(single) => { + // Syncronization is disabled so use the `lock_assume_no_sync` method optimized + // for that case. + + // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus + // `might_be_dyn_thread_safe` was also false. + unsafe { single.lock_assume(Mode::NoSync) } + } + #[cfg(parallel_compiler)] + Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)), + } + } + + #[inline] + #[track_caller] + pub fn lock_shard_by_hash(&self, hash: u64) -> LockGuard<'_, T> { + self.lock_shard_by_index(get_shard_hash(hash)) + } + + #[inline] + #[track_caller] + pub fn lock_shard_by_index(&self, _i: usize) -> LockGuard<'_, T> { + match self { + Self::Single(single) => { + // Syncronization is disabled so use the `lock_assume_no_sync` method optimized + // for that case. + + // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus + // `might_be_dyn_thread_safe` was also false. + unsafe { single.lock_assume(Mode::NoSync) } + } + #[cfg(parallel_compiler)] + Self::Shards(shards) => { + // Syncronization is enabled so use the `lock_assume_sync` method optimized + // for that case. + + // SAFETY (get_unchecked): The index gets ANDed with the shard mask, ensuring it is + // always inbounds. + // SAFETY (lock_assume_sync): We know `is_dyn_thread_safe` was true when creating + // the lock thus `might_be_dyn_thread_safe` was also true. + unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Mode::Sync) } + } + } + } + #[inline] pub fn lock_shards(&self) -> impl Iterator<Item = LockGuard<'_, T>> { match self { @@ -124,7 +174,7 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> { Q: Hash + Eq, { let hash = make_hash(value); - let mut shard = self.get_shard_by_hash(hash).lock(); + let mut shard = self.lock_shard_by_hash(hash); let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value); match entry { @@ -144,7 +194,7 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> { Q: Hash + Eq, { let hash = make_hash(&value); - let mut shard = self.get_shard_by_hash(hash).lock(); + let mut shard = self.lock_shard_by_hash(hash); let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value); match entry { @@ -166,7 +216,7 @@ pub trait IntoPointer { impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> { pub fn contains_pointer_to<T: Hash + IntoPointer>(&self, value: &T) -> bool { let hash = make_hash(&value); - let shard = self.get_shard_by_hash(hash).lock(); + let shard = self.lock_shard_by_hash(hash); let value = value.into_pointer(); shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some() } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 2ec509b9118..63f137516bd 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -49,7 +49,7 @@ use std::ops::{Deref, DerefMut}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; mod lock; -pub use lock::{Lock, LockGuard}; +pub use lock::{Lock, LockGuard, Mode}; mod worker_local; pub use worker_local::{Registry, WorkerLocal}; @@ -61,6 +61,9 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; +mod freeze; +pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; + mod mode { use super::Ordering; use std::sync::atomic::AtomicU8; @@ -83,7 +86,6 @@ mod mode { // Whether thread safety might be enabled. #[inline] - #[cfg(parallel_compiler)] pub fn might_be_dyn_thread_safe() -> bool { DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE } @@ -273,7 +275,7 @@ cfg_if! { pub use std::cell::RefMut as MappedWriteGuard; pub use std::cell::RefMut as MappedLockGuard; - pub use std::cell::OnceCell; + pub use std::cell::OnceCell as OnceLock; use std::cell::RefCell as InnerRwLock; @@ -327,7 +329,7 @@ cfg_if! { pub use parking_lot::MappedMutexGuard as MappedLockGuard; - pub use std::sync::OnceLock as OnceCell; + pub use std::sync::OnceLock; pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs new file mode 100644 index 00000000000..466c44f59bb --- /dev/null +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -0,0 +1,200 @@ +use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; +#[cfg(parallel_compiler)] +use crate::sync::{DynSend, DynSync}; +use std::{ + cell::UnsafeCell, + intrinsics::likely, + marker::PhantomData, + ops::{Deref, DerefMut}, + ptr::NonNull, + sync::atomic::Ordering, +}; + +/// A type which allows mutation using a lock until +/// the value is frozen and can be accessed lock-free. +/// +/// Unlike `RwLock`, it can be used to prevent mutation past a point. +#[derive(Default)] +pub struct FreezeLock<T> { + data: UnsafeCell<T>, + frozen: AtomicBool, + + /// This lock protects writes to the `data` and `frozen` fields. + lock: RwLock<()>, +} + +#[cfg(parallel_compiler)] +unsafe impl<T: DynSync + DynSend> DynSync for FreezeLock<T> {} + +impl<T> FreezeLock<T> { + #[inline] + pub fn new(value: T) -> Self { + Self::with(value, false) + } + + #[inline] + pub fn frozen(value: T) -> Self { + Self::with(value, true) + } + + #[inline] + pub fn with(value: T, frozen: bool) -> Self { + Self { + data: UnsafeCell::new(value), + frozen: AtomicBool::new(frozen), + lock: RwLock::new(()), + } + } + + /// Clones the inner value along with the frozen state. + #[inline] + pub fn clone(&self) -> Self + where + T: Clone, + { + let lock = self.read(); + Self::with(lock.clone(), self.is_frozen()) + } + + #[inline] + pub fn is_frozen(&self) -> bool { + self.frozen.load(Ordering::Acquire) + } + + /// Get the inner value if frozen. + #[inline] + pub fn get(&self) -> Option<&T> { + if likely(self.frozen.load(Ordering::Acquire)) { + // SAFETY: This is frozen so the data cannot be modified. + unsafe { Some(&*self.data.get()) } + } else { + None + } + } + + #[inline] + pub fn read(&self) -> FreezeReadGuard<'_, T> { + FreezeReadGuard { + _lock_guard: if self.frozen.load(Ordering::Acquire) { + None + } else { + Some(self.lock.read()) + }, + data: unsafe { NonNull::new_unchecked(self.data.get()) }, + } + } + + #[inline] + pub fn borrow(&self) -> FreezeReadGuard<'_, T> { + self.read() + } + + #[inline] + #[track_caller] + pub fn write(&self) -> FreezeWriteGuard<'_, T> { + self.try_write().expect("still mutable") + } + + #[inline] + pub fn try_write(&self) -> Option<FreezeWriteGuard<'_, T>> { + let _lock_guard = self.lock.write(); + // Use relaxed ordering since we're in the write lock. + if self.frozen.load(Ordering::Relaxed) { + None + } else { + Some(FreezeWriteGuard { + _lock_guard, + data: unsafe { NonNull::new_unchecked(self.data.get()) }, + frozen: &self.frozen, + marker: PhantomData, + }) + } + } + + #[inline] + pub fn freeze(&self) -> &T { + if !self.frozen.load(Ordering::Acquire) { + // Get the lock to ensure no concurrent writes and that we release the latest write. + let _lock = self.lock.write(); + self.frozen.store(true, Ordering::Release); + } + + // SAFETY: This is frozen so the data cannot be modified and shared access is sound. + unsafe { &*self.data.get() } + } +} + +/// A guard holding shared access to a `FreezeLock` which is in a locked state or frozen. +#[must_use = "if unused the FreezeLock may immediately unlock"] +pub struct FreezeReadGuard<'a, T: ?Sized> { + _lock_guard: Option<ReadGuard<'a, ()>>, + data: NonNull<T>, +} + +impl<'a, T: ?Sized + 'a> Deref for FreezeReadGuard<'a, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + // SAFETY: If the lock is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so + // this has shared access until the `FreezeReadGuard` is dropped. If the lock is frozen, + // the data cannot be modified and shared access is sound. + unsafe { &*self.data.as_ptr() } + } +} + +impl<'a, T: ?Sized> FreezeReadGuard<'a, T> { + #[inline] + pub fn map<U: ?Sized>(this: Self, f: impl FnOnce(&T) -> &U) -> FreezeReadGuard<'a, U> { + FreezeReadGuard { data: NonNull::from(f(&*this)), _lock_guard: this._lock_guard } + } +} + +/// A guard holding mutable access to a `FreezeLock` which is in a locked state or frozen. +#[must_use = "if unused the FreezeLock may immediately unlock"] +pub struct FreezeWriteGuard<'a, T: ?Sized> { + _lock_guard: WriteGuard<'a, ()>, + frozen: &'a AtomicBool, + data: NonNull<T>, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> FreezeWriteGuard<'a, T> { + pub fn freeze(self) -> &'a T { + self.frozen.store(true, Ordering::Release); + + // SAFETY: This is frozen so the data cannot be modified and shared access is sound. + unsafe { &*self.data.as_ptr() } + } +} + +impl<'a, T: ?Sized> FreezeWriteGuard<'a, T> { + #[inline] + pub fn map<U: ?Sized>( + mut this: Self, + f: impl FnOnce(&mut T) -> &mut U, + ) -> FreezeWriteGuard<'a, U> { + FreezeWriteGuard { + data: NonNull::from(f(&mut *this)), + _lock_guard: this._lock_guard, + frozen: this.frozen, + marker: PhantomData, + } + } +} + +impl<'a, T: ?Sized + 'a> Deref for FreezeWriteGuard<'a, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has shared access. + unsafe { &*self.data.as_ptr() } + } +} + +impl<'a, T: ?Sized + 'a> DerefMut for FreezeWriteGuard<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has mutable access. + unsafe { &mut *self.data.as_ptr() } + } +} diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs index 62cd1b993de..339aebbf81a 100644 --- a/compiler/rustc_data_structures/src/sync/lock.rs +++ b/compiler/rustc_data_structures/src/sync/lock.rs @@ -3,224 +3,229 @@ //! //! When `cfg(parallel_compiler)` is not set, the lock is instead a wrapper around `RefCell`. -#[cfg(not(parallel_compiler))] -use std::cell::RefCell; -#[cfg(parallel_compiler)] -use { - crate::cold_path, - crate::sync::DynSend, - crate::sync::DynSync, - parking_lot::lock_api::RawMutex, - std::cell::Cell, - std::cell::UnsafeCell, - std::fmt, - std::intrinsics::{likely, unlikely}, - std::marker::PhantomData, - std::mem::ManuallyDrop, - std::ops::{Deref, DerefMut}, -}; +#![allow(dead_code)] -#[cfg(not(parallel_compiler))] -pub use std::cell::RefMut as LockGuard; +use std::fmt; +#[cfg(parallel_compiler)] +pub use maybe_sync::*; #[cfg(not(parallel_compiler))] -#[derive(Debug)] -pub struct Lock<T>(RefCell<T>); +pub use no_sync::*; -#[cfg(not(parallel_compiler))] -impl<T> Lock<T> { - #[inline(always)] - pub fn new(inner: T) -> Self { - Lock(RefCell::new(inner)) - } +#[derive(Clone, Copy, PartialEq)] +pub enum Mode { + NoSync, + Sync, +} - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() +mod maybe_sync { + use super::Mode; + use crate::sync::mode; + #[cfg(parallel_compiler)] + use crate::sync::{DynSend, DynSync}; + use parking_lot::lock_api::RawMutex as _; + use parking_lot::RawMutex; + use std::cell::Cell; + use std::cell::UnsafeCell; + use std::intrinsics::unlikely; + use std::marker::PhantomData; + use std::mem::ManuallyDrop; + use std::ops::{Deref, DerefMut}; + + /// A guard holding mutable access to a `Lock` which is in a locked state. + #[must_use = "if unused the Lock will immediately unlock"] + pub struct LockGuard<'a, T> { + lock: &'a Lock<T>, + marker: PhantomData<&'a mut T>, + + /// The syncronization mode of the lock. This is explicitly passed to let LLVM relate it + /// to the original lock operation. + mode: Mode, } - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut() + impl<'a, T: 'a> Deref for LockGuard<'a, T> { + type Target = T; + #[inline] + fn deref(&self) -> &T { + // SAFETY: We have shared access to the mutable access owned by this type, + // so we can give out a shared reference. + unsafe { &*self.lock.data.get() } + } } - #[inline(always)] - pub fn try_lock(&self) -> Option<LockGuard<'_, T>> { - self.0.try_borrow_mut().ok() + impl<'a, T: 'a> DerefMut for LockGuard<'a, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + // SAFETY: We have mutable access to the data so we can give out a mutable reference. + unsafe { &mut *self.lock.data.get() } + } } - #[inline(always)] - #[track_caller] - pub fn lock(&self) -> LockGuard<'_, T> { - self.0.borrow_mut() + impl<'a, T: 'a> Drop for LockGuard<'a, T> { + #[inline] + fn drop(&mut self) { + // SAFETY (union access): We get `self.mode` from the lock operation so it is consistent + // with the `lock.mode` state. This means we access the right union fields. + match self.mode { + Mode::NoSync => { + let cell = unsafe { &self.lock.mode_union.no_sync }; + debug_assert_eq!(cell.get(), true); + cell.set(false); + } + // SAFETY (unlock): We know that the lock is locked as this type is a proof of that. + Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() }, + } + } } -} -/// A guard holding mutable access to a `Lock` which is in a locked state. -#[cfg(parallel_compiler)] -#[must_use = "if unused the Lock will immediately unlock"] -pub struct LockGuard<'a, T> { - lock: &'a Lock<T>, - marker: PhantomData<&'a mut T>, -} + union ModeUnion { + /// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`. + no_sync: ManuallyDrop<Cell<bool>>, -#[cfg(parallel_compiler)] -impl<'a, T: 'a> Deref for LockGuard<'a, T> { - type Target = T; - #[inline] - fn deref(&self) -> &T { - // SAFETY: We have shared access to the mutable access owned by this type, - // so we can give out a shared reference. - unsafe { &*self.lock.data.get() } + /// A lock implementation that's only used if `Lock.mode` is `Sync`. + sync: ManuallyDrop<RawMutex>, } -} -#[cfg(parallel_compiler)] -impl<'a, T: 'a> DerefMut for LockGuard<'a, T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - // SAFETY: We have mutable access to the data so we can give out a mutable reference. - unsafe { &mut *self.lock.data.get() } - } -} + /// The value representing a locked state for the `Cell`. + const LOCKED: bool = true; -#[cfg(parallel_compiler)] -impl<'a, T: 'a> Drop for LockGuard<'a, T> { - #[inline] - fn drop(&mut self) { - // SAFETY: We know that the lock is in a locked - // state because it is a invariant of this type. - unsafe { self.lock.raw.unlock() }; - } -} + /// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true. + /// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`. + pub struct Lock<T> { + /// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a + /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`. + /// This is set on initialization and never changed. + mode: Mode, -#[cfg(parallel_compiler)] -union LockRawUnion { - /// Indicates if the cell is locked. Only used if `LockRaw.sync` is false. - cell: ManuallyDrop<Cell<bool>>, + mode_union: ModeUnion, + data: UnsafeCell<T>, + } - /// A lock implementation that's only used if `LockRaw.sync` is true. - lock: ManuallyDrop<parking_lot::RawMutex>, -} + impl<T> Lock<T> { + #[inline(always)] + pub fn new(inner: T) -> Self { + let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) { + // Create the lock with synchronization enabled using the `RawMutex` type. + (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) }) + } else { + // Create the lock with synchronization disabled. + (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) }) + }; + Lock { mode, mode_union, data: UnsafeCell::new(inner) } + } -/// A raw lock which only uses synchronization if `might_be_dyn_thread_safe` is true. -/// It contains no associated data and is used in the implementation of `Lock` which does have such data. -/// -/// A manual implementation of a tagged union is used with the `sync` field and the `LockRawUnion` instead -/// of using enums as it results in better code generation. -#[cfg(parallel_compiler)] -struct LockRaw { - /// Indicates if synchronization is used via `opt.lock` if true, - /// or if a non-thread safe cell is used via `opt.cell`. This is set on initialization and never changed. - sync: bool, - opt: LockRawUnion, -} + #[inline(always)] + pub fn into_inner(self) -> T { + self.data.into_inner() + } -#[cfg(parallel_compiler)] -impl LockRaw { - fn new() -> Self { - if unlikely(super::mode::might_be_dyn_thread_safe()) { - // Create the lock with synchronization enabled using the `RawMutex` type. - LockRaw { - sync: true, - opt: LockRawUnion { lock: ManuallyDrop::new(parking_lot::RawMutex::INIT) }, - } - } else { - // Create the lock with synchronization disabled. - LockRaw { sync: false, opt: LockRawUnion { cell: ManuallyDrop::new(Cell::new(false)) } } + #[inline(always)] + pub fn get_mut(&mut self) -> &mut T { + self.data.get_mut() } - } - #[inline(always)] - fn try_lock(&self) -> bool { - // SAFETY: This is safe since the union fields are used in accordance with `self.sync`. - unsafe { - if likely(!self.sync) { - if self.opt.cell.get() { - false - } else { - self.opt.cell.set(true); - true + #[inline(always)] + pub fn try_lock(&self) -> Option<LockGuard<'_, T>> { + let mode = self.mode; + // SAFETY: This is safe since the union fields are used in accordance with `self.mode`. + match mode { + Mode::NoSync => { + let cell = unsafe { &self.mode_union.no_sync }; + let was_unlocked = cell.get() != LOCKED; + if was_unlocked { + cell.set(LOCKED); + } + was_unlocked } - } else { - self.opt.lock.try_lock() + Mode::Sync => unsafe { self.mode_union.sync.try_lock() }, } + .then(|| LockGuard { lock: self, marker: PhantomData, mode }) } - } - #[inline(always)] - fn lock(&self) { - if super::ERROR_CHECKING { - // We're in the debugging mode, so assert that the lock is not held so we - // get a panic instead of waiting for the lock. - assert_eq!(self.try_lock(), true, "lock must not be hold"); - } else { - // SAFETY: This is safe since the union fields are used in accordance with `self.sync`. + /// This acquires the lock assuming syncronization is in a specific mode. + /// + /// Safety + /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was + /// true on lock creation. + #[inline(always)] + #[track_caller] + pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> { + #[inline(never)] + #[track_caller] + #[cold] + fn lock_held() -> ! { + panic!("lock was already held") + } + + // SAFETY: This is safe since the union fields are used in accordance with `mode` + // which also must match `self.mode` due to the safety precondition. unsafe { - if likely(!self.sync) { - if unlikely(self.opt.cell.replace(true)) { - cold_path(|| panic!("lock was already held")) + match mode { + Mode::NoSync => { + if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) { + lock_held() + } } - } else { - self.opt.lock.lock(); + Mode::Sync => self.mode_union.sync.lock(), } } + LockGuard { lock: self, marker: PhantomData, mode } } - } - /// This unlocks the lock. - /// - /// Safety - /// This method may only be called if the lock is currently held. - #[inline(always)] - unsafe fn unlock(&self) { - // SAFETY: The union use is safe since the union fields are used in accordance with - // `self.sync` and the `unlock` method precondition is upheld by the caller. - unsafe { - if likely(!self.sync) { - debug_assert_eq!(self.opt.cell.get(), true); - self.opt.cell.set(false); - } else { - self.opt.lock.unlock(); - } + #[inline(always)] + #[track_caller] + pub fn lock(&self) -> LockGuard<'_, T> { + unsafe { self.lock_assume(self.mode) } } } -} -/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true. -/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`. -#[cfg(parallel_compiler)] -pub struct Lock<T> { - raw: LockRaw, - data: UnsafeCell<T>, + #[cfg(parallel_compiler)] + unsafe impl<T: DynSend> DynSend for Lock<T> {} + #[cfg(parallel_compiler)] + unsafe impl<T: DynSend> DynSync for Lock<T> {} } -#[cfg(parallel_compiler)] -impl<T> Lock<T> { - #[inline(always)] - pub fn new(inner: T) -> Self { - Lock { raw: LockRaw::new(), data: UnsafeCell::new(inner) } - } +mod no_sync { + use super::Mode; + use std::cell::RefCell; - #[inline(always)] - pub fn into_inner(self) -> T { - self.data.into_inner() - } + pub use std::cell::RefMut as LockGuard; - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.data.get_mut() - } + pub struct Lock<T>(RefCell<T>); - #[inline(always)] - pub fn try_lock(&self) -> Option<LockGuard<'_, T>> { - if self.raw.try_lock() { Some(LockGuard { lock: self, marker: PhantomData }) } else { None } - } + impl<T> Lock<T> { + #[inline(always)] + pub fn new(inner: T) -> Self { + Lock(RefCell::new(inner)) + } - #[inline(always)] - pub fn lock(&self) -> LockGuard<'_, T> { - self.raw.lock(); - LockGuard { lock: self, marker: PhantomData } + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } + + #[inline(always)] + pub fn get_mut(&mut self) -> &mut T { + self.0.get_mut() + } + + #[inline(always)] + pub fn try_lock(&self) -> Option<LockGuard<'_, T>> { + self.0.try_borrow_mut().ok() + } + + #[inline(always)] + #[track_caller] + // This is unsafe to match the API for the `parallel_compiler` case. + pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> { + self.0.borrow_mut() + } + + #[inline(always)] + #[track_caller] + pub fn lock(&self) -> LockGuard<'_, T> { + self.0.borrow_mut() + } } } @@ -244,12 +249,13 @@ impl<T> Lock<T> { } } -#[cfg(parallel_compiler)] -unsafe impl<T: DynSend> DynSend for Lock<T> {} -#[cfg(parallel_compiler)] -unsafe impl<T: DynSend> DynSync for Lock<T> {} +impl<T: Default> Default for Lock<T> { + #[inline] + fn default() -> Self { + Lock::new(T::default()) + } +} -#[cfg(parallel_compiler)] impl<T: fmt::Debug> fmt::Debug for Lock<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.try_lock() { @@ -267,10 +273,3 @@ impl<T: fmt::Debug> fmt::Debug for Lock<T> { } } } - -impl<T: Default> Default for Lock<T> { - #[inline] - fn default() -> Self { - Lock::new(T::default()) - } -} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1a16759d7f9..e56347ab38e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -313,6 +313,7 @@ fn run_compiler( override_queries: None, make_codegen_backend, registry: diagnostics_registry(), + expanded_args: args, }; match make_input(&early_error_handler, &matches.free) { diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index a88fba6dae6..5d3b2f45166 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -91,7 +91,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType { } Level::Warning(_) => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, - Level::Help => AnnotationType::Help, + Level::Help | Level::OnceHelp => AnnotationType::Help, // FIXME(#59346): Not sure how to map this level Level::FailureNote => AnnotationType::Error, Level::Allow => panic!("Should not call with Allow"), @@ -169,7 +169,7 @@ impl AnnotateSnippetEmitterWriter { .map(|line| { // Ensure the source file is present before we try // to load a string from it. - source_map.ensure_source_file_source_present(file.clone()); + source_map.ensure_source_file_source_present(&file); ( format!("{}", source_map.filename_for_diagnostics(&file.name)), source_string(file.clone(), &line), diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a96e317df55..3fd087b1d5e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -270,6 +270,7 @@ impl Diagnostic { | Level::Note | Level::OnceNote | Level::Help + | Level::OnceHelp | Level::Allow | Level::Expect(_) => false, } @@ -532,6 +533,13 @@ impl Diagnostic { self } + /// Prints the span with a help above it. + /// This is like [`Diagnostic::help()`], but it gets its own span. + pub fn help_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { + self.sub(Level::OnceHelp, msg, MultiSpan::new(), None); + self + } + /// Add a help message attached to this diagnostic with a customizable highlighted message. pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self { self.sub_with_highlights(Level::Help, msg, MultiSpan::new(), None); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 1811738c011..58be74f887b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1193,7 +1193,7 @@ impl EmitterWriter { let will_be_emitted = |span: Span| { !span.is_dummy() && { let file = sm.lookup_source_file(span.hi()); - sm.ensure_source_file_source_present(file) + sm.ensure_source_file_source_present(&file) } }; @@ -1388,7 +1388,7 @@ impl EmitterWriter { // Print out the annotate source lines that correspond with the error for annotated_file in annotated_files { // we can't annotate anything if the source is unavailable. - if !sm.ensure_source_file_source_present(annotated_file.file.clone()) { + if !sm.ensure_source_file_source_present(&annotated_file.file) { if !self.short_message { // We'll just print an unannotated message. for (annotation_id, line) in annotated_file.lines.iter().enumerate() { @@ -2348,7 +2348,13 @@ impl FileWithAnnotatedLines { } let label = label.as_ref().map(|m| { - emitter.translate_message(m, args).map_err(Report::new).unwrap().to_string() + normalize_whitespace( + &emitter + .translate_message(m, &args) + .map_err(Report::new) + .unwrap() + .to_string(), + ) }); if lo.line != hi.line { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 390bf28df09..38667c5ff81 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -558,7 +558,7 @@ impl DiagnosticSpanLine { .span_to_lines(span) .map(|lines| { // We can't get any lines if the source is unavailable. - if !je.sm.ensure_source_file_source_present(lines.file.clone()) { + if !je.sm.ensure_source_file_source_present(&lines.file) { return vec![]; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c2fe942fe37..990bd2d1cc9 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -44,7 +44,7 @@ use rustc_fluent_macro::fluent_messages; pub use rustc_lint_defs::{pluralize, Applicability}; use rustc_span::source_map::SourceMap; pub use rustc_span::ErrorGuaranteed; -use rustc_span::{Loc, Span}; +use rustc_span::{Loc, Span, DUMMY_SP}; use std::borrow::Cow; use std::error::Report; @@ -55,6 +55,8 @@ use std::num::NonZeroUsize; use std::panic; use std::path::{Path, PathBuf}; +// Used by external projects such as `rust-gpu`. +// See https://github.com/rust-lang/rust/pull/115393. pub use termcolor::{Color, ColorSpec, WriteColor}; pub mod annotate_snippet_emitter_writer; @@ -271,7 +273,7 @@ impl CodeSuggestion { assert!(!lines.lines.is_empty() || bounding_span.is_dummy()); // We can't splice anything if the source is unavailable. - if !sm.ensure_source_file_source_present(lines.file.clone()) { + if !sm.ensure_source_file_source_present(&lines.file) { return None; } @@ -1388,7 +1390,7 @@ impl HandlerInner { debug!(?self.emitted_diagnostics); let already_emitted_sub = |sub: &mut SubDiagnostic| { debug!(?sub); - if sub.level != Level::OnceNote { + if sub.level != Level::OnceNote && sub.level != Level::OnceHelp { return false; } let mut hasher = StableHasher::new(); @@ -1752,7 +1754,7 @@ impl DelayedDiagnostic { BacktraceStatus::Captured => { let inner = &self.inner; self.inner.subdiagnostic(DelayedAtWithNewline { - span: inner.span.primary_span().unwrap(), + span: inner.span.primary_span().unwrap_or(DUMMY_SP), emitted_at: inner.emitted_at.clone(), note: self.note, }); @@ -1762,7 +1764,7 @@ impl DelayedDiagnostic { _ => { let inner = &self.inner; self.inner.subdiagnostic(DelayedAtWithoutNewline { - span: inner.span.primary_span().unwrap(), + span: inner.span.primary_span().unwrap_or(DUMMY_SP), emitted_at: inner.emitted_at.clone(), note: self.note, }); @@ -1790,6 +1792,8 @@ pub enum Level { /// A note that is only emitted once. OnceNote, Help, + /// A help that is only emitted once. + OnceHelp, FailureNote, Allow, Expect(LintExpectationId), @@ -1814,7 +1818,7 @@ impl Level { Note | OnceNote => { spec.set_fg(Some(Color::Green)).set_intense(true); } - Help => { + Help | OnceHelp => { spec.set_fg(Some(Color::Cyan)).set_intense(true); } FailureNote => {} @@ -1829,7 +1833,7 @@ impl Level { Fatal | Error { .. } => "error", Warning(_) => "warning", Note | OnceNote => "note", - Help => "help", + Help | OnceHelp => "help", FailureNote => "failure-note", Allow => panic!("Shouldn't call on allowed error"), Expect(_) => panic!("Shouldn't call on expected error"), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 34d16bf00cd..f87f4aba2b9 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -587,7 +587,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .resolver .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment); - if self.cx.sess.opts.incremental_relative_spans() { + if self.cx.sess.opts.incremental.is_some() { for (invoc, _) in invocations.iter_mut() { let expn_id = invoc.expansion_data.id; let parent_def = self.cx.resolver.invocation_parent(expn_id); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index b1f74643b69..afcf30d0b29 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -54,7 +54,7 @@ declare_features! ( /// instead of just the platforms on which it is the C ABI. (accepted, abi_sysv64, "1.24.0", Some(36167), None), /// Allows using the `thiscall` ABI. - (accepted, abi_thiscall, "1.19.0", None, None), + (accepted, abi_thiscall, "1.73.0", None, None), /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`. (accepted, adx_target_feature, "1.61.0", Some(44839), None), /// Allows explicit discriminants on non-unit enum variants. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 172f557f8e2..d9195a374c2 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -152,7 +152,7 @@ pub mod nested_filter { /// visit fn bodies for fns that it encounters, and closure bodies, but /// skip over nested item-like things. /// - /// See the comments on `ItemLikeVisitor` for more details on the overall + /// See the comments at [`rustc_hir::intravisit`] for more details on the overall /// visit strategy. pub trait NestedFilter<'hir> { type Map: Map<'hir>; @@ -229,8 +229,8 @@ pub trait Visitor<'v>: Sized { /// `Self::NestedFilter` is `nested_filter::None`, this method does /// nothing. **You probably don't want to override this method** -- /// instead, override [`Self::NestedFilter`] or use the "shallow" or - /// "deep" visit patterns described on - /// `itemlikevisit::ItemLikeVisitor`. The only reason to override + /// "deep" visit patterns described at + /// [`rustc_hir::intravisit`]. The only reason to override /// this method is if you want a nested pattern but cannot supply a /// [`Map`]; see `nested_visit_map` for advice. fn visit_nested_item(&mut self, id: ItemId) { diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 597cae6ff33..50da2278312 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -222,6 +222,12 @@ hir_analysis_return_type_notation_on_non_rpitit = .note = function returns `{$ty}`, which is not compatible with associated type return bounds .label = this function must be `async` or return `impl Trait` +hir_analysis_rpitit_refined = impl trait in impl method signature does not match trait method signature + .suggestion = replace the return type so that it matches the trait + .label = return type from trait method defined here + .unmatched_bound_label = this bound is stronger than that defined on the trait + .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block .note = replace `Self` with a different type diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 6082d446979..ed4dde419c4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { { // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. - let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; + let is_dummy = assoc_name.span == DUMMY_SP; + let mut err = struct_span_err!( self.tcx().sess, - span, + if is_dummy { span } else { assoc_name.span }, E0220, "associated type `{}` not found for `{}`", assoc_name, ty_param_name ); + if is_dummy { + err.span_label(span, format!("associated type `{assoc_name}` not found")); + return err.emit(); + } + let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) .filter_map(|item| { @@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect(); - if let (Some(suggested_name), true) = ( - find_best_match_for_name(&all_candidate_names, assoc_name.name, None), - assoc_name.span != DUMMY_SP, - ) { + if let Some(suggested_name) = + find_best_match_for_name(&all_candidate_names, assoc_name.name, None) + { err.span_suggestion( assoc_name.span, "there is an associated type with a similar name", @@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect(); - if let (Some(suggested_name), true) = ( - find_best_match_for_name(&wider_candidate_names, assoc_name.name, None), - assoc_name.span != DUMMY_SP, - ) { + if let Some(suggested_name) = + find_best_match_for_name(&wider_candidate_names, assoc_name.name, None) + { if let [best_trait] = visible_traits .iter() .filter(|trait_def_id| { @@ -197,7 +201,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - err.span_label(span, format!("associated type `{assoc_name}` not found")); + // If we still couldn't find any associated type, and only one associated type exists, + // suggests using it. + + if all_candidate_names.len() == 1 { + // this should still compile, except on `#![feature(associated_type_defaults)]` + // where it could suggests `type A = Self::A`, thus recursing infinitely + let applicability = if self.tcx().features().associated_type_defaults { + Applicability::Unspecified + } else { + Applicability::MaybeIncorrect + }; + + err.span_suggestion( + assoc_name.span, + format!("`{ty_param_name}` has the following associated type"), + all_candidate_names.first().unwrap().to_string(), + applicability, + ); + } else { + err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found")); + } + err.emit() } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 7a6856fb1f4..90f64e18632 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2205,27 +2205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_note(span, format!("type parameter `{name}` defined here")); } }); - - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - let name = - tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); - let br = ty::BoundTy { - var: ty::BoundVar::from_u32(index), - kind: ty::BoundTyKind::Param(def_id, name), - }; - Ty::new_bound(tcx, debruijn, br) - } - Some(rbv::ResolvedArg::EarlyBound(_)) => { - let def_id = def_id.expect_local(); - let item_def_id = tcx.hir().ty_param_owner(def_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)) - } - Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), - } + self.hir_id_to_bound_ty(hir_id) } Res::SelfTyParam { .. } => { // `Self` in trait or type alias. @@ -2394,6 +2374,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } + // Converts a hir id corresponding to a type parameter to + // a early-bound `ty::Param` or late-bound `ty::Bound`. + pub(crate) fn hir_id_to_bound_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> { + let tcx = self.tcx(); + match tcx.named_bound_var(hir_id) { + Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { + let name = tcx.item_name(def_id); + let br = ty::BoundTy { + var: ty::BoundVar::from_u32(index), + kind: ty::BoundTyKind::Param(def_id, name), + }; + Ty::new_bound(tcx, debruijn, br) + } + Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + let def_id = def_id.expect_local(); + let item_def_id = tcx.hir().ty_param_owner(def_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)) + } + Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), + arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), + } + } + + // Converts a hir id corresponding to a const parameter to + // a early-bound `ConstKind::Param` or late-bound `ConstKind::Bound`. + pub(crate) fn hir_id_to_bound_const( + &self, + hir_id: hir::HirId, + param_ty: Ty<'tcx>, + ) -> Const<'tcx> { + let tcx = self.tcx(); + match tcx.named_bound_var(hir_id) { + Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + // Find the name and index of the const parameter by indexing the generics of + // the parent item and construct a `ParamConst`. + let item_def_id = tcx.parent(def_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + let name = tcx.item_name(def_id); + ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty) + } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { + ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty) + } + Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty), + arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), + } + } + /// Parses the programmer's textual representation of a type into our /// internal notion of a type. pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index bd0ab6463f0..92cc9759304 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -28,6 +28,8 @@ use rustc_trait_selection::traits::{ use std::borrow::Cow; use std::iter; +mod refine; + /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. /// @@ -53,6 +55,12 @@ pub(super) fn compare_impl_method<'tcx>( impl_trait_ref, CheckImpliedWfMode::Check, )?; + refine::check_refining_return_position_impl_trait_in_trait( + tcx, + impl_m, + trait_m, + impl_trait_ref, + ); }; } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs new file mode 100644 index 00000000000..a8149b634ef --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -0,0 +1,311 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt}; +use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT; +use rustc_middle::traits::{ObligationCause, Reveal}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; +use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::traits::{ + elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt, +}; +use std::ops::ControlFlow; + +/// Check that an implementation does not refine an RPITIT from a trait method signature. +pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: ty::AssocItem, + trait_m: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) { + if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { + return; + } + // crate-private traits don't have any library guarantees, there's no need to do this check. + if !tcx.visibility(trait_m.container_id(tcx)).is_public() { + return; + } + + // If a type in the trait ref is private, then there's also no reason to to do this check. + let impl_def_id = impl_m.container_id(tcx); + for arg in impl_trait_ref.args { + if let Some(ty) = arg.as_type() + && let Some(self_visibility) = type_visibility(tcx, ty) + && !self_visibility.is_public() + { + return; + } + } + + let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id); + let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args); + let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args); + let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig); + // replace the self type of the trait ref with `Self` so that diagnostics render better. + let trait_m_sig_with_self_for_diag = tcx.liberate_late_bound_regions( + impl_m.def_id, + tcx.fn_sig(trait_m.def_id).instantiate( + tcx, + tcx.mk_args_from_iter( + [tcx.types.self_param.into()] + .into_iter() + .chain(trait_m_to_impl_m_args.iter().skip(1)), + ), + ), + ); + + let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else { + // Error already emitted, no need to delay another. + return; + }; + + let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() }; + trait_m_sig.visit_with(&mut collector); + + // Bound that we find on RPITITs in the trait signature. + let mut trait_bounds = vec![]; + // Bounds that we find on the RPITITs in the impl signature. + let mut impl_bounds = vec![]; + + for trait_projection in collector.types.into_iter().rev() { + let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args); + let hidden_ty = hidden_tys[&trait_projection.def_id].instantiate(tcx, impl_opaque_args); + + // If the hidden type is not an opaque, then we have "refined" the trait signature. + let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig_with_self_for_diag, + trait_m.def_id, + impl_m.def_id, + None, + ); + return; + }; + + // This opaque also needs to be from the impl method -- otherwise, + // it's a refinement to a TAIT. + if !tcx.hir().get_if_local(impl_opaque.def_id).map_or(false, |node| { + matches!( + node.expect_item().expect_opaque_ty().origin, + hir::OpaqueTyOrigin::AsyncFn(def_id) | hir::OpaqueTyOrigin::FnReturn(def_id) + if def_id == impl_m.def_id.expect_local() + ) + }) { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig_with_self_for_diag, + trait_m.def_id, + impl_m.def_id, + None, + ); + return; + } + + trait_bounds.extend( + tcx.item_bounds(trait_projection.def_id).iter_instantiated(tcx, trait_projection.args), + ); + impl_bounds.extend(elaborate( + tcx, + tcx.explicit_item_bounds(impl_opaque.def_id) + .iter_instantiated_copied(tcx, impl_opaque.args), + )); + } + + let hybrid_preds = tcx + .predicates_of(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args)) + .map(|(clause, _)| clause); + let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); + let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); + + let ref infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); + + // Normalize the bounds. This has two purposes: + // + // 1. Project the RPITIT projections from the trait to the opaques on the impl, + // which means that they don't need to be mapped manually. + // + // 2. Project any other projections that show up in the bound. That makes sure that + // we don't consider `tests/ui/async-await/in-trait/async-associated-types.rs` + // to be refining. + let (trait_bounds, impl_bounds) = + ocx.normalize(&ObligationCause::dummy(), param_env, (trait_bounds, impl_bounds)); + + // Since we've normalized things, we need to resolve regions, since we'll + // possibly have introduced region vars during projection. We don't expect + // this resolution to have incurred any region errors -- but if we do, then + // just delay a bug. + let mut implied_wf_types = FxIndexSet::default(); + implied_wf_types.extend(trait_m_sig.inputs_and_output); + implied_wf_types.extend(ocx.normalize( + &ObligationCause::dummy(), + param_env, + trait_m_sig.inputs_and_output, + )); + if !ocx.select_all_or_error().is_empty() { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (selection)", + ); + return; + } + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types), + ); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (regions)", + ); + return; + } + // Resolve any lifetime variables that may have been introduced during normalization. + let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (resolution)", + ); + return; + }; + + // For quicker lookup, use an `IndexSet` + // (we don't use one earlier because it's not foldable..) + let trait_bounds = FxIndexSet::from_iter(trait_bounds); + + // Find any clauses that are present in the impl's RPITITs that are not + // present in the trait's RPITITs. This will trigger on trivial predicates, + // too, since we *do not* use the trait solver to prove that the RPITIT's + // bounds are not stronger -- we're doing a simple, syntactic compatibility + // check between bounds. This is strictly forwards compatible, though. + for (clause, span) in impl_bounds { + if !trait_bounds.contains(&clause) { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig_with_self_for_diag, + trait_m.def_id, + impl_m.def_id, + Some(span), + ); + return; + } + } +} + +struct ImplTraitInTraitCollector<'tcx> { + tcx: TyCtxt<'tcx>, + types: FxIndexSet<ty::AliasTy<'tcx>>, +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { + if let ty::Alias(ty::Projection, proj) = *ty.kind() + && self.tcx.is_impl_trait_in_trait(proj.def_id) + { + if self.types.insert(proj) { + for (pred, _) in self + .tcx + .explicit_item_bounds(proj.def_id) + .iter_instantiated_copied(self.tcx, proj.args) + { + pred.visit_with(self)?; + } + } + ControlFlow::Continue(()) + } else { + ty.super_visit_with(self) + } + } +} + +fn report_mismatched_rpitit_signature<'tcx>( + tcx: TyCtxt<'tcx>, + trait_m_sig: ty::FnSig<'tcx>, + trait_m_def_id: DefId, + impl_m_def_id: DefId, + unmatched_bound: Option<Span>, +) { + let mapping = std::iter::zip( + tcx.fn_sig(trait_m_def_id).skip_binder().bound_vars(), + tcx.fn_sig(impl_m_def_id).skip_binder().bound_vars(), + ) + .filter_map(|(impl_bv, trait_bv)| { + if let ty::BoundVariableKind::Region(impl_bv) = impl_bv + && let ty::BoundVariableKind::Region(trait_bv) = trait_bv + { + Some((impl_bv, trait_bv)) + } else { + None + } + }) + .collect(); + + let mut return_ty = + trait_m_sig.output().fold_with(&mut super::RemapLateBound { tcx, mapping: &mapping }); + + if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() { + let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else { + bug!(); + }; + let Some(future_output_ty) = tcx + .explicit_item_bounds(future_ty.def_id) + .iter_instantiated_copied(tcx, future_ty.args) + .find_map(|(clause, _)| match clause.kind().no_bound_vars()? { + ty::ClauseKind::Projection(proj) => proj.term.ty(), + _ => None, + }) + else { + bug!() + }; + return_ty = future_output_ty; + } + + let (span, impl_return_span, pre, post) = + match tcx.hir().get_by_def_id(impl_m_def_id.expect_local()).fn_decl().unwrap().output { + hir::FnRetTy::DefaultReturn(span) => (tcx.def_span(impl_m_def_id), span, "-> ", " "), + hir::FnRetTy::Return(ty) => (ty.span, ty.span, "", ""), + }; + let trait_return_span = + tcx.hir().get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output { + hir::FnRetTy::DefaultReturn(_) => tcx.def_span(trait_m_def_id), + hir::FnRetTy::Return(ty) => ty.span, + }); + + let span = unmatched_bound.unwrap_or(span); + tcx.emit_spanned_lint( + REFINING_IMPL_TRAIT, + tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()), + span, + crate::errors::ReturnPositionImplTraitInTraitRefined { + impl_return_span, + trait_return_span, + pre, + post, + return_ty, + unmatched_bound, + }, + ); +} + +fn type_visibility<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<ty::Visibility<DefId>> { + match *ty.kind() { + ty::Ref(_, ty, _) => type_visibility(tcx, ty), + ty::Adt(def, args) => { + if def.is_fundamental() { + type_visibility(tcx, args.type_at(0)) + } else { + Some(tcx.visibility(def.did())) + } + } + _ => None, + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 495e663666c..1298c086087 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -162,8 +162,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }; let generics = tcx.generics_of(def_id); - let parent_count = generics.parent_count as u32; - let has_own_self = generics.has_self && parent_count == 0; // Below we'll consider the bounds on the type parameters (including `Self`) // and the explicit where-clauses, but to get the full set of predicates @@ -189,17 +187,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id))); } - // Collect the region predicates that were declared inline as - // well. In the case of parameters declared on a fn or method, we - // have to be careful to only iterate over early-bound regions. - let mut index = parent_count - + has_own_self as u32 - + super::early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32; - - trace!(?predicates); - trace!(?ast_generics); - trace!(?generics); - // Collect the predicates that were written inline by the user on each // type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates // for each const parameter. @@ -208,10 +195,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We already dealt with early bound lifetimes above. GenericParamKind::Lifetime { .. } => (), GenericParamKind::Type { .. } => { - let name = param.name.ident().name; - let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); - index += 1; - + let param_ty = icx.astconv().hir_id_to_bound_ty(param.hir_id); let mut bounds = Bounds::default(); // Params are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized( @@ -225,23 +209,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend(bounds.clauses()); trace!(?predicates); } - GenericParamKind::Const { .. } => { - let name = param.name.ident().name; - let param_const = ty::ParamConst::new(index, name); - + hir::GenericParamKind::Const { .. } => { let ct_ty = tcx .type_of(param.def_id.to_def_id()) .no_bound_vars() .expect("const parameters cannot be generic"); - - let ct = ty::Const::new_param(tcx, param_const, ct_ty); - + let ct = icx.astconv().hir_id_to_bound_const(param.hir_id, ct_ty); predicates.insert(( ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), param.span, )); - - index += 1; } } } @@ -252,8 +229,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { let ty = icx.to_ty(bound_pred.bounded_ty); - let bound_vars = icx.tcx.late_bound_vars(bound_pred.hir_id); - + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` // is still checked for WF. @@ -296,7 +272,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen _ => bug!(), }; let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) - .to_predicate(icx.tcx); + .to_predicate(tcx); (pred, span) })) } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6dd0c840de6..2bee2727725 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -849,6 +849,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { + walk_list!(this, visit_generic_param, generics.params); for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} @@ -865,90 +866,86 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } } - for predicate in generics.predicates { - match predicate { - &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - hir_id, - bounded_ty, - bounds, - bound_generic_params, - origin, - .. - }) => { - let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = - bound_generic_params - .iter() - .enumerate() - .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(this.tcx, &pair.1, param); - (pair, r) - }) - .unzip(); - this.record_late_bound_vars(hir_id, binders.clone()); - // Even if there are no lifetimes defined here, we still wrap it in a binder - // scope. If there happens to be a nested poly trait ref (an error), that - // will be `Concatenating` anyways, so we don't have to worry about the depth - // being wrong. - let scope = Scope::Binder { - hir_id, - bound_vars, - s: this.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: Some(origin), - }; - this.with(scope, |this| { - this.visit_ty(&bounded_ty); - walk_list!(this, visit_param_bound, bounds); + walk_list!(this, visit_where_predicate, generics.predicates); + }) + } + + fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>) { + match predicate { + &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + hir_id, + bounded_ty, + bounds, + bound_generic_params, + origin, + .. + }) => { + let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = + bound_generic_params + .iter() + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = ResolvedArg::late(late_bound_idx as u32, param); + let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); + (pair, r) }) - } - &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - lifetime, - bounds, - .. - }) => { - this.visit_lifetime(lifetime); - walk_list!(this, visit_param_bound, bounds); - - if lifetime.res != hir::LifetimeName::Static { - for bound in bounds { - let hir::GenericBound::Outlives(lt) = bound else { - continue; - }; - if lt.res != hir::LifetimeName::Static { - continue; - } - this.insert_lifetime(lt, ResolvedArg::StaticLifetime); - this.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_LIFETIMES, - lifetime.hir_id, - lifetime.ident.span, - format!( - "unnecessary lifetime parameter `{}`", - lifetime.ident - ), - |lint| { - let help = format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime.ident, - ); - lint.help(help) - }, - ); - } + .unzip(); + self.record_late_bound_vars(hir_id, binders.clone()); + // Even if there are no lifetimes defined here, we still wrap it in a binder + // scope. If there happens to be a nested poly trait ref (an error), that + // will be `Concatenating` anyways, so we don't have to worry about the depth + // being wrong. + let scope = Scope::Binder { + hir_id, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: Some(origin), + }; + self.with(scope, |this| { + walk_list!(this, visit_generic_param, bound_generic_params); + this.visit_ty(&bounded_ty); + walk_list!(this, visit_param_bound, bounds); + }) + } + &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + lifetime, + bounds, + .. + }) => { + self.visit_lifetime(lifetime); + walk_list!(self, visit_param_bound, bounds); + + if lifetime.res != hir::LifetimeName::Static { + for bound in bounds { + let hir::GenericBound::Outlives(lt) = bound else { + continue; + }; + if lt.res != hir::LifetimeName::Static { + continue; } - } - &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - lhs_ty, - rhs_ty, - .. - }) => { - this.visit_ty(lhs_ty); - this.visit_ty(rhs_ty); + self.insert_lifetime(lt, ResolvedArg::StaticLifetime); + self.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_LIFETIMES, + lifetime.hir_id, + lifetime.ident.span, + format!("unnecessary lifetime parameter `{}`", lifetime.ident), + |lint| { + let help = format!( + "you can use the `'static` lifetime directly, in place of `{}`", + lifetime.ident, + ); + lint.help(help) + }, + ); } } } - }) + &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { + self.visit_ty(lhs_ty); + self.visit_ty(rhs_ty); + } + } } fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { @@ -986,6 +983,18 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { intravisit::walk_anon_const(this, c); }); } + + fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { + match p.kind { + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + self.resolve_type_ref(p.def_id, p.hir_id); + } + GenericParamKind::Lifetime { .. } => { + // No need to resolve lifetime params, we don't use them for things + // like implicit `?Sized` or const-param-has-ty predicates. + } + } + } } fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9471ad9ca90..7614913f4bf 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -919,6 +919,22 @@ pub struct UnusedAssociatedTypeBounds { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_rpitit_refined)] +#[note] +pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { + #[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")] + pub impl_return_span: Span, + #[label] + pub trait_return_span: Option<Span>, + #[label(hir_analysis_unmatched_bound_label)] + pub unmatched_bound: Option<Span>, + + pub pre: &'static str, + pub post: &'static str, + pub return_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_assoc_bound_on_const)] #[note] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 4f95174f869..b0f333b79ca 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -237,6 +237,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); + // Freeze definitions as we don't add new ones at this point. This improves performance by + // allowing lock-free access to them. + tcx.untracked().definitions.freeze(); + // FIXME: Remove this when we implement creating `DefId`s // for anon constants during their parents' typeck. // Typeck all body owners in parallel will produce queries diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 6a817122491..566dc09cdd2 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -643,17 +643,14 @@ fn check_must_not_suspend_ty<'tcx>( } ty::Array(ty, len) => { let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + let target_usize = + len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize; + let plural_len = target_usize.saturating_add(1); check_must_not_suspend_ty( fcx, ty, hir_id, - SuspendCheckData { - descr_pre, - plural_len: len.try_eval_target_usize(fcx.tcx, fcx.param_env).unwrap_or(0) - as usize - + 1, - ..data - }, + SuspendCheckData { descr_pre, plural_len, ..data }, ) } // If drop tracking is enabled, we want to look through references, since the referent diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 0cfaf583774..7719482890e 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -48,18 +48,6 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { join( move || { - sess.time("incr_comp_persist_result_cache", || { - // Drop the memory map so that we can remove the file and write to it. - if let Some(odc) = &tcx.query_system.on_disk_cache { - odc.drop_serialized_data(tcx); - } - - file_format::save_in(sess, query_cache_path, "query cache", |e| { - encode_query_cache(tcx, e) - }); - }); - }, - move || { sess.time("incr_comp_persist_dep_graph", || { if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) { sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err }); @@ -73,6 +61,20 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { } }); }, + move || { + // We execute this after `incr_comp_persist_dep_graph` for the serial compiler + // to catch any potential query execution writing to the dep graph. + sess.time("incr_comp_persist_result_cache", || { + // Drop the memory map so that we can remove the file and write to it. + if let Some(odc) = &tcx.query_system.on_disk_cache { + odc.drop_serialized_data(tcx); + } + + file_format::save_in(sess, query_cache_path, "query cache", |e| { + encode_query_cache(tcx, e) + }); + }); + }, ); }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index aaabf1482e2..dabebe0adc0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -764,13 +764,13 @@ impl<'tcx> InferCtxt<'tcx> { .collect(); vars.extend( (0..inner.int_unification_table().len()) - .map(|i| ty::IntVid { index: i as u32 }) + .map(|i| ty::IntVid::from_u32(i as u32)) .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none()) .map(|v| Ty::new_int_var(self.tcx, v)), ); vars.extend( (0..inner.float_unification_table().len()) - .map(|i| ty::FloatVid { index: i as u32 }) + .map(|i| ty::FloatVid::from_u32(i as u32)) .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none()) .map(|v| Ty::new_float_var(self.tcx, v)), ); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5b417e008cf..a0f0b530bae 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -279,6 +279,12 @@ pub struct Config { /// Registry of diagnostics codes. pub registry: Registry, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec<String>, } // JUSTIFICATION: before session exists, only config @@ -317,6 +323,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.make_codegen_backend, registry.clone(), config.ice_file, + config.expanded_args, ); if let Some(parse_sess_created) = config.parse_sess_created { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c8b1ba5694e..e5ae6d5b5d6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -8,7 +8,7 @@ use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; +use rustc_data_structures::sync::{Lrc, OnceLock, WorkerLocal}; use rustc_errors::PResult; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; @@ -584,7 +584,7 @@ fn resolver_for_lowering<'tcx>( let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver); // Make sure we don't mutate the cstore from here on. - tcx.untracked().cstore.leak(); + tcx.untracked().cstore.freeze(); let ty::ResolverOutputs { global_ctxt: untracked_resolutions, @@ -689,7 +689,7 @@ pub fn create_global_ctxt<'tcx>( lint_store: Lrc<LintStore>, dep_graph: DepGraph, untracked: Untracked, - gcx_cell: &'tcx OnceCell<GlobalCtxt<'tcx>>, + gcx_cell: &'tcx OnceLock<GlobalCtxt<'tcx>>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>, ) -> &'tcx GlobalCtxt<'tcx> { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index fc71c6c7e9a..29a5837eb7c 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal}; +use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, WorkerLocal}; use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::DepGraphFuture; @@ -78,7 +78,7 @@ impl<T> Default for Query<T> { pub struct Queries<'tcx> { compiler: &'tcx Compiler, - gcx_cell: OnceCell<GlobalCtxt<'tcx>>, + gcx_cell: OnceLock<GlobalCtxt<'tcx>>, arena: WorkerLocal<Arena<'tcx>>, hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>, @@ -93,7 +93,7 @@ impl<'tcx> Queries<'tcx> { pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { Queries { compiler, - gcx_cell: OnceCell::new(), + gcx_cell: OnceLock::new(), arena: WorkerLocal::new(|_| Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), parse: Default::default(), @@ -193,11 +193,11 @@ impl<'tcx> Queries<'tcx> { self.compiler.register_lints.as_deref(), &pre_configured_attrs, )); - let cstore = RwLock::new(Box::new(CStore::new( + let cstore = FreezeLock::new(Box::new(CStore::new( self.codegen_backend().metadata_loader(), stable_crate_id, )) as _); - let definitions = RwLock::new(Definitions::new(stable_crate_id)); + let definitions = FreezeLock::new(Definitions::new(stable_crate_id)); let source_span = AppendOnlyIndexVec::new(); let _id = source_span.push(krate.spans.inner_span); debug_assert_eq!(_id, CRATE_DEF_ID); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index b53ba251bcd..ccf8b5630d4 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -68,6 +68,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se None, "", None, + Default::default(), ); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 5c9b39cdbe3..37e242c6e40 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -71,6 +71,7 @@ pub fn create_session( >, descriptions: Registry, ice_file: Option<PathBuf>, + expanded_args: Vec<String>, ) -> (Session, Box<dyn CodegenBackend>) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) @@ -113,6 +114,7 @@ pub fn create_session( target_override, rustc_version_str().unwrap_or("unknown"), ice_file, + expanded_args, ); codegen_backend.init(&sess); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7f7f36ca170..ba50c9e00e3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -156,15 +156,6 @@ lint_builtin_unused_doc_comment = unused doc comment lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` -lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} - -lint_check_name_removed = lint `{$lint_name}` has been removed: {$reason} - -lint_check_name_renamed = lint `{$lint_name}` has been renamed to `{$replace}` - -lint_check_name_unknown = unknown lint: `{$lint_name}` - .help = did you mean: `{$suggestion}` - lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` lint_command_line_source = `forbid` lint level was set on command line @@ -187,6 +178,7 @@ lint_default_source = `forbid` lint level is the default for {$id} lint_deprecated_lint_name = lint name `{$name}` is deprecated and may not have an effect in the future. .suggestion = change it to + .help = change it to {$replace} lint_diag_out_of_impl = diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls @@ -528,6 +520,7 @@ lint_unknown_gated_lint = lint_unknown_lint = unknown lint: `{$name}` .suggestion = did you mean + .help = did you mean: `{$replace}` lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` .help = add `#![register_tool({$tool_name})]` to the crate root diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4b6917fdfdd..de228bdb850 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1001,8 +1001,22 @@ impl EarlyLintPass for UnusedDocComment { warn_if_doc(cx, arm_span, "match arms", &arm.attrs); } + fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) { + if let ast::PatKind::Struct(_, _, fields, _) = &pat.kind { + for field in fields { + warn_if_doc(cx, field.span, "pattern fields", &field.attrs); + } + } + } + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { warn_if_doc(cx, expr.span, "expressions", &expr.attrs); + + if let ExprKind::Struct(s) = &expr.kind { + for field in &s.fields { + warn_if_doc(cx, field.span, "expression fields", &field.attrs); + } + } } fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 9dfde84b552..7a336a8f694 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -16,10 +16,6 @@ use self::TargetLint::*; -use crate::errors::{ - CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown, - CheckNameUnknownTool, RequestedLevel, UnsupportedGroup, -}; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; @@ -330,58 +326,6 @@ impl LintStore { } } - /// Checks the validity of lint names derived from the command line. - pub fn check_lint_name_cmdline( - &self, - sess: &Session, - lint_name: &str, - level: Level, - registered_tools: &RegisteredTools, - ) { - let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); - if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) { - sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); - return; - } - match self.check_lint_name(lint_name_only, tool_name, registered_tools) { - CheckLintNameResult::Renamed(replace) => { - sess.emit_warning(CheckNameRenamed { - lint_name, - replace: &replace, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::Removed(reason) => { - sess.emit_warning(CheckNameRemoved { - lint_name, - reason: &reason, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::NoLint(suggestion) => { - sess.emit_err(CheckNameUnknown { - lint_name, - suggestion, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::Tool(Err((Some(_), new_name))) => { - sess.emit_warning(CheckNameDeprecated { - lint_name, - new_name: &new_name, - sub: RequestedLevel { level, lint_name }, - }); - } - CheckLintNameResult::NoTool => { - sess.emit_err(CheckNameUnknownTool { - tool_name: tool_name.unwrap(), - sub: RequestedLevel { level, lint_name }, - }); - } - _ => {} - }; - } - /// True if this symbol represents a lint group name. pub fn is_lint_group(&self, lint_name: Symbol) -> bool { debug!( @@ -1402,14 +1346,3 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> { err } } - -pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) { - match lint_name.split_once("::") { - Some((tool_name, lint_name)) => { - let tool_name = Symbol::intern(tool_name); - - (Some(tool_name), lint_name) - } - None => (None, lint_name), - } -} diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 211ea8f4347..d102e3a6c15 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -228,6 +228,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) => self.check_id(closure_id), _ => {} } + lint_callback!(self, check_expr_post, e); } fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) { diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 607875b3faa..eccea35c702 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,7 +1,5 @@ use crate::fluent_generated as fluent; -use rustc_errors::{ - AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage, -}; +use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -102,29 +100,6 @@ pub struct UnsupportedGroup { pub lint_group: String, } -pub struct CheckNameUnknown<'a> { - pub lint_name: &'a str, - pub suggestion: Option<Symbol>, - pub sub: RequestedLevel<'a>, -} - -impl IntoDiagnostic<'_> for CheckNameUnknown<'_> { - fn into_diagnostic( - self, - handler: &Handler, - ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(fluent::lint_check_name_unknown); - diag.code(rustc_errors::error_code!(E0602)); - if let Some(suggestion) = self.suggestion { - diag.help(fluent::lint_help); - diag.set_arg("suggestion", suggestion); - } - diag.set_arg("lint_name", self.lint_name); - diag.subdiagnostic(self.sub); - diag - } -} - #[derive(Diagnostic)] #[diag(lint_check_name_unknown_tool, code = "E0602")] pub struct CheckNameUnknownTool<'a> { @@ -132,30 +107,3 @@ pub struct CheckNameUnknownTool<'a> { #[subdiagnostic] pub sub: RequestedLevel<'a>, } - -#[derive(Diagnostic)] -#[diag(lint_check_name_renamed)] -pub struct CheckNameRenamed<'a> { - pub lint_name: &'a str, - pub replace: &'a str, - #[subdiagnostic] - pub sub: RequestedLevel<'a>, -} - -#[derive(Diagnostic)] -#[diag(lint_check_name_removed)] -pub struct CheckNameRemoved<'a> { - pub lint_name: &'a str, - pub reason: &'a str, - #[subdiagnostic] - pub sub: RequestedLevel<'a>, -} - -#[derive(Diagnostic)] -#[diag(lint_check_name_deprecated)] -pub struct CheckNameDeprecated<'a> { - pub lint_name: &'a str, - pub new_name: &'a str, - #[subdiagnostic] - pub sub: RequestedLevel<'a>, -} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f58782c0f22..df67cf5d12f 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,3 +1,8 @@ +use crate::errors::{CheckNameUnknownTool, RequestedLevel, UnsupportedGroup}; +use crate::lints::{ + DeprecatedLintNameFromCommandLine, RemovedLintFromCommandLine, RenamedLintFromCommandLine, + UnknownLintFromCommandLine, +}; use crate::{ builtin::MISSING_DOCS, context::{CheckLintNameResult, LintStore}, @@ -552,12 +557,55 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { fn add_command_line(&mut self) { for &(ref lint_name, level) in &self.sess.opts.lint_opts { - self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools); + // Checks the validity of lint names derived from the command line. + let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); + if lint_name_only == crate::WARNINGS.name_lower() + && matches!(level, Level::ForceWarn(_)) + { + self.sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); + } + match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) { + CheckLintNameResult::Renamed(ref replace) => { + let name = lint_name.as_str(); + let suggestion = RenamedLintSuggestion::WithoutSpan { replace }; + let requested_level = RequestedLevel { level, lint_name }; + let lint = RenamedLintFromCommandLine { name, suggestion, requested_level }; + self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); + } + CheckLintNameResult::Removed(ref reason) => { + let name = lint_name.as_str(); + let requested_level = RequestedLevel { level, lint_name }; + let lint = RemovedLintFromCommandLine { name, reason, requested_level }; + self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); + } + CheckLintNameResult::NoLint(suggestion) => { + let name = lint_name.clone(); + let suggestion = + suggestion.map(|replace| UnknownLintSuggestion::WithoutSpan { replace }); + let requested_level = RequestedLevel { level, lint_name }; + let lint = UnknownLintFromCommandLine { name, suggestion, requested_level }; + self.emit_lint(UNKNOWN_LINTS, lint); + } + CheckLintNameResult::Tool(Err((Some(_), ref replace))) => { + let name = lint_name.clone(); + let requested_level = RequestedLevel { level, lint_name }; + let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level }; + self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); + } + CheckLintNameResult::NoTool => { + self.sess.emit_err(CheckNameUnknownTool { + tool_name: tool_name.unwrap(), + sub: RequestedLevel { level, lint_name }, + }); + } + _ => {} + }; + let orig_level = level; let lint_flag_val = Symbol::intern(lint_name); let Ok(ids) = self.store.find_lints(&lint_name) else { - // errors handled in check_lint_name_cmdline above + // errors already handled above continue; }; for id in ids { @@ -915,24 +963,18 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { _ if !self.warn_about_weird_lints => {} - CheckLintNameResult::Renamed(new_name) => { + CheckLintNameResult::Renamed(ref replace) => { let suggestion = - RenamedLintSuggestion { suggestion: sp, replace: new_name.as_str() }; + RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - self.emit_spanned_lint( - RENAMED_AND_REMOVED_LINTS, - sp.into(), - RenamedLint { name: name.as_str(), suggestion }, - ); + let lint = RenamedLint { name: name.as_str(), suggestion }; + self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } - CheckLintNameResult::Removed(reason) => { + CheckLintNameResult::Removed(ref reason) => { let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - self.emit_spanned_lint( - RENAMED_AND_REMOVED_LINTS, - sp.into(), - RemovedLint { name: name.as_str(), reason: reason.as_str() }, - ); + let lint = RemovedLint { name: name.as_str(), reason }; + self.emit_spanned_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } CheckLintNameResult::NoLint(suggestion) => { @@ -941,13 +983,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } else { name.to_string() }; - let suggestion = suggestion - .map(|replace| UnknownLintSuggestion { suggestion: sp, replace }); - self.emit_spanned_lint( - UNKNOWN_LINTS, - sp.into(), - UnknownLint { name, suggestion }, - ); + let suggestion = suggestion.map(|replace| { + UnknownLintSuggestion::WithSpan { suggestion: sp, replace } + }); + let lint = UnknownLint { name, suggestion }; + self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint); } } // If this lint was renamed, apply the new lint instead of ignoring the attribute. @@ -1092,3 +1132,14 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers }; } + +pub fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) { + match lint_name.split_once("::") { + Some((tool_name, lint_name)) => { + let tool_name = Symbol::intern(tool_name); + + (Some(tool_name), lint_name) + } + None => (None, lint_name), + } +} diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0e942d774a7..3e26d6dc32d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,6 +2,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] use std::num::NonZeroU32; +use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString, @@ -1013,6 +1014,16 @@ pub struct DeprecatedLintName<'a> { } #[derive(LintDiagnostic)] +#[diag(lint_deprecated_lint_name)] +#[help] +pub struct DeprecatedLintNameFromCommandLine<'a> { + pub name: String, + pub replace: &'a str, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, +} + +#[derive(LintDiagnostic)] #[diag(lint_renamed_lint)] pub struct RenamedLint<'a> { pub name: &'a str, @@ -1021,11 +1032,25 @@ pub struct RenamedLint<'a> { } #[derive(Subdiagnostic)] -#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] -pub struct RenamedLintSuggestion<'a> { - #[primary_span] - pub suggestion: Span, - pub replace: &'a str, +pub enum RenamedLintSuggestion<'a> { + #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] + WithSpan { + #[primary_span] + suggestion: Span, + replace: &'a str, + }, + #[help(lint_help)] + WithoutSpan { replace: &'a str }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_renamed_lint)] +pub struct RenamedLintFromCommandLine<'a> { + pub name: &'a str, + #[subdiagnostic] + pub suggestion: RenamedLintSuggestion<'a>, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, } #[derive(LintDiagnostic)] @@ -1036,6 +1061,15 @@ pub struct RemovedLint<'a> { } #[derive(LintDiagnostic)] +#[diag(lint_removed_lint)] +pub struct RemovedLintFromCommandLine<'a> { + pub name: &'a str, + pub reason: &'a str, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, +} + +#[derive(LintDiagnostic)] #[diag(lint_unknown_lint)] pub struct UnknownLint { pub name: String, @@ -1044,11 +1078,25 @@ pub struct UnknownLint { } #[derive(Subdiagnostic)] -#[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] -pub struct UnknownLintSuggestion { - #[primary_span] - pub suggestion: Span, - pub replace: Symbol, +pub enum UnknownLintSuggestion { + #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] + WithSpan { + #[primary_span] + suggestion: Span, + replace: Symbol, + }, + #[help(lint_help)] + WithoutSpan { replace: Symbol }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unknown_lint, code = "E0602")] +pub struct UnknownLintFromCommandLine<'a> { + pub name: String, + #[subdiagnostic] + pub suggestion: Option<UnknownLintSuggestion>, + #[subdiagnostic] + pub requested_level: RequestedLevel<'a>, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 16964565b01..fca0eeeecc4 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -153,6 +153,7 @@ macro_rules! early_lint_methods { fn check_pat(a: &ast::Pat); fn check_pat_post(a: &ast::Pat); fn check_expr(a: &ast::Expr); + fn check_expr_post(a: &ast::Expr); fn check_ty(a: &ast::Ty); fn check_generic_arg(a: &ast::GenericArg); fn check_generic_param(a: &ast::GenericParam); diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 883f6242b56..d540f473ae8 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -128,7 +128,11 @@ fn is_operation_we_care_about<'tcx>( fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { let e = e.peel_blocks(); - fn from_casts<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + fn from_casts<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'tcx>, + need_check_freeze: &mut bool, + ) -> Option<&'tcx Expr<'tcx>> { // <expr> as *mut ... let mut e = if let ExprKind::Cast(e, t) = e.kind && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() { @@ -138,6 +142,14 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) { expr + // UnsafeCell::raw_get(<expr>) + } else if let ExprKind::Call(path, [arg]) = e.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) + { + *need_check_freeze = true; + arg } else { return None; }; @@ -160,11 +172,18 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) { had_at_least_one_cast = true; expr - // ptr::from_ref(<expr>) + // ptr::from_ref(<expr>) or UnsafeCell::raw_get(<expr>) } else if let ExprKind::Call(path, [arg]) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) { + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_from_ref | sym::unsafe_cell_raw_get) + ) + { + if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) { + *need_check_freeze = true; + } return Some(arg); } else if had_at_least_one_cast { return Some(e); @@ -190,10 +209,25 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) } } - let Some(e) = from_casts(cx, e).or_else(|| from_transmute(cx, e)) else { + let mut need_check_freeze = false; + let Some(e) = from_casts(cx, e, &mut need_check_freeze).or_else(|| from_transmute(cx, e)) + else { return false; }; let e = e.peel_blocks(); - matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(_, _, Mutability::Not)) + let node_type = cx.typeck_results().node_type(e.hir_id); + if let ty::Ref(_, inner_ty, Mutability::Not) = node_type.kind() { + // If an UnsafeCell method is involved we need to additionaly check the + // inner type for the presence of the Freeze trait (ie does NOT contain + // an UnsafeCell), since in that case we would incorrectly lint on valid casts. + // + // We also consider non concrete skeleton types (ie generics) + // to be an issue since there is no way to make it safe for abitrary types. + !need_check_freeze + || inner_ty.is_freeze(cx.tcx, cx.param_env) + || !inner_ty.has_concrete_skeleton() + } else { + false + } } diff --git a/compiler/rustc_lint/src/tests.rs b/compiler/rustc_lint/src/tests.rs index fc9d6f636b2..4fd054cb717 100644 --- a/compiler/rustc_lint/src/tests.rs +++ b/compiler/rustc_lint/src/tests.rs @@ -1,4 +1,4 @@ -use crate::context::parse_lint_and_tool_name; +use crate::levels::parse_lint_and_tool_name; use rustc_span::{create_default_session_globals_then, Symbol}; #[test] diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 56508a2a6cc..e812493b3dd 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { }; let def_id = trait_predicate.trait_ref.def_id; if cx.tcx.lang_items().drop_trait() == Some(def_id) { - // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern. + // Explicitly allow `impl Drop`, a drop-guards-as-unnameable-type pattern. if trait_predicate.trait_ref.self_ty().is_impl_trait() { continue; } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fc4c29eb36d..c38c6337b7b 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -917,8 +917,8 @@ pub(crate) fn repr_nullable_ptr<'tcx>( // At this point, the field's type is known to be nonnull and the parent enum is Option-like. // If the computed size for the field and the enum are different, the nonnull optimization isn't // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).unwrap(); - if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) { + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).ok(); + if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { bug!("improper_ctypes: Option nonnull optimization not applied?"); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 6041f80753b..39e6fb805ae 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -955,11 +955,14 @@ declare_lint! { pub struct UnusedParens { with_self_ty_parens: bool, + /// `1 as (i32) < 2` parses to ExprKind::Lt + /// `1 as i32 < 2` parses to i32::<2[missing angle bracket] + parens_in_cast_in_lt: Vec<ast::NodeId>, } impl UnusedParens { pub fn new() -> Self { - Self { with_self_ty_parens: false } + Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() } } } @@ -1055,6 +1058,14 @@ impl UnusedParens { impl EarlyLintPass for UnusedParens { #[inline] fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { + if let ExprKind::Binary(op, lhs, _rhs) = &e.kind && + (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) && + let ExprKind::Cast(_expr, ty) = &lhs.kind && + let ast::TyKind::Paren(_) = &ty.kind + { + self.parens_in_cast_in_lt.push(ty.id); + } + match e.kind { ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => { self.check_unused_parens_pat(cx, pat, false, false, (true, true)); @@ -1101,6 +1112,17 @@ impl EarlyLintPass for UnusedParens { <Self as UnusedDelimLint>::check_expr(self, cx, e) } + fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) { + if let ExprKind::Binary(op, lhs, _rhs) = &e.kind && + (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) && + let ExprKind::Cast(_expr, ty) = &lhs.kind && + let ast::TyKind::Paren(_) = &ty.kind + { + let id = self.parens_in_cast_in_lt.pop().expect("check_expr and check_expr_post must balance"); + assert_eq!(id, ty.id, "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"); + } + } + fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) { use ast::{Mutability, PatKind::*}; let keep_space = (false, false); @@ -1141,6 +1163,11 @@ impl EarlyLintPass for UnusedParens { } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { + if let ast::TyKind::Paren(_) = ty.kind && + Some(&ty.id) == self.parens_in_cast_in_lt.last() + { + return; + } match &ty.kind { ast::TyKind::Array(_, len) => { self.check_unused_delims_expr( diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7e745de4f1a..2567e273e11 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3381,6 +3381,7 @@ declare_lint_pass! { PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + REFINING_IMPL_TRAIT, RENAMED_AND_REMOVED_LINTS, REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, @@ -4363,7 +4364,7 @@ declare_lint! { /// pub struct S; /// } /// - /// pub fn get_voldemort() -> m::S { m::S } + /// pub fn get_unnameable() -> m::S { m::S } /// # fn main() {} /// ``` /// @@ -4448,7 +4449,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// /// #![deny(ambiguous_glob_imports)] /// pub fn foo() -> u32 { /// use sub::*; @@ -4485,6 +4485,50 @@ declare_lint! { } declare_lint! { + /// The `refining_impl_trait` lint detects usages of return-position impl + /// traits in trait signatures which are refined by implementations. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(return_position_impl_trait_in_trait)] + /// #![deny(refining_impl_trait)] + /// + /// use std::fmt::Display; + /// + /// pub trait AsDisplay { + /// fn as_display(&self) -> impl Display; + /// } + /// + /// impl<'s> AsDisplay for &'s str { + /// fn as_display(&self) -> Self { + /// *self + /// } + /// } + /// + /// fn main() { + /// // users can observe that the return type of + /// // `<&str as AsDisplay>::as_display()` is `&str`. + /// let x: &str = "".as_display(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Return-position impl trait in traits (RPITITs) desugar to associated types, + /// and callers of methods for types where the implementation is known are + /// able to observe the types written in the impl signature. This may be + /// intended behavior, but may also pose a semver hazard for authors of libraries + /// who do not wish to make stronger guarantees about the types than what is + /// written in the trait signature. + pub REFINING_IMPL_TRAIT, + Warn, + "impl trait in impl method signature does not match trait method signature", +} + +declare_lint! { /// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes /// that were erroneously allowed in associated constants. /// diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 4302b161833..f606fa483ca 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -252,7 +252,10 @@ fn main() { } else if target.contains("windows-gnu") { println!("cargo:rustc-link-lib=shell32"); println!("cargo:rustc-link-lib=uuid"); - } else if target.contains("haiku") || target.contains("darwin") { + } else if target.contains("haiku") + || target.contains("darwin") + || (is_crossed && (target.contains("dragonfly") || target.contains("solaris"))) + { println!("cargo:rustc-link-lib=z"); } else if target.contains("netbsd") { println!("cargo:rustc-link-lib=z"); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 6af5c24c458..fefb1e0fbe0 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1,5 +1,6 @@ #include <stdio.h> +#include <cstddef> #include <iomanip> #include <vector> #include <set> @@ -9,6 +10,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/AssemblyAnnotationWriter.h" @@ -50,6 +52,8 @@ using namespace llvm; +static codegen::RegisterCodeGenFlags CGF; + typedef struct LLVMOpaquePass *LLVMPassRef; typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; @@ -406,7 +410,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, - bool ForceEmulatedTls) { + const char *DebugInfoCompression, + bool ForceEmulatedTls, + const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) { auto OptLevel = fromRust(RustOptLevel); auto RM = fromRust(RustReloc); @@ -421,7 +427,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( return nullptr; } - TargetOptions Options; + TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Trip); Options.FloatABIType = FloatABI::Default; if (UseSoftFloat) { @@ -436,6 +442,16 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( if (SplitDwarfFile) { Options.MCOptions.SplitDwarfFile = SplitDwarfFile; } +#if LLVM_VERSION_GE(16, 0) + if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) { + Options.CompressDebugSections = DebugCompressionType::Zlib; + } else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) { + Options.CompressDebugSections = DebugCompressionType::Zstd; + } else if (!strcmp("none", DebugInfoCompression)) { + Options.CompressDebugSections = DebugCompressionType::None; + } +#endif + Options.RelaxELFRelocations = RelaxELFRelocations; Options.UseInitArray = UseInitArray; @@ -462,12 +478,48 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; + + if (ArgsCstrBuff != nullptr) + { + int buffer_offset = 0; + assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); + + const size_t arg0_len = std::strlen(ArgsCstrBuff); + char* arg0 = new char[arg0_len + 1]; + memcpy(arg0, ArgsCstrBuff, arg0_len); + arg0[arg0_len] = '\0'; + buffer_offset += arg0_len + 1; + + const int num_cmd_arg_strings = + std::count(&ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0'); + + std::string* cmd_arg_strings = new std::string[num_cmd_arg_strings]; + for (int i = 0; i < num_cmd_arg_strings; ++i) + { + assert(buffer_offset < ArgsCstrBuffLen); + const int len = std::strlen(ArgsCstrBuff + buffer_offset); + cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len); + buffer_offset += len + 1; + } + + assert(buffer_offset == ArgsCstrBuffLen); + + Options.MCOptions.Argv0 = arg0; + Options.MCOptions.CommandLineArgs = + llvm::ArrayRef<std::string>(cmd_arg_strings, num_cmd_arg_strings); + } + TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); return wrap(TM); } extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { + + MCTargetOptions& MCOptions = unwrap(TM)->Options.MCOptions; + delete[] MCOptions.Argv0; + delete[] MCOptions.CommandLineArgs.data(); + delete unwrap(TM); } @@ -1058,6 +1110,13 @@ extern "C" void LLVMRustPrintPasses() { extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, size_t Len) { auto PreserveFunctions = [=](const GlobalValue &GV) { + // Preserve LLVM-injected, ASAN-related symbols. + // See also https://github.com/rust-lang/rust/issues/113404. + if (GV.getName() == "___asan_globals_registered") { + return true; + } + + // Preserve symbols exported from Rust modules. for (size_t I = 0; I < Len; I++) { if (GV.getName() == Symbols[I]) { return true; @@ -1202,7 +1261,11 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, Ret->ModuleMap[module->identifier] = mem_buffer; +#if LLVM_VERSION_GE(18, 0) + if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index)) { +#else if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) { +#endif LLVMRustSetLastError(toString(std::move(Err)).c_str()); return nullptr; } @@ -1507,6 +1570,38 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data, return BitcodeOrError->getBufferStart(); } +// Find a section of an object file by name. Fail if the section is missing or +// empty. +extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, + size_t len, + const char *name, + size_t *out_len) { + *out_len = 0; + StringRef Data(data, len); + MemoryBufferRef Buffer(Data, ""); // The id is unused. + file_magic Type = identify_magic(Buffer.getBuffer()); + Expected<std::unique_ptr<object::ObjectFile>> ObjFileOrError = + object::ObjectFile::createObjectFile(Buffer, Type); + if (!ObjFileOrError) { + LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str()); + return nullptr; + } + for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) { + Expected<StringRef> Name = Sec.getName(); + if (Name && *Name == name) { + Expected<StringRef> SectionOrError = Sec.getContents(); + if (!SectionOrError) { + LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str()); + return nullptr; + } + *out_len = SectionOrError->size(); + return SectionOrError->data(); + } + } + LLVMRustSetLastError("could not find requested section"); + return nullptr; +} + // Computes the LTO cache key for the provided 'ModId' in the given 'Data', // storing the result in 'KeyOut'. // Currently, this cache key is a SHA-1 hash of anything that could affect diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 70cdf3d6d23..4390486b0de 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -2044,3 +2044,19 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) { } return false; } + +extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() { +#if LLVM_VERSION_GE(16, 0) + return llvm::compression::zlib::isAvailable(); +#else + return false; +#endif +} + +extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() { +#if LLVM_VERSION_GE(16, 0) + return llvm::compression::zstd::isAvailable(); +#else + return false; +#endif +} diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index fce80ab37dd..69221475356 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -8,7 +8,7 @@ use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, All use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard}; +use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; use rustc_expand::base::SyntaxExtension; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; @@ -134,14 +134,14 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { } impl CStore { - pub fn from_tcx(tcx: TyCtxt<'_>) -> MappedReadGuard<'_, CStore> { - ReadGuard::map(tcx.untracked().cstore.read(), |cstore| { + pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> { + FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| { cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`") }) } - pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> MappedWriteGuard<'_, CStore> { - WriteGuard::map(tcx.untracked().cstore.write(), |cstore| { + pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> { + FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| { cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`") }) } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 87373d99743..99fef84931e 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -42,6 +42,6 @@ pub mod locator; pub use fs::{emit_wrapper_file, METADATA_FILENAME}; pub use native_libs::find_native_static_library; -pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER}; +pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER}; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 05e608c0d1a..7fd3c0f494a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -9,7 +9,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc, OnceCell}; +use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc, OnceLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; @@ -93,7 +93,7 @@ pub(crate) struct CrateMetadata { /// For every definition in this crate, maps its `DefPathHash` to its `DefIndex`. def_path_hash_map: DefPathHashMapRef<'static>, /// Likewise for ExpnHash. - expn_hash_map: OnceCell<UnhashMap<ExpnHash, ExpnIndex>>, + expn_hash_map: OnceLock<UnhashMap<ExpnHash, ExpnIndex>>, /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_state: AllocDecodingState, /// Caches decoded `DefKey`s. @@ -1501,11 +1501,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // We can't reuse an existing SourceFile, so allocate a new one // containing the information we need. + let original_end_pos = source_file_to_import.end_position(); let rustc_span::SourceFile { mut name, src_hash, - start_pos, - end_pos, + start_pos: original_start_pos, + source_len, lines, multibyte_chars, non_narrow_chars, @@ -1547,35 +1548,32 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // on `try_to_translate_virtual_to_real`). try_to_translate_virtual_to_real(&mut name); - let source_length = (end_pos - start_pos).to_usize(); - let local_version = sess.source_map().new_imported_source_file( name, src_hash, name_hash, - source_length, + source_len.to_u32(), self.cnum, lines, multibyte_chars, non_narrow_chars, normalized_pos, - start_pos, source_file_index, ); debug!( "CrateMetaData::imported_source_files alloc \ - source_file {:?} original (start_pos {:?} end_pos {:?}) \ - translated (start_pos {:?} end_pos {:?})", + source_file {:?} original (start_pos {:?} source_len {:?}) \ + translated (start_pos {:?} source_len {:?})", local_version.name, - start_pos, - end_pos, + original_start_pos, + source_len, local_version.start_pos, - local_version.end_pos + local_version.source_len ); ImportedSourceFile { - original_start_pos: start_pos, - original_end_pos: end_pos, + original_start_pos, + original_end_pos, translated_source_file: local_version, } }) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index aeda8af6d2c..f964a8c76c0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -131,7 +131,7 @@ macro_rules! provide_one { $tcx.ensure().crate_hash($def_id.krate); } - let cdata = rustc_data_structures::sync::MappedReadGuard::map(CStore::from_tcx($tcx), |c| { + let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| { c.get_crate_data($def_id.krate).cdata }); let $cdata = crate::creader::CrateMetadataRef { @@ -510,7 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { crates: |tcx, ()| { // The list of loaded crates is now frozen in query cache, // so make sure cstore is not mutably accessed from here on. - tcx.untracked().cstore.leak(); + tcx.untracked().cstore.freeze(); tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) }, ..*providers diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ecb15c41eef..cc7ae932e11 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -14,11 +14,12 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{ - CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, + CrateNum, DefId, DefIndex, LocalDefId, LocalDefIdSet, CRATE_DEF_ID, CRATE_DEF_INDEX, + LOCAL_CRATE, }; use rustc_hir::definitions::DefPathData; -use rustc_hir::intravisit; use rustc_hir::lang_items::LangItem; +use rustc_hir_pretty::id_to_string; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -50,7 +51,6 @@ pub(super) struct EncodeContext<'a, 'tcx> { opaque: opaque::FileEncoder, tcx: TyCtxt<'tcx>, feat: &'tcx rustc_feature::Features, - tables: TableBuilders, lazy_state: LazyState, @@ -280,8 +280,8 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData { // All of this logic ensures that the final result of deserialization is a 'normal' // Span that can be used without any additional trouble. let metadata_index = { - // Introduce a new scope so that we drop the 'lock()' temporary - match &*source_file.external_src.lock() { + // Introduce a new scope so that we drop the 'read()' temporary + match &*source_file.external_src.read() { ExternalSource::Foreign { metadata_index, .. } => *metadata_index, src => panic!("Unexpected external source {src:?}"), } @@ -1002,15 +1002,31 @@ fn should_encode_stability(def_kind: DefKind) -> bool { } } -/// Whether we should encode MIR. +/// Whether we should encode MIR. Return a pair, resp. for CTFE and for LLVM. /// /// Computing, optimizing and encoding the MIR is a relatively expensive operation. /// We want to avoid this work when not required. Therefore: /// - we only compute `mir_for_ctfe` on items with const-eval semantics; /// - we skip `optimized_mir` for check runs. +/// - we only encode `optimized_mir` that could be generated in other crates, that is, a code that +/// is either generic or has inline hint, and is reachable from the other crates (contained +/// in reachable set). +/// +/// Note: Reachable set describes definitions that might be generated or referenced from other +/// crates and it can be used to limit optimized MIR that needs to be encoded. On the other hand, +/// the reachable set doesn't have much to say about which definitions might be evaluated at compile +/// time in other crates, so it cannot be used to omit CTFE MIR. For example, `f` below is +/// unreachable and yet it can be evaluated in other crates: /// -/// Return a pair, resp. for CTFE and for LLVM. -fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { +/// ``` +/// const fn f() -> usize { 0 } +/// pub struct S { pub a: [usize; f()] } +/// ``` +fn should_encode_mir( + tcx: TyCtxt<'_>, + reachable_set: &LocalDefIdSet, + def_id: LocalDefId, +) -> (bool, bool) { match tcx.def_kind(def_id) { // Constructors DefKind::Ctor(_, _) => { @@ -1027,14 +1043,15 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { // Full-fledged functions + closures DefKind::AssocFn | DefKind::Fn | DefKind::Closure => { let generics = tcx.generics_of(def_id); - let needs_inline = (generics.requires_monomorphization(tcx) - || tcx.codegen_fn_attrs(def_id).requests_inline()) - && tcx.sess.opts.output_types.should_codegen(); + let opt = tcx.sess.opts.unstable_opts.always_encode_mir + || (tcx.sess.opts.output_types.should_codegen() + && reachable_set.contains(&def_id) + && (generics.requires_monomorphization(tcx) + || tcx.codegen_fn_attrs(def_id).requests_inline())); // The function has a `const` modifier or is in a `#[const_trait]`. let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); - let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; - (is_const_fn, needs_inline || always_encode_mir) + (is_const_fn, opt) } // Generators require optimized MIR to compute layout. DefKind::Generator => (false, true), @@ -1580,9 +1597,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } let tcx = self.tcx; + let reachable_set = tcx.reachable_set(()); let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| { - let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); + let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None } }); for (def_id, encode_const, encode_opt) in keys_and_jobs { @@ -1615,7 +1633,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs); let body_id = tcx.hir().maybe_body_owned_by(def_id); if let Some(body_id) = body_id { - let const_data = self.encode_rendered_const_for_body(body_id); + let const_data = rendered_const(self.tcx, body_id); record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data); } } @@ -1683,14 +1701,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> String { - let hir = self.tcx.hir(); - let body = hir.body(body_id); - rustc_hir_pretty::to_string(&(&hir as &dyn intravisit::Map<'_>), |s| { - s.print_expr(&body.value) - }) - } - #[instrument(level = "debug", skip(self))] fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; @@ -2075,8 +2085,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { return; } + let reachable_set = tcx.reachable_set(()); par_for_each_in(tcx.mir_keys(()), |&def_id| { - let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); + let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); if encode_const { tcx.ensure_with_value().mir_for_ctfe(def_id); @@ -2292,3 +2303,97 @@ pub fn provide(providers: &mut Providers) { ..*providers } } + +/// Build a textual representation of an unevaluated constant expression. +/// +/// If the const expression is too complex, an underscore `_` is returned. +/// For const arguments, it's `{ _ }` to be precise. +/// This means that the output is not necessarily valid Rust code. +/// +/// Currently, only +/// +/// * literals (optionally with a leading `-`) +/// * unit `()` +/// * blocks (`{ … }`) around simple expressions and +/// * paths without arguments +/// +/// are considered simple enough. Simple blocks are included since they are +/// necessary to disambiguate unit from the unit type. +/// This list might get extended in the future. +/// +/// Without this censoring, in a lot of cases the output would get too large +/// and verbose. Consider `match` expressions, blocks and deeply nested ADTs. +/// Further, private and `doc(hidden)` fields of structs would get leaked +/// since HIR datatypes like the `body` parameter do not contain enough +/// semantic information for this function to be able to hide them – +/// at least not without significant performance overhead. +/// +/// Whenever possible, prefer to evaluate the constant first and try to +/// use a different method for pretty-printing. Ideally this function +/// should only ever be used as a fallback. +pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: hir::BodyId) -> String { + let hir = tcx.hir(); + let value = &hir.body(body).value; + + #[derive(PartialEq, Eq)] + enum Classification { + Literal, + Simple, + Complex, + } + + use Classification::*; + + fn classify(expr: &hir::Expr<'_>) -> Classification { + match &expr.kind { + hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { + if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex } + } + hir::ExprKind::Lit(_) => Literal, + hir::ExprKind::Tup([]) => Simple, + hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => { + if classify(expr) == Complex { Complex } else { Simple } + } + // Paths with a self-type or arguments are too “complex” following our measure since + // they may leak private fields of structs (with feature `adt_const_params`). + // Consider: `<Self as Trait<{ Struct { private: () } }>>::CONSTANT`. + // Paths without arguments are definitely harmless though. + hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) => { + if segments.iter().all(|segment| segment.args.is_none()) { Simple } else { Complex } + } + // FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty + // contains const arguments. Is there a *concise* way to check for this? + hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple, + // FIXME: Can they contain const arguments and thus leak private struct fields? + hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple, + _ => Complex, + } + } + + let classification = classify(value); + + if classification == Literal + && !value.span.from_expansion() + && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) { + // For literals, we avoid invoking the pretty-printer and use the source snippet instead to + // preserve certain stylistic choices the user likely made for the sake legibility like + // + // * hexadecimal notation + // * underscores + // * character escapes + // + // FIXME: This passes through `-/*spacer*/0` verbatim. + snippet + } else if classification == Simple { + // Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and + // other formatting artifacts. + id_to_string(&hir, body.hir_id) + } else if tcx.def_kind(hir.body_owner_def_id(body).to_def_id()) == DefKind::AnonConst { + // FIXME: Omit the curly braces if the enclosing expression is an array literal + // with a repeated element (an `ExprKind::Repeat`) as in such case it + // would not actually need any disambiguation. + "{ _ }".to_owned() + } else { + "_".to_owned() + } +} diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 1f68e83e0ab..71269779d42 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -42,7 +42,7 @@ pub use decoder::provide_extern; use decoder::DecodeContext; pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use encoder::EncodeContext; -pub use encoder::{encode_metadata, EncodedMetadata}; +pub use encoder::{encode_metadata, rendered_const, EncodedMetadata}; use rustc_span::hygiene::SyntaxContextData; mod decoder; diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 04c09d33400..78a0f82db13 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -80,12 +80,56 @@ macro_rules! define_dep_nodes { } /// This enum serves as an index into arrays built by `make_dep_kind_array`. - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] + // This enum has more than u8::MAX variants so we need some kind of multi-byte + // encoding. The derived Encodable/Decodable uses leb128 encoding which is + // dense when only considering this enum. But DepKind is encoded in a larger + // struct, and there we can take advantage of the unused bits in the u16. + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[allow(non_camel_case_types)] + #[repr(u16)] pub enum DepKind { $( $( #[$attr] )* $variant),* } + impl DepKind { + // This const implements two things: A bounds check so that we can decode + // a DepKind from a u16 with just one check, and a const check that the + // discriminants of the variants have been assigned consecutively from 0 + // so that just the one comparison suffices to check that the u16 can be + // transmuted to a DepKind. + pub const VARIANTS: u16 = { + let deps: &[DepKind] = &[$(DepKind::$variant,)*]; + let mut i = 0; + while i < deps.len() { + if i as u16 != deps[i] as u16 { + panic!(); + } + i += 1; + } + deps.len() as u16 + }; + } + + impl<S: rustc_serialize::Encoder> rustc_serialize::Encodable<S> for DepKind { + #[inline] + fn encode(&self, s: &mut S) { + s.emit_u16(*self as u16); + } + } + + impl<D: rustc_serialize::Decoder> rustc_serialize::Decodable<D> for DepKind { + #[inline] + fn decode(d: &mut D) -> DepKind { + let discrim = d.read_u16(); + assert!(discrim < DepKind::VARIANTS); + // SAFETY: DepKind::VARIANTS checks that the discriminant values permit + // this one check to soundly guard the transmute. + unsafe { + std::mem::transmute::<u16, DepKind>(discrim) + } + } + } + pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> { match label { $(stringify!($variant) => Ok(DepKind::$variant),)* @@ -114,6 +158,8 @@ rustc_query_append!(define_dep_nodes![ [] fn CompileMonoItem() -> (), ]); +static_assert_size!(DepKind, 2); + // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index f79ce08b8ae..87436f9eeed 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -26,6 +26,7 @@ pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCt impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; const RED: Self = DepKind::Red; + const MAX: u16 = DepKind::VARIANTS - 1; fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}(", node.kind)?; @@ -68,6 +69,21 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { op(icx.task_deps) }) } + + #[track_caller] + #[inline] + fn from_u16(u: u16) -> Self { + if u > Self::MAX { + panic!("Invalid DepKind {u}"); + } + // SAFETY: See comment on DepKind::VARIANTS + unsafe { std::mem::transmute(u) } + } + + #[inline] + fn to_u16(self) -> u16 { + self as u16 + } } impl<'tcx> DepContext for TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3e8f07ed233..f67f8015c04 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1206,8 +1206,8 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); - if tcx.sess.opts.incremental_relative_spans() { - let definitions = tcx.definitions_untracked(); + if tcx.sess.opts.incremental.is_some() { + let definitions = tcx.untracked().definitions.freeze(); let mut owner_spans: Vec<_> = krate .owners .iter_enumerated() diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 81823118ab8..5011ea829dc 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -27,6 +27,7 @@ use crate::ty::GenericArg; use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; use rustc_macros::HashStable; use smallvec::SmallVec; +use std::fmt::Display; use std::ops::Index; /// A "canonicalized" type `V` is one where all free inference @@ -40,6 +41,16 @@ pub struct Canonical<'tcx, V> { pub variables: CanonicalVarInfos<'tcx>, } +impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", + self.value, self.max_universe, self.variables + ) + } +} + pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>; impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index f62e406692a..037f84f476f 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -225,6 +225,9 @@ pub fn explain_lint_level_source( err.note_once(format!( "`{flag} {hyphen_case_lint_name}` implied by `{flag} {hyphen_case_flag_val}`" )); + err.help_once(format!( + "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`" + )); } } LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => { diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 0ad17e819c7..70d8f3bd54b 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceCell; +use rustc_data_structures::sync::OnceLock; use rustc_index::{IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; @@ -23,11 +23,11 @@ pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u1 #[derive(Clone, Default, Debug)] struct Cache { - predecessors: OnceCell<Predecessors>, - switch_sources: OnceCell<SwitchSources>, - is_cyclic: OnceCell<bool>, - reverse_postorder: OnceCell<Vec<BasicBlock>>, - dominators: OnceCell<Dominators<BasicBlock>>, + predecessors: OnceLock<Predecessors>, + switch_sources: OnceLock<SwitchSources>, + is_cyclic: OnceLock<bool>, + reverse_postorder: OnceLock<Vec<BasicBlock>>, + dominators: OnceLock<Dominators<BasicBlock>>, } impl<'tcx> BasicBlocks<'tcx> { diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 65d04919357..1c9ce1cb130 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -103,7 +103,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {} /// mostly opaque; the `Machine` trait extends it with some more operations that also have access to /// some global state. /// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`. -pub trait Provenance: Copy + fmt::Debug { +pub trait Provenance: Copy + fmt::Debug + 'static { /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address. /// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are /// different from what the Abstract Machine prescribes, so the interpreter must prevent any diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6484c30167c..3d45b4bdc33 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -8,6 +8,7 @@ use crate::mir::interpret::{ use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; +use crate::ty::print::with_no_trimmed_paths; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, List, Ty, TyCtxt}; @@ -1028,19 +1029,6 @@ pub enum VarDebugInfoContents<'tcx> { /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. Place(Place<'tcx>), Const(Constant<'tcx>), - /// The user variable's data is split across several fragments, - /// each described by a `VarDebugInfoFragment`. - /// See DWARF 5's "2.6.1.2 Composite Location Descriptions" - /// and LLVM's `DW_OP_LLVM_fragment` for more details on - /// the underlying debuginfo feature this relies on. - Composite { - /// Type of the original user variable. - /// This cannot contain a union or an enum. - ty: Ty<'tcx>, - /// All the parts of the original user variable, which ended - /// up in disjoint places, due to optimizations. - fragments: Vec<VarDebugInfoFragment<'tcx>>, - }, } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { @@ -1048,19 +1036,16 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> { match self { VarDebugInfoContents::Const(c) => write!(fmt, "{c}"), VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"), - VarDebugInfoContents::Composite { ty, fragments } => { - write!(fmt, "{ty:?}{{ ")?; - for f in fragments.iter() { - write!(fmt, "{f:?}, ")?; - } - write!(fmt, "}}") - } } } } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct VarDebugInfoFragment<'tcx> { + /// Type of the original user variable. + /// This cannot contain a union or an enum. + pub ty: Ty<'tcx>, + /// Where in the composite user variable this fragment is, /// represented as a "projection" into the composite variable. /// At lower levels, this corresponds to a byte/bit range. @@ -1071,29 +1056,10 @@ pub struct VarDebugInfoFragment<'tcx> { // to match on the discriminant, or by using custom type debuginfo // with non-overlapping variants for the composite variable. pub projection: Vec<PlaceElem<'tcx>>, - - /// Where the data for this fragment can be found. - /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. - pub contents: Place<'tcx>, -} - -impl Debug for VarDebugInfoFragment<'_> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - for elem in self.projection.iter() { - match elem { - ProjectionElem::Field(field, _) => { - write!(fmt, ".{:?}", field.index())?; - } - _ => bug!("unsupported fragment projection `{:?}`", elem), - } - } - - write!(fmt, " => {:?}", self.contents) - } } /// Debug information pertaining to a user variable. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct VarDebugInfo<'tcx> { pub name: Symbol, @@ -1102,6 +1068,13 @@ pub struct VarDebugInfo<'tcx> { /// (see `LocalDecl`'s `source_info` field for more details). pub source_info: SourceInfo, + /// The user variable's data is split across several fragments, + /// each described by a `VarDebugInfoFragment`. + /// See DWARF 5's "2.6.1.2 Composite Location Descriptions" + /// and LLVM's `DW_OP_LLVM_fragment` for more details on + /// the underlying debuginfo feature this relies on. + pub composite: Option<Box<VarDebugInfoFragment<'tcx>>>, + /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents<'tcx>, @@ -1111,6 +1084,20 @@ pub struct VarDebugInfo<'tcx> { pub argument_index: Option<u16>, } +impl Debug for VarDebugInfo<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + if let Some(box VarDebugInfoFragment { ty, ref projection }) = self.composite { + pre_fmt_projection(&projection[..], fmt)?; + write!(fmt, "({}: {})", self.name, ty)?; + post_fmt_projection(&projection[..], fmt)?; + } else { + write!(fmt, "{}", self.name)?; + } + + write!(fmt, " => {:?}", self.value) + } +} + /////////////////////////////////////////////////////////////////////////// // BasicBlock @@ -1575,7 +1562,7 @@ impl<V, T> ProjectionElem<V, T> { /// need neither the `V` parameter for `Index` nor the `T` for `Field`. pub type ProjectionKind = ProjectionElem<(), ()>; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct PlaceRef<'tcx> { pub local: Local, pub projection: &'tcx [PlaceElem<'tcx>], @@ -1751,69 +1738,90 @@ impl<'tcx> PlaceRef<'tcx> { } } +impl From<Local> for PlaceRef<'_> { + #[inline] + fn from(local: Local) -> Self { + PlaceRef { local, projection: &[] } + } +} + impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - for elem in self.projection.iter().rev() { - match elem { - ProjectionElem::OpaqueCast(_) - | ProjectionElem::Downcast(_, _) - | ProjectionElem::Field(_, _) => { - write!(fmt, "(").unwrap(); - } - ProjectionElem::Deref => { - write!(fmt, "(*").unwrap(); - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => {} - } - } + self.as_ref().fmt(fmt) + } +} +impl Debug for PlaceRef<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + pre_fmt_projection(self.projection, fmt)?; write!(fmt, "{:?}", self.local)?; + post_fmt_projection(self.projection, fmt) + } +} - for elem in self.projection.iter() { - match elem { - ProjectionElem::OpaqueCast(ty) => { - write!(fmt, " as {ty})")?; - } - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, " as {name})")?; - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, " as variant#{index:?})")?; - } - ProjectionElem::Deref => { - write!(fmt, ")")?; - } - ProjectionElem::Field(field, ty) => { - write!(fmt, ".{:?}: {:?})", field.index(), ty)?; - } - ProjectionElem::Index(ref index) => { - write!(fmt, "[{index:?}]")?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { - write!(fmt, "[{offset:?} of {min_length:?}]")?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { - write!(fmt, "[-{offset:?} of {min_length:?}]")?; - } - ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { - write!(fmt, "[{from:?}:]")?; - } - ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { - write!(fmt, "[:-{to:?}]")?; - } - ProjectionElem::Subslice { from, to, from_end: true } => { - write!(fmt, "[{from:?}:-{to:?}]")?; - } - ProjectionElem::Subslice { from, to, from_end: false } => { - write!(fmt, "[{from:?}..{to:?}]")?; - } +fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result { + for &elem in projection.iter().rev() { + match elem { + ProjectionElem::OpaqueCast(_) + | ProjectionElem::Downcast(_, _) + | ProjectionElem::Field(_, _) => { + write!(fmt, "(").unwrap(); + } + ProjectionElem::Deref => { + write!(fmt, "(*").unwrap(); } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => {} } + } - Ok(()) + Ok(()) +} + +fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result { + for &elem in projection.iter() { + match elem { + ProjectionElem::OpaqueCast(ty) => { + write!(fmt, " as {ty})")?; + } + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, " as {name})")?; + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, " as variant#{index:?})")?; + } + ProjectionElem::Deref => { + write!(fmt, ")")?; + } + ProjectionElem::Field(field, ty) => { + with_no_trimmed_paths!(write!(fmt, ".{:?}: {})", field.index(), ty)?); + } + ProjectionElem::Index(ref index) => { + write!(fmt, "[{index:?}]")?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { + write!(fmt, "[{offset:?} of {min_length:?}]")?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { + write!(fmt, "[-{offset:?} of {min_length:?}]")?; + } + ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { + write!(fmt, "[{from:?}:]")?; + } + ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { + write!(fmt, "[:-{to:?}]")?; + } + ProjectionElem::Subslice { from, to, from_end: true } => { + write!(fmt, "[{from:?}:-{to:?}]")?; + } + ProjectionElem::Subslice { from, to, from_end: false } => { + write!(fmt, "[{from:?}..{to:?}]")?; + } + } } + + Ok(()) } /////////////////////////////////////////////////////////////////////////// @@ -2070,7 +2078,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { } Len(ref a) => write!(fmt, "Len({a:?})"), Cast(ref kind, ref place, ref ty) => { - write!(fmt, "{place:?} as {ty:?} ({kind:?})") + with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})")) } BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"), CheckedBinaryOp(ref op, box (ref a, ref b)) => { @@ -2078,11 +2086,14 @@ impl<'tcx> Debug for Rvalue<'tcx> { } UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"), Discriminant(ref place) => write!(fmt, "discriminant({place:?})"), - NullaryOp(ref op, ref t) => match op { - NullOp::SizeOf => write!(fmt, "SizeOf({t:?})"), - NullOp::AlignOf => write!(fmt, "AlignOf({t:?})"), - NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t:?}, {fields:?})"), - }, + NullaryOp(ref op, ref t) => { + let t = with_no_trimmed_paths!(format!("{}", t)); + match op { + NullOp::SizeOf => write!(fmt, "SizeOf({t})"), + NullOp::AlignOf => write!(fmt, "AlignOf({t})"), + NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"), + } + } ThreadLocalRef(did) => ty::tls::with(|tcx| { let muta = tcx.static_mutability(did).unwrap().prefix_str(); write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) @@ -2218,7 +2229,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { } ShallowInitBox(ref place, ref ty) => { - write!(fmt, "ShallowInitBox({place:?}, {ty:?})") + with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})")) } } } @@ -2317,7 +2328,7 @@ impl<'tcx> ConstantKind<'tcx> { #[inline] pub fn try_to_scalar_int(self) -> Option<ScalarInt> { - Some(self.try_to_scalar()?.assert_int()) + self.try_to_scalar()?.try_to_int().ok() } #[inline] @@ -3056,6 +3067,6 @@ mod size_asserts { static_assert_size!(StatementKind<'_>, 16); static_assert_size!(Terminator<'_>, 104); static_assert_size!(TerminatorKind<'_>, 88); - static_assert_size!(VarDebugInfo<'_>, 80); + static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 773056e8a17..6b23a7f5bff 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -554,10 +554,7 @@ fn write_scope_tree( continue; } - let indented_debug_info = format!( - "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.value, - ); + let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info); if tcx.sess.opts.unstable_opts.mir_include_spans { writeln!( @@ -586,8 +583,10 @@ fn write_scope_tree( let mut_str = local_decl.mutability.prefix_str(); - let mut indented_decl = - format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty); + let mut indented_decl = ty::print::with_no_trimmed_paths!(format!( + "{0:1$}let {2}{3:?}: {4}", + INDENT, indent, mut_str, local, local_decl.ty + )); if let Some(user_ty) = &local_decl.user_ty { for user_ty in user_ty.projections() { write!(indented_decl, " as {user_ty:?}").unwrap(); @@ -1061,11 +1060,11 @@ fn write_user_type_annotations( for (index, annotation) in body.user_type_annotations.iter_enumerated() { writeln!( w, - "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}", + "| {:?}: user_ty: {}, span: {}, inferred_ty: {}", index.index(), annotation.user_ty, tcx.sess.source_map().span_to_embeddable_string(annotation.span), - annotation.inferred_ty, + with_no_trimmed_paths!(format!("{}", annotation.inferred_ty)), )?; } if !body.user_type_annotations.is_empty() { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 87b04aabe6a..61244b94289 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -838,12 +838,20 @@ macro_rules! make_mir_visitor { let VarDebugInfo { name: _, source_info, + composite, value, argument_index: _, } = var_debug_info; self.visit_source_info(source_info); let location = Location::START; + if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite { + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + for elem in projection { + let ProjectionElem::Field(_, ty) = elem else { bug!() }; + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } + } match value { VarDebugInfoContents::Const(c) => self.visit_constant(c, location), VarDebugInfoContents::Place(place) => @@ -852,17 +860,6 @@ macro_rules! make_mir_visitor { PlaceContext::NonUse(NonUseContext::VarDebugInfo), location ), - VarDebugInfoContents::Composite { ty, fragments } => { - // FIXME(eddyb) use a better `TyContext` here. - self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); - for VarDebugInfoFragment { projection: _, contents } in fragments { - self.visit_place( - contents, - PlaceContext::NonUse(NonUseContext::VarDebugInfo), - location, - ); - } - } } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 995b2140f61..280f5d0a84c 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -22,7 +22,7 @@ use rustc_span::hygiene::{ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; -use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span}; +use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span}; use rustc_span::{CachingSourceMapView, Symbol}; use std::collections::hash_map::Entry; use std::io; @@ -688,11 +688,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { let file_lo_index = SourceFileIndex::decode(decoder); let line_lo = usize::decode(decoder); - let col_lo = BytePos::decode(decoder); + let col_lo = RelativeBytePos::decode(decoder); let len = BytePos::decode(decoder); let file_lo = decoder.file_index_to_file(file_lo_index); - let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo); + let lo = file_lo.lines()[line_lo - 1] + col_lo; + let lo = file_lo.absolute_position(lo); let hi = lo + len; Span::new(lo, hi, ctxt, parent) @@ -895,7 +896,7 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span { } if let Some(parent) = span_data.parent { - let enclosing = s.tcx.source_span(parent).data_untracked(); + let enclosing = s.tcx.source_span_untracked(parent).data_untracked(); if enclosing.contains(span_data) { TAG_RELATIVE_SPAN.encode(s); (span_data.lo - enclosing.lo).to_u32().encode(s); diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index b16163edf14..9d99344d5bd 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -227,6 +227,11 @@ impl ScalarInt { } #[inline] + pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> { + Self::try_from_uint(i, tcx.data_layout.pointer_size) + } + + #[inline] pub fn assert_bits(self, target_size: Size) -> u128 { self.to_bits(target_size).unwrap_or_else(|size| { bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes()) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e2f9e299566..eeb87d5561d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -39,7 +39,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{self, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal}; +use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{ DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan, @@ -964,8 +964,8 @@ impl<'tcx> TyCtxt<'tcx> { i += 1; } - // Leak a read lock once we finish iterating on definitions, to prevent adding new ones. - definitions.leak(); + // Freeze definitions once we finish iterating on them, to prevent adding new ones. + definitions.freeze(); }) } @@ -974,10 +974,9 @@ impl<'tcx> TyCtxt<'tcx> { // definitions change. self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); - // Leak a read lock once we start iterating on definitions, to prevent adding new ones + // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. - let definitions = self.untracked.definitions.leak(); - definitions.def_path_table() + self.untracked.definitions.freeze().def_path_table() } pub fn def_path_hash_to_def_index_map( @@ -986,17 +985,16 @@ impl<'tcx> TyCtxt<'tcx> { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new ones + // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. - let definitions = self.untracked.definitions.leak(); - definitions.def_path_hash_to_def_index_map() + self.untracked.definitions.freeze().def_path_hash_to_def_index_map() } /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries #[inline] - pub fn cstore_untracked(self) -> MappedReadGuard<'tcx, CrateStoreDyn> { - ReadGuard::map(self.untracked.cstore.read(), |c| &**c) + pub fn cstore_untracked(self) -> FreezeReadGuard<'tcx, CrateStoreDyn> { + FreezeReadGuard::map(self.untracked.cstore.read(), |c| &**c) } /// Give out access to the untracked data without any sanity checks. @@ -1006,7 +1004,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries #[inline] - pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> { + pub fn definitions_untracked(self) -> FreezeReadGuard<'tcx, Definitions> { self.untracked.definitions.read() } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 97dab5cb47e..153b24acba1 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -440,7 +440,7 @@ impl<'tcx> GenericArgs<'tcx> { target_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { let defs = tcx.generics_of(source_ancestor); - tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.params.len()))) + tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.count()))) } pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> { @@ -450,6 +450,11 @@ impl<'tcx> GenericArgs<'tcx> { pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> { self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host)) } + + pub fn print_as_list(&self) -> String { + let v = self.iter().map(|arg| arg.to_string()).collect::<Vec<_>>(); + format!("[{}]", v.join(", ")) + } } impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ac0c88468fa..f24ac79323f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -760,9 +760,12 @@ pub trait PrettyPrinter<'tcx>: // only affect certain debug messages (e.g. messages printed // from `rustc_middle::ty` during the computation of `tcx.predicates_of`), // and should have no effect on any compiler output. + // [Unless `-Zverbose` is used, e.g. in the output of + // `tests/ui/nll/ty-outlives/impl-trait-captures.rs`, for + // example.] if self.should_print_verbose() { // FIXME(eddyb) print this with `print_def_path`. - p!(write("Opaque({:?}, {:?})", def_id, args)); + p!(write("Opaque({:?}, {})", def_id, args.print_as_list())); return Ok(self); } @@ -894,7 +897,7 @@ pub trait PrettyPrinter<'tcx>: p!(print_def_path(did, args)); if !args.as_closure().is_valid() { p!(" closure_args=(unavailable)"); - p!(write(" args={:?}", args)); + p!(write(" args={}", args.print_as_list())); } else { p!(" closure_kind_ty=", print(args.as_closure().kind_ty())); p!( @@ -1123,6 +1126,17 @@ pub trait PrettyPrinter<'tcx>: } } + if self.tcx().features().return_type_notation + && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id) + && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() + && alias_ty.def_id == def_id + { + let num_args = self.tcx().generics_of(fn_def_id).count(); + write!(self, " {{ ")?; + self = self.print_def_path(fn_def_id, &args[..num_args])?; + write!(self, "() }}")?; + } + Ok(self) } @@ -1239,21 +1253,18 @@ pub trait PrettyPrinter<'tcx>: .generics_of(principal.def_id) .own_args_no_defaults(cx.tcx(), principal.args); - let mut projections = predicates.projection_bounds(); - - let mut args = args.iter().cloned(); - let arg0 = args.next(); - let projection0 = projections.next(); - if arg0.is_some() || projection0.is_some() { - let args = arg0.into_iter().chain(args); - let projections = projection0.into_iter().chain(projections); + let mut projections: Vec<_> = predicates.projection_bounds().collect(); + projections.sort_by_cached_key(|proj| { + cx.tcx().item_name(proj.item_def_id()).to_string() + }); + if !args.is_empty() || !projections.is_empty() { p!(generic_delimiters(|mut cx| { - cx = cx.comma_sep(args)?; - if arg0.is_some() && projection0.is_some() { + cx = cx.comma_sep(args.iter().copied())?; + if !args.is_empty() && !projections.is_empty() { write!(cx, ", ")?; } - cx.comma_sep(projections) + cx.comma_sep(projections.iter().copied()) })); } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f979ddd00fa..a35ca8685c4 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -154,7 +154,7 @@ impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> { } impl<'tcx> fmt::Debug for Ty<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - with_no_trimmed_paths!(fmt::Display::fmt(self, f)) + with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f)) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0291cdd6c57..fbbdfe5f14f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2857,7 +2857,7 @@ impl<'tcx> Ty<'tcx> { | ty::Uint(..) | ty::Float(..) => true, - // The voldemort ZSTs are fine. + // ZST which can't be named are fine. ty::FnDef(..) => true, ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(), diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 327cd0a5d7b..7ecc7e6014d 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -722,3 +722,14 @@ pub enum UserType<'tcx> { /// given substitutions applied. TypeOf(DefId, UserArgs<'tcx>), } + +impl<'tcx> std::fmt::Display for UserType<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ty(arg0) => { + ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0)) + } + Self::TypeOf(arg0, arg1) => write!(f, "TypeOf({:?}, {:?})", arg0, arg1), + } + } +} diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index 60c4a041696..e2ab2cb90c7 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -1,5 +1,6 @@ use rustc_index::IndexSlice; -use rustc_middle::{mir::*, thir::*, ty::Ty}; +use rustc_middle::ty::{self, Ty}; +use rustc_middle::{mir::*, thir::*}; use rustc_span::Span; use super::{PResult, ParseCtxt, ParseError}; @@ -159,6 +160,14 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ); self.parse_local_decls(local_decls.iter().copied())?; + let (debuginfo, rest) = parse_by_kind!(self, rest, _, "body with debuginfo", + ExprKind::Block { block } => { + let block = &self.thir[*block]; + (&block.stmts, block.expr.unwrap()) + }, + ); + self.parse_debuginfo(debuginfo.iter().copied())?; + let block_defs = parse_by_kind!(self, rest, _, "body with block defs", ExprKind::Block { block } => &self.thir[*block].stmts, ); @@ -195,6 +204,53 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(()) } + fn parse_debuginfo(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> { + for stmt in stmts { + let stmt = &self.thir[stmt]; + let expr = match stmt.kind { + StmtKind::Let { span, .. } => { + return Err(ParseError { + span, + item_description: format!("{:?}", stmt), + expected: "debuginfo".to_string(), + }); + } + StmtKind::Expr { expr, .. } => expr, + }; + let span = self.thir[expr].span; + let (name, operand) = parse_by_kind!(self, expr, _, "debuginfo", + @call("mir_debuginfo", args) => { + (args[0], args[1]) + }, + ); + let name = parse_by_kind!(self, name, _, "debuginfo", + ExprKind::Literal { lit, neg: false } => lit, + ); + let Some(name) = name.node.str() else { + return Err(ParseError { + span, + item_description: format!("{:?}", name), + expected: "string".to_string(), + }); + }; + let operand = self.parse_operand(operand)?; + let value = match operand { + Operand::Constant(c) => VarDebugInfoContents::Const(*c), + Operand::Copy(p) | Operand::Move(p) => VarDebugInfoContents::Place(p), + }; + let dbginfo = VarDebugInfo { + name, + source_info: SourceInfo { span, scope: self.source_scope }, + composite: None, + argument_index: None, + value, + }; + self.body.var_debug_info.push(dbginfo); + } + + Ok(()) + } + fn parse_let_statement(&mut self, stmt_id: StmtId) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { let pattern = match &self.thir[stmt_id].kind { StmtKind::Let { pattern, .. } => pattern, diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 26662f5de45..da5f2b1bcc9 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -204,7 +204,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ) } - fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> { + pub fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> { parse_by_kind!(self, expr_id, expr, "operand", @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move), @call("mir_static", args) => self.parse_static(args[0]), diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5ec216cea61..7e81c8b50c2 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2287,6 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(for_arm_body.into()), + composite: None, argument_index: None, }); let locals = if has_guard.0 { @@ -2306,6 +2307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(ref_for_guard.into()), + composite: None, argument_index: None, }); LocalsForNode::ForGuard { ref_for_guard, for_arm_body } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e614046e83e..4e10916ad61 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -823,6 +823,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), + composite: None, argument_index: None, }); @@ -852,6 +853,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info, value: VarDebugInfoContents::Place(arg_local.into()), + composite: None, argument_index: Some(argument_index as u16 + 1), }); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index f46cf0dc0ff..95dced644e1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -720,32 +720,31 @@ fn non_exhaustive_match<'p, 'tcx>( }; }; - let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(), - ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local()); - adt_defined_here(cx, &mut err, scrut_ty, &witnesses); - err.note(format!( - "the matched value is of type `{}`{}", - scrut_ty, - if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" } - )); + err.note(format!("the matched value is of type `{}`", scrut_ty)); if !is_empty_match && witnesses.len() == 1 { let mut non_exhaustive_tys = FxHashSet::default(); collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys); for ty in non_exhaustive_tys { - if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize { + if ty.is_ptr_sized_integral() { err.note(format!( "`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \ - exhaustively", - )); + exhaustively", + )); if cx.tcx.sess.is_nightly_build() { err.help(format!( - "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \ - enable precise `{ty}` matching", - )); + "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \ + enable precise `{ty}` matching", + )); } + } else if ty == cx.tcx.types.str_ { + err.note(format!( + "`&str` cannot be matched exhaustively, so a wildcard `_` is necessary", + )); + } else if cx.is_foreign_non_exhaustive_enum(ty) { + err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively")); } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c08fe54c39c..7736183027f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -555,8 +555,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { subpattern: pattern, ascription: Ascription { annotation, - /// Note that use `Contravariant` here. See the - /// `variance` field documentation for details. + // Note that use `Contravariant` here. See the + // `variance` field documentation for details. variance: ty::Variance::Contravariant, }, }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 08cfe98bb68..21031e8ba9d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -618,10 +618,15 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { let new_witnesses = if let Constructor::Missing { .. } = ctor { // We got the special `Missing` constructor, so each of the missing constructors // gives a new pattern that is not caught by the match. We list those patterns. - let new_patterns = if pcx.is_non_exhaustive { - // Here we don't want the user to try to list all variants, we want them to add - // a wildcard, so we only suggest that. - vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)] + if pcx.is_non_exhaustive { + witnesses + .into_iter() + // Here we don't want the user to try to list all variants, we want them to add + // a wildcard, so we only suggest that. + .map(|witness| { + witness.apply_constructor(pcx, &Constructor::NonExhaustive) + }) + .collect() } else { let mut split_wildcard = SplitWildcard::new(pcx); split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); @@ -633,7 +638,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { // constructor, that matches everything that can be built with // it. For example, if `ctor` is a `Constructor::Variant` for // `Option::Some`, we get the pattern `Some(_)`. - let mut new: Vec<DeconstructedPat<'_, '_>> = split_wildcard + let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard .iter_missing(pcx) .filter_map(|missing_ctor| { // Check if this variant is marked `doc(hidden)` @@ -648,27 +653,25 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { .collect(); if hide_variant_show_wild { - new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span)); + new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span)); } - new - }; - - witnesses - .into_iter() - .flat_map(|witness| { - new_patterns.iter().map(move |pat| { - Witness( - witness - .0 - .iter() - .chain(once(pat)) - .map(DeconstructedPat::clone_and_forget_reachability) - .collect(), - ) + witnesses + .into_iter() + .flat_map(|witness| { + new_patterns.iter().map(move |pat| { + Witness( + witness + .0 + .iter() + .chain(once(pat)) + .map(DeconstructedPat::clone_and_forget_reachability) + .collect(), + ) + }) }) - }) - .collect() + .collect() + } } else { witnesses .into_iter() diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 1421d9b45cd..bdddaaebca4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -538,7 +538,7 @@ where fn visit_block_start( &mut self, - _results: &Results<'tcx, A>, + _results: &mut Results<'tcx, A>, state: &Self::FlowState, _block_data: &mir::BasicBlockData<'tcx>, _block: BasicBlock, @@ -550,7 +550,7 @@ where fn visit_block_end( &mut self, - _results: &Results<'tcx, A>, + _results: &mut Results<'tcx, A>, state: &Self::FlowState, _block_data: &mir::BasicBlockData<'tcx>, _block: BasicBlock, @@ -562,7 +562,7 @@ where fn visit_statement_before_primary_effect( &mut self, - results: &Results<'tcx, A>, + results: &mut Results<'tcx, A>, state: &Self::FlowState, _statement: &mir::Statement<'tcx>, _location: Location, @@ -575,7 +575,7 @@ where fn visit_statement_after_primary_effect( &mut self, - results: &Results<'tcx, A>, + results: &mut Results<'tcx, A>, state: &Self::FlowState, _statement: &mir::Statement<'tcx>, _location: Location, @@ -586,7 +586,7 @@ where fn visit_terminator_before_primary_effect( &mut self, - results: &Results<'tcx, A>, + results: &mut Results<'tcx, A>, state: &Self::FlowState, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -599,7 +599,7 @@ where fn visit_terminator_after_primary_effect( &mut self, - results: &Results<'tcx, A>, + results: &mut Results<'tcx, A>, state: &Self::FlowState, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 76a72982781..3cfa7cc1c02 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -35,7 +35,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_block_start( &mut self, - _results: &R, + _results: &mut R, _state: &Self::FlowState, _block_data: &'mir mir::BasicBlockData<'tcx>, _block: BasicBlock, @@ -46,7 +46,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// its `statement_effect`. fn visit_statement_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, _state: &Self::FlowState, _statement: &'mir mir::Statement<'tcx>, _location: Location, @@ -57,7 +57,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// statement applied to `state`. fn visit_statement_after_primary_effect( &mut self, - _results: &R, + _results: &mut R, _state: &Self::FlowState, _statement: &'mir mir::Statement<'tcx>, _location: Location, @@ -68,7 +68,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// its `terminator_effect`. fn visit_terminator_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, _state: &Self::FlowState, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, @@ -81,7 +81,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// The `call_return_effect` (if one exists) will *not* be applied to `state`. fn visit_terminator_after_primary_effect( &mut self, - _results: &R, + _results: &mut R, _state: &Self::FlowState, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, @@ -90,7 +90,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_block_end( &mut self, - _results: &R, + _results: &mut R, _state: &Self::FlowState, _block_data: &'mir mir::BasicBlockData<'tcx>, _block: BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 6872ef5e985..299bf692307 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -581,6 +581,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> { } } + /// Retrieve the value stored for a place, or ⊤ if it is not tracked. + pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V { + match map.find_len(place) { + Some(place) => self.get_idx(place, map), + None => V::TOP, + } + } + /// Retrieve the value stored for a place index, or ⊤ if it is not tracked. pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V { match &self.0 { @@ -626,45 +634,36 @@ pub struct Map { } impl Map { - fn new() -> Self { - Self { + /// Returns a map that only tracks places whose type has scalar layout. + /// + /// This is currently the only way to create a [`Map`]. The way in which the tracked places are + /// chosen is an implementation detail and may not be relied upon (other than that their type + /// are scalars). + pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) -> Self { + let mut map = Self { locals: IndexVec::new(), projections: FxHashMap::default(), places: IndexVec::new(), value_count: 0, inner_values: IndexVec::new(), inner_values_buffer: Vec::new(), - } - } - - /// Returns a map that only tracks places whose type passes the filter. - /// - /// This is currently the only way to create a [`Map`]. The way in which the tracked places are - /// chosen is an implementation detail and may not be relied upon (other than that their type - /// passes the filter). - pub fn from_filter<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - filter: impl Fn(Ty<'tcx>) -> bool, - value_limit: Option<usize>, - ) -> Self { - let mut map = Self::new(); + }; let exclude = excluded_locals(body); - map.register_with_filter(tcx, body, filter, exclude, value_limit); + map.register(tcx, body, exclude, value_limit); debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len()); map } - /// Register all non-excluded places that pass the filter. - fn register_with_filter<'tcx>( + /// Register all non-excluded places that have scalar layout. + fn register<'tcx>( &mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - filter: impl Fn(Ty<'tcx>) -> bool, exclude: BitSet<Local>, value_limit: Option<usize>, ) { let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len())); + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); // Start by constructing the places for each bare local. self.locals = IndexVec::from_elem(None, &body.local_decls); @@ -679,7 +678,7 @@ impl Map { self.locals[local] = Some(place); // And push the eventual children places to the worklist. - self.register_children(tcx, place, decl.ty, &filter, &mut worklist); + self.register_children(tcx, param_env, place, decl.ty, &mut worklist); } // `place.elem1.elem2` with type `ty`. @@ -702,7 +701,7 @@ impl Map { } // And push the eventual children places to the worklist. - self.register_children(tcx, place, ty, &filter, &mut worklist); + self.register_children(tcx, param_env, place, ty, &mut worklist); } // Pre-compute the tree of ValueIndex nested in each PlaceIndex. @@ -732,42 +731,52 @@ impl Map { fn register_children<'tcx>( &mut self, tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, place: PlaceIndex, ty: Ty<'tcx>, - filter: &impl Fn(Ty<'tcx>) -> bool, worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>, ) { // Allocate a value slot if it doesn't have one, and the user requested one. - if self.places[place].value_index.is_none() && filter(ty) { + assert!(self.places[place].value_index.is_none()); + if tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.abi.is_scalar()) { self.places[place].value_index = Some(self.value_count.into()); self.value_count += 1; } // For enums, directly create the `Discriminant`, as that's their main use. if ty.is_enum() { - let discr_ty = ty.discriminant_ty(tcx); - if filter(discr_ty) { - let discr = *self - .projections - .entry((place, TrackElem::Discriminant)) - .or_insert_with(|| { - // Prepend new child to the linked list. - let next = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant))); - self.places[next].next_sibling = self.places[place].first_child; - self.places[place].first_child = Some(next); - next - }); - - // Allocate a value slot if it doesn't have one. - if self.places[discr].value_index.is_none() { - self.places[discr].value_index = Some(self.value_count.into()); - self.value_count += 1; - } - } + // Prepend new child to the linked list. + let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant))); + self.places[discr].next_sibling = self.places[place].first_child; + self.places[place].first_child = Some(discr); + let old = self.projections.insert((place, TrackElem::Discriminant), discr); + assert!(old.is_none()); + + // Allocate a value slot since it doesn't have one. + assert!(self.places[discr].value_index.is_none()); + self.places[discr].value_index = Some(self.value_count.into()); + self.value_count += 1; + } + + if let Some(ref_ty) = ty.builtin_deref(true) && let ty::Slice(..) = ref_ty.ty.kind() { + assert!(self.places[place].value_index.is_none(), "slices are not scalars"); + + // Prepend new child to the linked list. + let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen))); + self.places[len].next_sibling = self.places[place].first_child; + self.places[place].first_child = Some(len); + + let old = self.projections.insert((place, TrackElem::DerefLen), len); + assert!(old.is_none()); + + // Allocate a value slot since it doesn't have one. + assert!( self.places[len].value_index.is_none() ); + self.places[len].value_index = Some(self.value_count.into()); + self.value_count += 1; } // Recurse with all fields of this place. - iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| { + iter_fields(ty, tcx, param_env, |variant, field, ty| { worklist.push_back(( place, variant.map(TrackElem::Variant), @@ -834,6 +843,11 @@ impl Map { self.find_extra(place, [TrackElem::Discriminant]) } + /// Locates the given place and applies `DerefLen`, if it exists in the tree. + pub fn find_len(&self, place: PlaceRef<'_>) -> Option<PlaceIndex> { + self.find_extra(place, [TrackElem::DerefLen]) + } + /// Iterate over all direct children. pub fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> + '_ { Children::new(self, parent) @@ -985,6 +999,8 @@ pub enum TrackElem { Field(FieldIdx), Variant(VariantIdx), Discriminant, + // Length of a slice. + DerefLen, } impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem { @@ -1124,6 +1140,9 @@ fn debug_with_context_rec<V: Debug + Eq>( format!("{}.{}", place_str, field.index()) } } + TrackElem::DerefLen => { + format!("Len(*{})", place_str) + } }; debug_with_context_rec(child, &child_place_str, new, old, map, f)?; } diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 2598eb2ed09..5a99afc45b0 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -42,8 +42,6 @@ mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in } .not_inherited = items do not inherit unsafety from separate enclosing items -mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item - mir_transform_target_feature_call_label = call to function with `#[target_feature]` mir_transform_target_feature_call_note = can only be called if the required target features are available diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 0fce9cb19a8..d5af321d726 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -483,7 +483,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu // `mir_built` force this. let body = &tcx.mir_built(def).borrow(); - if body.is_custom_mir() { + if body.is_custom_mir() || body.tainted_by_errors.is_some() { return tcx.arena.alloc(UnsafetyCheckResult { violations: Vec::new(), used_unsafe_blocks: Default::default(), diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 0aaa3f75c82..5f135e96980 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -22,8 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::MirPass; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, FnArg, Frame, ImmTy, - Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, - StackPopCleanup, + Immediate, InterpCx, InterpResult, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, StackPopCleanup, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -225,11 +224,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn access_local_mut<'a>( + fn before_access_local_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: Local, - ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> { + ) -> InterpResult<'tcx> { assert_eq!(frame, 0); match ecx.machine.can_const_prop[local] { ConstPropMode::NoPropagation => { @@ -242,7 +241,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } ConstPropMode::FullConstProp => {} } - ecx.machine.stack[frame].locals[local].access_mut() + Ok(()) } fn before_access_global( @@ -382,8 +381,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // mark those as live... We rely on `local_to_place`/`local_to_op` in the interpreter // stopping us before those unsized immediates can cause issues deeper in the // interpreter. - ecx.frame_mut().locals[local].value = - LocalValue::Live(interpret::Operand::Immediate(Immediate::Uninit)); + ecx.frame_mut().locals[local].make_live_uninit(); } ConstPropagator { ecx, tcx, param_env, local_decls: &dummy_body.local_decls } @@ -392,7 +390,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> { let op = match self.ecx.eval_place_to_op(place, None) { Ok(op) => { - if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) { + if op + .as_mplace_or_imm() + .right() + .is_some_and(|imm| matches!(*imm, Immediate::Uninit)) + { // Make sure nobody accidentally uses this value. return None; } @@ -415,8 +417,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Remove `local` from the pool of `Locals`. Allows writing to them, /// but not reading from them anymore. fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { - ecx.frame_mut().locals[local].value = - LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + ecx.frame_mut().locals[local].make_live_uninit(); ecx.machine.written_only_inside_own_block_locals.remove(&local); } @@ -743,7 +744,8 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { ) -> Option<PlaceElem<'tcx>> { if let PlaceElem::Index(local) = elem && let Some(value) = self.get_const(local.into()) - && let interpret::Operand::Immediate(Immediate::Scalar(scalar)) = *value + && let Some(imm) = value.as_mplace_or_imm().right() + && let Immediate::Scalar(scalar) = *imm && let Ok(offset) = scalar.to_target_usize(&self.tcx) && let Some(min_length) = offset.checked_add(1) { diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index dec79ddf58c..b52827a1e88 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -7,7 +7,7 @@ use either::Left; use rustc_const_eval::interpret::Immediate; use rustc_const_eval::interpret::{ - self, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup, + InterpCx, InterpResult, MemoryKind, OpTy, Scalar, StackPopCleanup, }; use rustc_const_eval::ReportErrorExt; use rustc_hir::def::DefKind; @@ -39,6 +39,10 @@ pub struct ConstProp; impl<'tcx> MirLint<'tcx> for ConstProp { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + if body.tainted_by_errors.is_some() { + return; + } + // will be evaluated by miri and produce its errors there if body.source.promoted.is_some() { return; @@ -212,8 +216,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // mark those as live... We rely on `local_to_place`/`local_to_op` in the interpreter // stopping us before those unsized immediates can cause issues deeper in the // interpreter. - ecx.frame_mut().locals[local].value = - LocalValue::Live(interpret::Operand::Immediate(Immediate::Uninit)); + ecx.frame_mut().locals[local].make_live_uninit(); } ConstPropagator { @@ -236,7 +239,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> { let op = match self.ecx.eval_place_to_op(place, None) { Ok(op) => { - if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) { + if op + .as_mplace_or_imm() + .right() + .is_some_and(|imm| matches!(*imm, Immediate::Uninit)) + { // Make sure nobody accidentally uses this value. return None; } @@ -259,8 +266,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Remove `local` from the pool of `Locals`. Allows writing to them, /// but not reading from them anymore. fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { - ecx.frame_mut().locals[local].value = - LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + ecx.frame_mut().locals[local].make_live_uninit(); ecx.machine.written_only_inside_own_block_locals.remove(&local); } @@ -656,12 +662,12 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { } StatementKind::StorageLive(local) => { let frame = self.ecx.frame_mut(); - frame.locals[local].value = - LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)); + frame.locals[local].make_live_uninit(); } StatementKind::StorageDead(local) => { let frame = self.ecx.frame_mut(); - frame.locals[local].value = LocalValue::Dead; + // We don't actually track liveness, so the local remains live. But forget its value. + frame.locals[local].make_live_uninit(); } _ => {} } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 8c9eae508b4..d0b28eb2f5d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -28,7 +28,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::source_map::SourceMap; -use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; +use rustc_span::{ExpnKind, SourceFile, Span, Symbol}; /// A simple error message wrapper for `coverage::Error`s. #[derive(Debug)] @@ -314,8 +314,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { }; graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); - let code_region = - make_code_region(source_map, file_name, &self.source_file, span, body_span); + let code_region = make_code_region(source_map, file_name, span, body_span); inject_statement( self.mir_body, @@ -510,40 +509,36 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'_>, expression: Cove fn make_code_region( source_map: &SourceMap, file_name: Symbol, - source_file: &Lrc<SourceFile>, span: Span, body_span: Span, ) -> CodeRegion { debug!( - "Called make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", + "Called make_code_region(file_name={}, span={}, body_span={})", file_name, - source_file, source_map.span_to_diagnostic_string(span), source_map.span_to_diagnostic_string(body_span) ); - let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo()); - let (end_line, end_col) = if span.hi() == span.lo() { - let (end_line, mut end_col) = (start_line, start_col); + let (file, mut start_line, mut start_col, mut end_line, mut end_col) = + source_map.span_to_location_info(span); + if span.hi() == span.lo() { // Extend an empty span by one character so the region will be counted. - let CharPos(char_pos) = start_col; if span.hi() == body_span.hi() { - start_col = CharPos(char_pos.saturating_sub(1)); + start_col = start_col.saturating_sub(1); } else { - end_col = CharPos(char_pos + 1); + end_col = start_col + 1; } - (end_line, end_col) - } else { - source_file.lookup_file_pos(span.hi()) }; - let start_line = source_map.doctest_offset_line(&source_file.name, start_line); - let end_line = source_map.doctest_offset_line(&source_file.name, end_line); + if let Some(file) = file { + start_line = source_map.doctest_offset_line(&file.name, start_line); + end_line = source_map.doctest_offset_line(&file.name, end_line); + } CodeRegion { file_name, start_line: start_line as u32, - start_col: start_col.to_u32() + 1, + start_col: start_col as u32, end_line: end_line as u32, - end_col: end_col.to_u32() + 1, + end_col: end_col as u32, } } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index aa205655f9d..56365c5d474 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,5 +1,6 @@ use super::*; +use rustc_data_structures::captures::Captures; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; use rustc_middle::query::Providers; @@ -12,15 +13,10 @@ pub(crate) fn provide(providers: &mut Providers) { providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); } -/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in -/// other words, the number of counter value references injected into the MIR (plus 1 for the -/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected -/// counters have a counter ID from `1..num_counters-1`. -/// -/// `num_expressions` is the number of counter expressions added to the MIR body. -/// -/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend -/// code generate, to lookup counters and expressions by simple u32 indexes. +/// Coverage codegen needs to know the total number of counter IDs and expression IDs that have +/// been used by a function's coverage mappings. These totals are used to create vectors to hold +/// the relevant counter and expression data, and the maximum counter ID (+ 1) is also needed by +/// the `llvm.instrprof.increment` intrinsic. /// /// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code /// including injected counters. (It is OK if some counters are optimized out, but those counters @@ -28,71 +24,51 @@ pub(crate) fn provide(providers: &mut Providers) { /// calls may not work; but computing the number of counters or expressions by adding `1` to the /// highest ID (for a given instrumented function) is valid. /// -/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum -/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a -/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression -/// IDs referenced by expression operands, if not already seen. -/// -/// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage` -/// statement for the `Counter` or `Expression` with the referenced ID. but since current or future -/// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to -/// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs. +/// It's possible for a coverage expression to remain in MIR while one or both of its operands +/// have been optimized away. To avoid problems in codegen, we include those operands' IDs when +/// determining the maximum counter/expression ID, even if the underlying counter/expression is +/// no longer present. struct CoverageVisitor { - info: CoverageInfo, - add_missing_operands: bool, + max_counter_id: CounterId, + max_expression_id: ExpressionId, } impl CoverageVisitor { - /// Updates `num_counters` to the maximum encountered counter ID plus 1. + /// Updates `max_counter_id` to the maximum encountered counter ID. #[inline(always)] - fn update_num_counters(&mut self, counter_id: CounterId) { - let counter_id = counter_id.as_u32(); - self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); + fn update_max_counter_id(&mut self, counter_id: CounterId) { + self.max_counter_id = self.max_counter_id.max(counter_id); } - /// Updates `num_expressions` to the maximum encountered expression ID plus 1. + /// Updates `max_expression_id` to the maximum encountered expression ID. #[inline(always)] - fn update_num_expressions(&mut self, expression_id: ExpressionId) { - let expression_id = expression_id.as_u32(); - self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_id + 1); + fn update_max_expression_id(&mut self, expression_id: ExpressionId) { + self.max_expression_id = self.max_expression_id.max(expression_id); } fn update_from_expression_operand(&mut self, operand: Operand) { match operand { - Operand::Counter(id) => self.update_num_counters(id), - Operand::Expression(id) => self.update_num_expressions(id), + Operand::Counter(id) => self.update_max_counter_id(id), + Operand::Expression(id) => self.update_max_expression_id(id), Operand::Zero => {} } } fn visit_body(&mut self, body: &Body<'_>) { - for bb_data in body.basic_blocks.iter() { - for statement in bb_data.statements.iter() { - if let StatementKind::Coverage(box ref coverage) = statement.kind { - if is_inlined(body, statement) { - continue; - } - self.visit_coverage(coverage); - } - } + for coverage in all_coverage_in_mir_body(body) { + self.visit_coverage(coverage); } } fn visit_coverage(&mut self, coverage: &Coverage) { - if self.add_missing_operands { - match coverage.kind { - CoverageKind::Expression { lhs, rhs, .. } => { - self.update_from_expression_operand(lhs); - self.update_from_expression_operand(rhs); - } - _ => {} - } - } else { - match coverage.kind { - CoverageKind::Counter { id, .. } => self.update_num_counters(id), - CoverageKind::Expression { id, .. } => self.update_num_expressions(id), - _ => {} + match coverage.kind { + CoverageKind::Counter { id, .. } => self.update_max_counter_id(id), + CoverageKind::Expression { id, lhs, rhs, .. } => { + self.update_max_expression_id(id); + self.update_from_expression_operand(lhs); + self.update_from_expression_operand(rhs); } + CoverageKind::Unreachable => {} } } } @@ -101,37 +77,40 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> let mir_body = tcx.instance_mir(instance_def); let mut coverage_visitor = CoverageVisitor { - info: CoverageInfo { num_counters: 0, num_expressions: 0 }, - add_missing_operands: false, + max_counter_id: CounterId::START, + max_expression_id: ExpressionId::START, }; coverage_visitor.visit_body(mir_body); - coverage_visitor.add_missing_operands = true; - coverage_visitor.visit_body(mir_body); - - coverage_visitor.info + // Add 1 to the highest IDs to get the total number of IDs. + CoverageInfo { + num_counters: (coverage_visitor.max_counter_id + 1).as_u32(), + num_expressions: (coverage_visitor.max_expression_id + 1).as_u32(), + } } fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> { let body = mir_body(tcx, def_id); - body.basic_blocks - .iter() - .flat_map(|data| { - data.statements.iter().filter_map(|statement| match statement.kind { - StatementKind::Coverage(box ref coverage) => { - if is_inlined(body, statement) { - None - } else { - coverage.code_region.as_ref() // may be None - } - } - _ => None, - }) - }) + all_coverage_in_mir_body(body) + // Not all coverage statements have an attached code region. + .filter_map(|coverage| coverage.code_region.as_ref()) .collect() } +fn all_coverage_in_mir_body<'a, 'tcx>( + body: &'a Body<'tcx>, +) -> impl Iterator<Item = &'a Coverage> + Captures<'tcx> { + body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| { + match statement.kind { + StatementKind::Coverage(box ref coverage) if !is_inlined(body, statement) => { + Some(coverage) + } + _ => None, + } + }) +} + fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { let scope_data = &body.source_scopes[statement.source_info.scope]; scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 3a1ef3e7d64..333a14be996 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -6,10 +6,10 @@ use rustc_const_eval::const_eval::CheckAlignment; use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; -use rustc_middle::mir::visit::{MutVisitor, Visitor}; +use rustc_middle::mir::visit::{MutVisitor, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, }; @@ -50,7 +50,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp { let place_limit = if tcx.sess.mir_opt_level() < 4 { Some(PLACE_LIMIT) } else { None }; // Decide which places to track during the analysis. - let map = Map::from_filter(tcx, body, Ty::is_scalar, place_limit); + let map = Map::new(tcx, body, place_limit); // Perform the actual dataflow analysis. let analysis = ConstAnalysis::new(tcx, body, map); @@ -58,9 +58,13 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp { .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint()); // Collect results and patch the body afterwards. - let mut visitor = CollectAndPatch::new(tcx); + let mut visitor = CollectAndPatch::new(tcx, &body.local_decls); debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor)); - debug_span!("patch").in_scope(|| visitor.visit_body(body)); + debug_span!("patch").in_scope(|| { + for (block, bbdata) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(block, bbdata); + } + }) } } @@ -73,7 +77,7 @@ struct ConstAnalysis<'a, 'tcx> { } impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { - type Value = FlatSet<ScalarTy<'tcx>>; + type Value = FlatSet<ScalarInt>; const NAME: &'static str = "ConstAnalysis"; @@ -172,9 +176,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { if let Some(overflow_target) = overflow_target { let overflow = match overflow { FlatSet::Top => FlatSet::Top, - FlatSet::Elem(overflow) => { - self.wrap_scalar(Scalar::from_bool(overflow), self.tcx.types.bool) - } + FlatSet::Elem(overflow) => FlatSet::Elem(overflow.into()), FlatSet::Bottom => FlatSet::Bottom, }; // We have flooded `target` earlier. @@ -182,6 +184,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } } + Rvalue::Cast( + CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), + operand, + _, + ) => { + let pointer = self.handle_operand(operand, state); + state.assign(target.as_ref(), pointer, self.map()); + + if let Some(target_len) = self.map().find_len(target.as_ref()) + && let operand_ty = operand.ty(self.local_decls, self.tcx) + && let Some(operand_ty) = operand_ty.builtin_deref(true) + && let ty::Array(_, len) = operand_ty.ty.kind() + && let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int() + { + state.insert_value_idx(target_len, FlatSet::Elem(len), self.map()); + } + } _ => self.super_assign(target, rvalue, state), } } @@ -191,47 +210,77 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { rvalue: &Rvalue<'tcx>, state: &mut State<Self::Value>, ) -> ValueOrPlace<Self::Value> { - match rvalue { - Rvalue::Cast( - kind @ (CastKind::IntToInt - | CastKind::FloatToInt - | CastKind::FloatToFloat - | CastKind::IntToFloat), - operand, - ty, - ) => match self.eval_operand(operand, state) { - FlatSet::Elem(op) => match kind { - CastKind::IntToInt | CastKind::IntToFloat => { - self.ecx.int_to_int_or_float(&op, *ty) - } - CastKind::FloatToInt | CastKind::FloatToFloat => { - self.ecx.float_to_float_or_int(&op, *ty) - } - _ => unreachable!(), + let val = match rvalue { + Rvalue::Len(place) => { + let place_ty = place.ty(self.local_decls, self.tcx); + if let ty::Array(_, len) = place_ty.ty.kind() { + ConstantKind::Ty(*len) + .eval(self.tcx, self.param_env) + .try_to_scalar_int() + .map_or(FlatSet::Top, FlatSet::Elem) + } else if let [ProjectionElem::Deref] = place.projection[..] { + state.get_len(place.local.into(), self.map()) + } else { + FlatSet::Top } - .map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty))) - .unwrap_or(ValueOrPlace::TOP), - _ => ValueOrPlace::TOP, - }, + } + Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { + match self.eval_operand(operand, state) { + FlatSet::Elem(op) => self + .ecx + .int_to_int_or_float(&op, *ty) + .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, + } + } + Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => { + match self.eval_operand(operand, state) { + FlatSet::Elem(op) => self + .ecx + .float_to_float_or_int(&op, *ty) + .map_or(FlatSet::Top, |result| self.wrap_immediate(result)), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, + } + } + Rvalue::Cast(CastKind::Transmute, operand, _) => { + match self.eval_operand(operand, state) { + FlatSet::Elem(op) => self.wrap_immediate(*op), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, + } + } Rvalue::BinaryOp(op, box (left, right)) => { // Overflows must be ignored here. let (val, _overflow) = self.binary_op(state, *op, left, right); - ValueOrPlace::Value(val) + val } Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) { - FlatSet::Elem(value) => self - .ecx - .unary_op(*op, &value) - .map(|val| ValueOrPlace::Value(self.wrap_immty(val))) - .unwrap_or(ValueOrPlace::Value(FlatSet::Top)), - FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom), - FlatSet::Top => ValueOrPlace::Value(FlatSet::Top), + FlatSet::Elem(value) => { + self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val)) + } + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, }, - Rvalue::Discriminant(place) => { - ValueOrPlace::Value(state.get_discr(place.as_ref(), self.map())) + Rvalue::NullaryOp(null_op, ty) => { + let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else { + return ValueOrPlace::Value(FlatSet::Top); + }; + let val = match null_op { + NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), + NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), + NullOp::OffsetOf(fields) => layout + .offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index())) + .bytes(), + _ => return ValueOrPlace::Value(FlatSet::Top), + }; + ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem) } - _ => self.super_rvalue(rvalue, state), - } + Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()), + _ => return self.super_rvalue(rvalue, state), + }; + ValueOrPlace::Value(val) } fn handle_constant( @@ -242,9 +291,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { constant .literal .eval(self.tcx, self.param_env) - .try_to_scalar() - .map(|value| FlatSet::Elem(ScalarTy(value, constant.ty()))) - .unwrap_or(FlatSet::Top) + .try_to_scalar_int() + .map_or(FlatSet::Top, FlatSet::Elem) } fn handle_switch_int<'mir>( @@ -261,9 +309,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { // We are branching on uninitialized data, this is UB, treat it as unreachable. // This allows the set of visited edges to grow monotonically with the lattice. FlatSet::Bottom => TerminatorEdges::None, - FlatSet::Elem(ScalarTy(scalar, _)) => { - let int = scalar.assert_int(); - let choice = int.assert_bits(int.size()); + FlatSet::Elem(scalar) => { + let choice = scalar.assert_bits(scalar.size()); TerminatorEdges::Single(targets.target_for_value(choice)) } FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, @@ -271,16 +318,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } -#[derive(Clone, PartialEq, Eq)] -struct ScalarTy<'tcx>(Scalar, Ty<'tcx>); - -impl<'tcx> std::fmt::Debug for ScalarTy<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // This is used for dataflow visualization, so we return something more concise. - std::fmt::Display::fmt(&ConstantKind::Val(ConstValue::Scalar(self.0), self.1), f) - } -} - impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); @@ -295,32 +332,62 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { fn binary_op( &self, - state: &mut State<FlatSet<ScalarTy<'tcx>>>, + state: &mut State<FlatSet<ScalarInt>>, op: BinOp, left: &Operand<'tcx>, right: &Operand<'tcx>, - ) -> (FlatSet<ScalarTy<'tcx>>, FlatSet<bool>) { + ) -> (FlatSet<ScalarInt>, FlatSet<bool>) { let left = self.eval_operand(left, state); let right = self.eval_operand(right, state); + match (left, right) { + (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), + // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { match self.ecx.overflowing_binary_op(op, &left, &right) { - Ok((val, overflow, ty)) => (self.wrap_scalar(val, ty), FlatSet::Elem(overflow)), + Ok((Scalar::Int(val), overflow, _)) => { + (FlatSet::Elem(val), FlatSet::Elem(overflow)) + } _ => (FlatSet::Top, FlatSet::Top), } } - (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), - (_, _) => { - // Could attempt some algebraic simplifications here. - (FlatSet::Top, FlatSet::Top) + // Exactly one side is known, attempt some algebraic simplifications. + (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => { + let layout = const_arg.layout; + if !matches!(layout.abi, rustc_target::abi::Abi::Scalar(..)) { + return (FlatSet::Top, FlatSet::Top); + } + + let arg_scalar = const_arg.to_scalar(); + let Ok(arg_scalar) = arg_scalar.try_to_int() else { + return (FlatSet::Top, FlatSet::Top); + }; + let Ok(arg_value) = arg_scalar.to_bits(layout.size) else { + return (FlatSet::Top, FlatSet::Top); + }; + + match op { + BinOp::BitAnd if arg_value == 0 => (FlatSet::Elem(arg_scalar), FlatSet::Bottom), + BinOp::BitOr + if arg_value == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && arg_value == 1) => + { + (FlatSet::Elem(arg_scalar), FlatSet::Bottom) + } + BinOp::Mul if layout.ty.is_integral() && arg_value == 0 => { + (FlatSet::Elem(arg_scalar), FlatSet::Elem(false)) + } + _ => (FlatSet::Top, FlatSet::Top), + } } + (FlatSet::Top, FlatSet::Top) => (FlatSet::Top, FlatSet::Top), } } fn eval_operand( &self, op: &Operand<'tcx>, - state: &mut State<FlatSet<ScalarTy<'tcx>>>, + state: &mut State<FlatSet<ScalarInt>>, ) -> FlatSet<ImmTy<'tcx>> { let value = match self.handle_operand(op, state) { ValueOrPlace::Value(value) => value, @@ -328,80 +395,80 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { }; match value { FlatSet::Top => FlatSet::Top, - FlatSet::Elem(ScalarTy(scalar, ty)) => self - .tcx - .layout_of(self.param_env.and(ty)) - .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar, layout))) - .unwrap_or(FlatSet::Top), + FlatSet::Elem(scalar) => { + let ty = op.ty(self.local_decls, self.tcx); + self.tcx + .layout_of(self.param_env.and(ty)) + .map(|layout| FlatSet::Elem(ImmTy::from_scalar(scalar.into(), layout))) + .unwrap_or(FlatSet::Top) + } FlatSet::Bottom => FlatSet::Bottom, } } - fn eval_discriminant( - &self, - enum_ty: Ty<'tcx>, - variant_index: VariantIdx, - ) -> Option<ScalarTy<'tcx>> { + fn eval_discriminant(&self, enum_ty: Ty<'tcx>, variant_index: VariantIdx) -> Option<ScalarInt> { if !enum_ty.is_enum() { return None; } let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?; let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?; - let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?; - Some(ScalarTy(discr_value, discr.ty)) - } - - fn wrap_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> FlatSet<ScalarTy<'tcx>> { - FlatSet::Elem(ScalarTy(scalar, ty)) + let discr_value = ScalarInt::try_from_uint(discr.val, discr_layout.size)?; + Some(discr_value) } - fn wrap_immediate(&self, imm: Immediate, ty: Ty<'tcx>) -> FlatSet<ScalarTy<'tcx>> { + fn wrap_immediate(&self, imm: Immediate) -> FlatSet<ScalarInt> { match imm { - Immediate::Scalar(scalar) => self.wrap_scalar(scalar, ty), + Immediate::Scalar(Scalar::Int(scalar)) => FlatSet::Elem(scalar), _ => FlatSet::Top, } } - fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<ScalarTy<'tcx>> { - self.wrap_immediate(*val, val.layout.ty) + fn wrap_immty(&self, val: ImmTy<'tcx>) -> FlatSet<ScalarInt> { + self.wrap_immediate(*val) } } -struct CollectAndPatch<'tcx> { +struct CollectAndPatch<'tcx, 'locals> { tcx: TyCtxt<'tcx>, + local_decls: &'locals LocalDecls<'tcx>, /// For a given MIR location, this stores the values of the operands used by that location. In /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.) - before_effect: FxHashMap<(Location, Place<'tcx>), ScalarTy<'tcx>>, + before_effect: FxHashMap<(Location, Place<'tcx>), ScalarInt>, /// Stores the assigned values for assignments where the Rvalue is constant. - assignments: FxHashMap<Location, ScalarTy<'tcx>>, + assignments: FxHashMap<Location, ScalarInt>, } -impl<'tcx> CollectAndPatch<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() } +impl<'tcx, 'locals> CollectAndPatch<'tcx, 'locals> { + fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self { + Self { + tcx, + local_decls, + before_effect: FxHashMap::default(), + assignments: FxHashMap::default(), + } } - fn make_operand(&self, scalar: ScalarTy<'tcx>) -> Operand<'tcx> { + fn make_operand(&self, scalar: ScalarInt, ty: Ty<'tcx>) -> Operand<'tcx> { Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, - literal: ConstantKind::Val(ConstValue::Scalar(scalar.0), scalar.1), + literal: ConstantKind::Val(ConstValue::Scalar(scalar.into()), ty), })) } } impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>> - for CollectAndPatch<'tcx> + for CollectAndPatch<'tcx, '_> { - type FlowState = State<FlatSet<ScalarTy<'tcx>>>; + type FlowState = State<FlatSet<ScalarInt>>; fn visit_statement_before_primary_effect( &mut self, - results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, + results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, state: &Self::FlowState, statement: &'mir Statement<'tcx>, location: Location, @@ -417,7 +484,7 @@ impl<'mir, 'tcx> fn visit_statement_after_primary_effect( &mut self, - results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, + results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, state: &Self::FlowState, statement: &'mir Statement<'tcx>, location: Location, @@ -443,7 +510,7 @@ impl<'mir, 'tcx> fn visit_terminator_before_primary_effect( &mut self, - results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, + results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, state: &Self::FlowState, terminator: &'mir Terminator<'tcx>, location: Location, @@ -453,8 +520,8 @@ impl<'mir, 'tcx> } } -impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { +impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -462,7 +529,8 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> { if let Some(value) = self.assignments.get(&location) { match &mut statement.kind { StatementKind::Assign(box (_, rvalue)) => { - *rvalue = Rvalue::Use(self.make_operand(value.clone())); + let ty = rvalue.ty(self.local_decls, self.tcx); + *rvalue = Rvalue::Use(self.make_operand(*value, ty)); } _ => bug!("found assignment info for non-assign statement"), } @@ -475,33 +543,56 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> { match operand { Operand::Copy(place) | Operand::Move(place) => { if let Some(value) = self.before_effect.get(&(location, *place)) { - *operand = self.make_operand(value.clone()); + let ty = place.ty(self.local_decls, self.tcx).ty; + *operand = self.make_operand(*value, ty); + } else if !place.projection.is_empty() { + self.super_operand(operand, location) } } - _ => (), + Operand::Constant(_) => {} + } + } + + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + location: Location, + ) -> Option<PlaceElem<'tcx>> { + if let PlaceElem::Index(local) = elem + && let Some(value) = self.before_effect.get(&(location, local.into())) + && let Ok(offset) = value.try_to_target_usize(self.tcx) + && let Some(min_length) = offset.checked_add(1) + { + Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false }) + } else { + None } } } -struct OperandCollector<'tcx, 'map, 'a> { - state: &'a State<FlatSet<ScalarTy<'tcx>>>, - visitor: &'a mut CollectAndPatch<'tcx>, +struct OperandCollector<'tcx, 'map, 'locals, 'a> { + state: &'a State<FlatSet<ScalarInt>>, + visitor: &'a mut CollectAndPatch<'tcx, 'locals>, map: &'map Map, } -impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> { +impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - match self.state.get(place.as_ref(), self.map) { - FlatSet::Top => (), - FlatSet::Elem(value) => { - self.visitor.before_effect.insert((location, *place), value); - } - FlatSet::Bottom => (), - } + if let Some(place) = operand.place() { + if let FlatSet::Elem(value) = self.state.get(place.as_ref(), self.map) { + self.visitor.before_effect.insert((location, place), value); + } else if !place.projection.is_empty() { + // Try to propagate into `Index` projections. + self.super_operand(operand, location) } - _ => (), + } + } + + fn visit_local(&mut self, local: Local, ctxt: PlaceContext, location: Location) { + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy | NonMutatingUseContext::Move) = ctxt + && let FlatSet::Elem(value) = self.state.get(local.into(), self.map) + { + self.visitor.before_effect.insert((location, local.into()), value); } } } @@ -572,7 +663,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm _bin_op: BinOp, _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, - ) -> interpret::InterpResult<'tcx, (interpret::Scalar<Self::Provenance>, bool, Ty<'tcx>)> { + ) -> interpret::InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)> { throw_unsup!(Unsupported("".into())) } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 4b796d79ef6..35373bcaa41 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -258,10 +258,3 @@ pub(crate) struct MustNotSuspendReason { pub span: Span, pub reason: String, } - -#[derive(Diagnostic)] -#[diag(mir_transform_simd_shuffle_last_const)] -pub(crate) struct SimdShuffleLastConst { - #[primary_span] - pub span: Span, -} diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 1e7161189c3..eae83448c46 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -814,7 +814,7 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_statement_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, state: &Self::FlowState, _statement: &'mir Statement<'tcx>, loc: Location, @@ -824,7 +824,7 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, state: &Self::FlowState, _terminator: &'mir Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index fc36c6e4124..13277d62bf4 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -1,11 +1,10 @@ //! Lowers intrinsic calls -use crate::{errors, MirPass}; +use crate::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; pub struct LowerIntrinsics; @@ -176,23 +175,22 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { } else { span_bug!(terminator.source_info.span, "Only passing a local is supported"); }; + // Add new statement at the end of the block that does the read, and patch + // up the terminator. + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Use(Operand::Copy(derefed_place)), + ))), + }); terminator.kind = match *target { None => { // No target means this read something uninhabited, - // so it must be unreachable, and we don't need to - // preserve the assignment either. + // so it must be unreachable. TerminatorKind::Unreachable } - Some(target) => { - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - *destination, - Rvalue::Use(Operand::Copy(derefed_place)), - ))), - }); - TerminatorKind::Goto { target } - } + Some(target) => TerminatorKind::Goto { target }, } } sym::write_via_move => { @@ -305,9 +303,6 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Unreachable; } } - sym::simd_shuffle => { - validate_simd_shuffle(tcx, args, terminator.source_info.span); - } _ => {} } } @@ -326,9 +321,3 @@ fn resolve_rust_intrinsic<'tcx>( } None } - -fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) { - if !matches!(args[2], Operand::Constant(_)) { - tcx.sess.emit_err(errors::SimdShuffleLastConst { span }); - } -} diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 9c6c55b0811..c13bafa9fbb 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -87,11 +87,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty)) } } - VarDebugInfoContents::Composite { ty, fragments: _ } => { - if self.known_to_be_zst(ty) { - var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty)) - } - } } } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index e66ae8ff884..c21b1724cbb 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,4 +1,5 @@ use crate::MirPass; +use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; use rustc_middle::mir::patch::MirPatch; @@ -147,7 +148,7 @@ fn escaping_locals<'tcx>( } // We ignore anything that happens in debuginfo, since we expand it using - // `VarDebugInfoContents::Composite`. + // `VarDebugInfoFragment`. fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {} } } @@ -246,9 +247,7 @@ fn replace_flattened_locals<'tcx>( for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() { visitor.visit_user_type_annotation(index, annotation); } - for var_debug_info in &mut body.var_debug_info { - visitor.visit_var_debug_info(var_debug_info); - } + visitor.expand_var_debug_info(&mut body.var_debug_info); let ReplacementVisitor { patch, all_dead_locals, .. } = visitor; patch.apply(body); all_dead_locals @@ -256,7 +255,7 @@ fn replace_flattened_locals<'tcx>( struct ReplacementVisitor<'tcx, 'll> { tcx: TyCtxt<'tcx>, - /// This is only used to compute the type for `VarDebugInfoContents::Composite`. + /// This is only used to compute the type for `VarDebugInfoFragment`. local_decls: &'ll LocalDecls<'tcx>, /// Work to do. replacements: &'ll ReplacementMap<'tcx>, @@ -266,16 +265,38 @@ struct ReplacementVisitor<'tcx, 'll> { } impl<'tcx> ReplacementVisitor<'tcx, '_> { - fn gather_debug_info_fragments(&self, local: Local) -> Option<Vec<VarDebugInfoFragment<'tcx>>> { - let mut fragments = Vec::new(); - let parts = self.replacements.place_fragments(local.into())?; - for (field, ty, replacement_local) in parts { - fragments.push(VarDebugInfoFragment { - projection: vec![PlaceElem::Field(field, ty)], - contents: Place::from(replacement_local), - }); - } - Some(fragments) + #[instrument(level = "trace", skip(self))] + fn expand_var_debug_info(&mut self, var_debug_info: &mut Vec<VarDebugInfo<'tcx>>) { + var_debug_info.flat_map_in_place(|mut var_debug_info| { + let place = match var_debug_info.value { + VarDebugInfoContents::Const(_) => return vec![var_debug_info], + VarDebugInfoContents::Place(ref mut place) => place, + }; + + if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { + *place = repl; + return vec![var_debug_info]; + } + + let Some(parts) = self.replacements.place_fragments(*place) else { + return vec![var_debug_info]; + }; + + let ty = place.ty(self.local_decls, self.tcx).ty; + + parts + .map(|(field, field_ty, replacement_local)| { + let mut var_debug_info = var_debug_info.clone(); + let composite = var_debug_info.composite.get_or_insert_with(|| { + Box::new(VarDebugInfoFragment { ty, projection: Vec::new() }) + }); + composite.projection.push(PlaceElem::Field(field, field_ty)); + + var_debug_info.value = VarDebugInfoContents::Place(replacement_local.into()); + var_debug_info + }) + .collect() + }); } } @@ -422,48 +443,6 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.super_statement(statement, location) } - #[instrument(level = "trace", skip(self))] - fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { - match &mut var_debug_info.value { - VarDebugInfoContents::Place(ref mut place) => { - if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { - *place = repl; - } else if let Some(local) = place.as_local() - && let Some(fragments) = self.gather_debug_info_fragments(local) - { - let ty = place.ty(self.local_decls, self.tcx).ty; - var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; - } - } - VarDebugInfoContents::Composite { ty: _, ref mut fragments } => { - let mut new_fragments = Vec::new(); - debug!(?fragments); - fragments.retain_mut(|fragment| { - if let Some(repl) = - self.replacements.replace_place(self.tcx, fragment.contents.as_ref()) - { - fragment.contents = repl; - true - } else if let Some(local) = fragment.contents.as_local() - && let Some(frg) = self.gather_debug_info_fragments(local) - { - new_fragments.extend(frg.into_iter().map(|mut f| { - f.projection.splice(0..0, fragment.projection.iter().copied()); - f - })); - false - } else { - true - } - }); - debug!(?fragments); - debug!(?new_fragments); - fragments.extend(new_fragments); - } - VarDebugInfoContents::Const(_) => {} - } - } - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { assert!(!self.all_dead_locals.contains(*local)); } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index fdd47e6f79b..2b7d9bd3413 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -14,6 +14,10 @@ monomorphize_large_assignments = .label = value moved from here .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` +monomorphize_no_optimized_mir = + missing optimized MIR for an item in the crate `{$crate_name}` + .note = missing optimized MIR for this item (was the crate `{$crate_name}` compiled with `--emit=metadata`?) + monomorphize_recursion_limit = reached the recursion limit while instantiating `{$shrunk}` .note = `{$def_path_str}` defined here diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index bf88360a8c1..8cbb68fc8c1 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -179,8 +179,8 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - VtblEntry, + self, AssocKind, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, VtblEntry, }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; @@ -188,11 +188,13 @@ use rustc_session::config::EntryFnType; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; +use rustc_span::symbol::{sym, Ident}; use rustc_target::abi::Size; use std::path::PathBuf; use crate::errors::{ - EncounteredErrorWhileInstantiating, LargeAssignmentsLint, RecursionLimit, TypeLengthLimit, + EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit, + TypeLengthLimit, }; #[derive(PartialEq)] @@ -431,7 +433,7 @@ fn collect_items_rec<'tcx>( hir::InlineAsmOperand::SymFn { anon_const } => { let fn_ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); - visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items); + visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items, &[]); } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { let instance = Instance::mono(tcx, *def_id); @@ -592,6 +594,11 @@ struct MirUsedCollector<'a, 'tcx> { instance: Instance<'tcx>, /// Spans for move size lints already emitted. Helps avoid duplicate lints. move_size_spans: Vec<Span>, + /// If true, we should temporarily skip move size checks, because we are + /// processing an operand to a `skip_move_check_fns` function call. + skip_move_size_check: bool, + /// Set of functions for which it is OK to move large data into. + skip_move_check_fns: Vec<DefId>, } impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { @@ -690,7 +697,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { ) => { let fn_ty = operand.ty(self.body, self.tcx); let fn_ty = self.monomorphize(fn_ty); - visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); + visit_fn_use( + self.tcx, + fn_ty, + false, + span, + &mut self.output, + &self.skip_move_check_fns, + ); } mir::Rvalue::Cast( mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), @@ -789,7 +803,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.body, tcx); let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output) + self.skip_move_size_check = visit_fn_use( + self.tcx, + callee_ty, + true, + source, + &mut self.output, + &self.skip_move_check_fns, + ) } mir::TerminatorKind::Drop { ref place, .. } => { let ty = place.ty(self.body, self.tcx).ty; @@ -801,7 +822,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { match *op { mir::InlineAsmOperand::SymFn { ref value } => { let fn_ty = self.monomorphize(value.literal.ty()); - visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); + visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]); } mir::InlineAsmOperand::SymStatic { def_id } => { let instance = Instance::mono(self.tcx, def_id); @@ -840,12 +861,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } self.super_terminator(terminator, location); + self.skip_move_size_check = false; } fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { self.super_operand(operand, location); let move_size_limit = self.tcx.move_size_limit().0; - if move_size_limit > 0 { + if move_size_limit > 0 && !self.skip_move_size_check { self.check_move_size(move_size_limit, operand, location); } } @@ -876,8 +898,11 @@ fn visit_fn_use<'tcx>( is_direct_call: bool, source: Span, output: &mut MonoItems<'tcx>, -) { + skip_move_check_fns: &[DefId], +) -> bool { + let mut skip_move_size_check = false; if let ty::FnDef(def_id, args) = *ty.kind() { + skip_move_size_check = skip_move_check_fns.contains(&def_id); let instance = if is_direct_call { ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) } else { @@ -888,6 +913,7 @@ fn visit_fn_use<'tcx>( }; visit_instance_use(tcx, instance, is_direct_call, source, output); } + skip_move_size_check } fn visit_instance_use<'tcx>( @@ -960,7 +986,10 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> } if !tcx.is_mir_available(def_id) { - bug!("no MIR available for {:?}", def_id); + tcx.sess.emit_fatal(NoOptimizedMir { + span: tcx.def_span(def_id), + crate_name: tcx.crate_name(def_id.krate), + }); } true @@ -1365,6 +1394,31 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } +fn add_assoc_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: Option<DefId>, + fn_ident: Ident, + skip_move_check_fns: &mut Vec<DefId>, +) { + if let Some(def_id) = def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, fn_ident)) { + skip_move_check_fns.push(def_id); + } +} + +fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> { + for impl_def_id in tcx.inherent_impls(def_id) { + if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind( + tcx, + fn_ident, + AssocKind::Fn, + def_id, + ) { + return Some(new.def_id); + } + } + return None; +} + /// Scans the MIR in order to find function calls, closures, and drop-glue. #[instrument(skip(tcx, output), level = "debug")] fn collect_used_items<'tcx>( @@ -1373,8 +1427,39 @@ fn collect_used_items<'tcx>( output: &mut MonoItems<'tcx>, ) { let body = tcx.instance_mir(instance.def); - MirUsedCollector { tcx, body: &body, output, instance, move_size_spans: vec![] } - .visit_body(&body); + + let mut skip_move_check_fns = vec![]; + if tcx.move_size_limit().0 > 0 { + add_assoc_fn( + tcx, + tcx.lang_items().owned_box(), + Ident::from_str("new"), + &mut skip_move_check_fns, + ); + add_assoc_fn( + tcx, + tcx.get_diagnostic_item(sym::Arc), + Ident::from_str("new"), + &mut skip_move_check_fns, + ); + add_assoc_fn( + tcx, + tcx.get_diagnostic_item(sym::Rc), + Ident::from_str("new"), + &mut skip_move_check_fns, + ); + } + + MirUsedCollector { + tcx, + body: &body, + output, + instance, + move_size_spans: vec![], + skip_move_size_check: false, + skip_move_check_fns, + } + .visit_body(&body); } #[instrument(skip(tcx, output), level = "debug")] diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 495a73490a2..fdcc95f137f 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -4,7 +4,7 @@ use crate::fluent_generated as fluent; use rustc_errors::ErrorGuaranteed; use rustc_errors::IntoDiagnostic; use rustc_macros::{Diagnostic, LintDiagnostic}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] #[diag(monomorphize_recursion_limit)] @@ -33,6 +33,14 @@ pub struct TypeLengthLimit { pub type_length: usize, } +#[derive(Diagnostic)] +#[diag(monomorphize_no_optimized_mir)] +pub struct NoOptimizedMir { + #[note] + pub span: Span, + pub crate_name: Symbol, +} + pub struct UnusedGenericParamsHint { pub span: Span, pub param_spans: Vec<Span>, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 598adbe7985..c012a866332 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -132,7 +132,7 @@ fn maybe_source_file_to_parser( sess: &ParseSess, source_file: Lrc<SourceFile>, ) -> Result<Parser<'_>, Vec<Diagnostic>> { - let end_pos = source_file.end_pos; + let end_pos = source_file.end_position(); let stream = maybe_file_to_stream(sess, source_file, None)?; let mut parser = stream_to_parser(sess, stream, None); if parser.token == token::Eof { diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 5d6c574baa6..c4e8d9006e6 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -106,7 +106,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { let mut cursor_snapshot = self.cursor_snapshot.clone(); let tokens = std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) - .chain((0..self.num_calls).map(|_| { + .chain(std::iter::repeat_with(|| { let token = cursor_snapshot.next(); (FlatToken::Token(token.0), token.1) })) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9ae3ef6172c..5898c6565e6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2477,9 +2477,7 @@ impl<'a> Parser<'a> { } else { self.expect(&token::Eq)?; } - let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { - this.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), None.into()) - })?; + let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), None.into())?; let span = lo.to(expr.span); self.sess.gated_spans.gate(sym::let_chains, span); Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span))) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 233c7016417..aad4edaba90 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -73,12 +73,16 @@ impl<'a> Parser<'a> { if !self.maybe_consume_incorrect_semicolon(&items) { let msg = format!("expected item, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); - let label = if self.is_kw_followed_by_ident(kw::Let) { - "consider using `const` or `static` instead of `let` for global variables" + let span = self.token.span; + if self.is_kw_followed_by_ident(kw::Let) { + err.span_label( + span, + "consider using `const` or `static` instead of `let` for global variables", + ); } else { - "expected item" + err.span_label(span, "expected item") + .note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>"); }; - err.span_label(self.token.span, label); return Err(err); } } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 72da398d3fc..14330353239 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] rustc_lexer = { path = "../rustc_lexer" } -rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index", default-features = false } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 88452ccdf05..a6c7eb8d912 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -1011,7 +1011,7 @@ fn unescape_string(string: &str) -> Option<string::String> { // Assert a reasonable size for `Piece` #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Piece<'_>, 16); +rustc_index::static_assert_size!(Piece<'_>, 16); #[cfg(test)] mod tests; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 57598cf8bcf..9f3cd656bd1 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -4,14 +4,14 @@ -passes_see_issue = see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information -passes_abi = - abi: {$abi} - +passes_abi_invalid_attribute = + `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions +passes_abi_ne = + ABIs are not compatible + left ABI = {$left} + right ABI = {$right} passes_abi_of = - fn_abi_of_instance({$fn_name}) = {$fn_abi} - -passes_align = - align: {$align} + fn_abi_of({$fn_name}) = {$fn_abi} passes_allow_incoherent_impl = `rustc_allow_incoherent_impl` attribute should be applied to impl items. @@ -318,9 +318,6 @@ passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. .label = only adts, extern types and traits are supported -passes_homogeneous_aggregate = - homogeneous_aggregate: {$homogeneous_aggregate} - passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms .warn = {-passes_previously_accepted} @@ -404,9 +401,18 @@ passes_lang_item_on_incorrect_target = passes_layout = layout error: {$layout_error} - +passes_layout_abi = + abi: {$abi} +passes_layout_align = + align: {$align} +passes_layout_homogeneous_aggregate = + homogeneous_aggregate: {$homogeneous_aggregate} +passes_layout_invalid_attribute = + `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases passes_layout_of = layout_of({$normalized_ty}) = {$ty_layout} +passes_layout_size = + size: {$size} passes_link = attribute should be applied to an `extern` block with non-Rust ABI @@ -662,9 +668,6 @@ passes_should_be_applied_to_trait = attribute should be applied to a trait .label = not a trait -passes_size = - size: {$size} - passes_skipping_const_checks = skipping const checks passes_stability_promotable = diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 5c0438e78ae..9e4d960af14 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -1,44 +1,66 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::layout::{FnAbiError, LayoutError}; -use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; +use rustc_target::abi::call::FnAbi; -use crate::errors::{AbiOf, UnrecognizedField}; +use super::layout_test::ensure_wf; +use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; pub fn test_abi(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing ABI return; } - for id in tcx.hir().items() { - match tcx.def_kind(id.owner_id) { - DefKind::Fn => { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) { - dump_abi_of(tcx, id.owner_id.def_id.into(), attr); + for id in tcx.hir_crate_items(()).definitions() { + for attr in tcx.get_attrs(id, sym::rustc_abi) { + match tcx.def_kind(id) { + DefKind::Fn | DefKind::AssocFn => { + dump_abi_of_fn_item(tcx, id, attr); } - } - DefKind::Impl { .. } => { - // To find associated functions we need to go into the child items here. - for &id in tcx.associated_item_def_ids(id.owner_id) { - if matches!(tcx.def_kind(id), DefKind::AssocFn) { - for attr in tcx.get_attrs(id, sym::rustc_abi) { - dump_abi_of(tcx, id, attr); - } - } + DefKind::TyAlias { .. } => { + dump_abi_of_fn_type(tcx, id, attr); + } + _ => { + tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) }); } } - _ => {} } } } -fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { +fn unwrap_fn_abi<'tcx>( + abi: Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>>, + tcx: TyCtxt<'tcx>, + item_def_id: LocalDefId, +) -> &'tcx FnAbi<'tcx, Ty<'tcx>> { + match abi { + Ok(abi) => abi, + Err(FnAbiError::Layout(layout_error)) => { + tcx.sess.emit_fatal(Spanned { + node: layout_error.into_diagnostic(), + span: tcx.def_span(item_def_id), + }); + } + Err(FnAbiError::AdjustForForeignAbi(e)) => { + // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if + // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE + // isn't the worst thing. Also this matches what codegen does. + span_bug!( + tcx.def_span(item_def_id), + "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", + ) + } + } +} + +fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let args = GenericArgs::identity_for_item(tcx, item_def_id); - let instance = match Instance::resolve(tcx, param_env, item_def_id, args) { + let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) { Ok(Some(instance)) => instance, Ok(None) => { // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? @@ -51,43 +73,125 @@ fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) { } Err(_guaranteed) => return, }; - match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) { - Ok(abi) => { - // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. - // The `..` are the names of fields to dump. - let meta_items = attr.meta_item_list().unwrap_or_default(); - for meta_item in meta_items { - match meta_item.name_or_empty() { - sym::debug => { - let fn_name = tcx.item_name(item_def_id); - tcx.sess.emit_err(AbiOf { - span: tcx.def_span(item_def_id), - fn_name, - fn_abi: format!("{:#?}", abi), - }); - } + let abi = unwrap_fn_abi( + tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))), + tcx, + item_def_id, + ); - name => { - tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); - } - } + // Check out the `#[rustc_abi(..)]` attribute to tell what to dump. + // The `..` are the names of fields to dump. + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let fn_name = tcx.item_name(item_def_id.into()); + tcx.sess.emit_err(AbiOf { + span: tcx.def_span(item_def_id), + fn_name, + // FIXME: using the `Debug` impl here isn't ideal. + fn_abi: format!("{:#?}", abi), + }); } - } - Err(FnAbiError::Layout(layout_error)) => { - tcx.sess.emit_fatal(Spanned { - node: layout_error.into_diagnostic(), - span: tcx.def_span(item_def_id), - }); + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } } - Err(FnAbiError::AdjustForForeignAbi(e)) => { - // Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if - // this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE - // isn't the worst thing. Also this matches what codegen does. - span_bug!( - tcx.def_span(item_def_id), - "error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}", - ) + } +} + +fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx, Ty<'tcx>>) -> bool { + if abi1.conv != abi2.conv + || abi1.args.len() != abi2.args.len() + || abi1.c_variadic != abi2.c_variadic + || abi1.fixed_count != abi2.fixed_count + || abi1.can_unwind != abi2.can_unwind + { + return false; + } + + abi1.ret.eq_abi(&abi2.ret) + && abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| arg1.eq_abi(arg2)) +} + +fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { + let param_env = tcx.param_env(item_def_id); + let ty = tcx.type_of(item_def_id).instantiate_identity(); + let span = tcx.def_span(item_def_id); + if !ensure_wf(tcx, param_env, ty, item_def_id, span) { + return; + } + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::debug => { + let ty::FnPtr(sig) = ty.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(debug)]` on a type alias requires function pointer type" + ); + }; + let abi = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr(param_env.and((*sig, /* extra_args */ ty::List::empty()))), + tcx, + item_def_id, + ); + + let fn_name = tcx.item_name(item_def_id.into()); + tcx.sess.emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) }); + } + sym::assert_eq => { + let ty::Tuple(fields) = ty.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair type" + ); + }; + let [field1, field2] = ***fields else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair type" + ); + }; + let ty::FnPtr(sig1) = field1.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types" + ); + }; + let abi1 = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr( + param_env.and((*sig1, /* extra_args */ ty::List::empty())), + ), + tcx, + item_def_id, + ); + let ty::FnPtr(sig2) = field2.kind() else { + span_bug!( + meta_item.span(), + "`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types" + ); + }; + let abi2 = unwrap_fn_abi( + tcx.fn_abi_of_fn_ptr( + param_env.and((*sig2, /* extra_args */ ty::List::empty())), + ), + tcx, + item_def_id, + ); + + if !test_abi_eq(abi1, abi2) { + tcx.sess.emit_err(AbiNe { + span, + left: format!("{:#?}", abi1), + right: format!("{:#?}", abi2), + }); + } + } + name => { + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); + } } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 32dd02a4aa9..d7319ef91e0 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -873,32 +873,32 @@ pub struct DuplicateDiagnosticItemInCrate { } #[derive(Diagnostic)] -#[diag(passes_abi)] -pub struct Abi { +#[diag(passes_layout_abi)] +pub struct LayoutAbi { #[primary_span] pub span: Span, pub abi: String, } #[derive(Diagnostic)] -#[diag(passes_align)] -pub struct Align { +#[diag(passes_layout_align)] +pub struct LayoutAlign { #[primary_span] pub span: Span, pub align: String, } #[derive(Diagnostic)] -#[diag(passes_size)] -pub struct Size { +#[diag(passes_layout_size)] +pub struct LayoutSize { #[primary_span] pub span: Span, pub size: String, } #[derive(Diagnostic)] -#[diag(passes_homogeneous_aggregate)] -pub struct HomogeneousAggregate { +#[diag(passes_layout_homogeneous_aggregate)] +pub struct LayoutHomogeneousAggregate { #[primary_span] pub span: Span, pub homogeneous_aggregate: String, @@ -914,6 +914,13 @@ pub struct LayoutOf { } #[derive(Diagnostic)] +#[diag(passes_layout_invalid_attribute)] +pub struct LayoutInvalidAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(passes_abi_of)] pub struct AbiOf { #[primary_span] @@ -923,6 +930,22 @@ pub struct AbiOf { } #[derive(Diagnostic)] +#[diag(passes_abi_ne)] +pub struct AbiNe { + #[primary_span] + pub span: Span, + pub left: String, + pub right: String, +} + +#[derive(Diagnostic)] +#[diag(passes_abi_invalid_attribute)] +pub struct AbiInvalidAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(passes_unrecognized_field)] pub struct UnrecognizedField { #[primary_span] diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index d839fee07a6..e3a63f2e004 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -2,34 +2,76 @@ use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::{infer::TyCtxtInferExt, traits}; -use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField}; +use crate::errors::{ + LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf, + LayoutSize, UnrecognizedField, +}; pub fn test_layout(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout return; } - for id in tcx.hir().items() { - if matches!( - tcx.def_kind(id.owner_id), - DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union - ) { - for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { - dump_layout_of(tcx, id.owner_id.def_id, attr); + for id in tcx.hir_crate_items(()).definitions() { + for attr in tcx.get_attrs(id, sym::rustc_layout) { + match tcx.def_kind(id) { + DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union => { + dump_layout_of(tcx, id, attr); + } + _ => { + tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) }); + } } } } } +pub fn ensure_wf<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: LocalDefId, + span: Span, +) -> bool { + let pred = ty::ClauseKind::WellFormed(ty.into()); + let obligation = traits::Obligation::new( + tcx, + traits::ObligationCause::new( + span, + def_id, + traits::ObligationCauseCode::WellFormed(Some(traits::WellFormedLoc::Ty(def_id))), + ), + param_env, + pred, + ); + let infcx = tcx.infer_ctxt().build(); + let ocx = traits::ObligationCtxt::new(&infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors); + false + } else { + // looks WF! + true + } +} + fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); + let span = tcx.def_span(item_def_id.to_def_id()); + if !ensure_wf(tcx, param_env, ty, item_def_id, span) { + return; + } match tcx.layout_of(param_env.and(ty)) { Ok(ty_layout) => { // Check out the `#[rustc_layout(..)]` attribute to tell what to dump. @@ -38,29 +80,24 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { for meta_item in meta_items { match meta_item.name_or_empty() { sym::abi => { - tcx.sess.emit_err(Abi { - span: tcx.def_span(item_def_id.to_def_id()), - abi: format!("{:?}", ty_layout.abi), - }); + tcx.sess.emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) }); } sym::align => { - tcx.sess.emit_err(Align { - span: tcx.def_span(item_def_id.to_def_id()), + tcx.sess.emit_err(LayoutAlign { + span, align: format!("{:?}", ty_layout.align), }); } sym::size => { - tcx.sess.emit_err(Size { - span: tcx.def_span(item_def_id.to_def_id()), - size: format!("{:?}", ty_layout.size), - }); + tcx.sess + .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) }); } sym::homogeneous_aggregate => { - tcx.sess.emit_err(HomogeneousAggregate { - span: tcx.def_span(item_def_id.to_def_id()), + tcx.sess.emit_err(LayoutHomogeneousAggregate { + span, homogeneous_aggregate: format!( "{:?}", ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }) @@ -70,18 +107,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { sym::debug => { let normalized_ty = format!( - "{:?}", + "{}", tcx.normalize_erasing_regions( param_env.with_reveal_all_normalized(tcx), ty, ) ); + // FIXME: using the `Debug` impl here isn't ideal. let ty_layout = format!("{:#?}", *ty_layout); - tcx.sess.emit_err(LayoutOf { - span: tcx.def_span(item_def_id.to_def_id()), - normalized_ty, - ty_layout, - }); + tcx.sess.emit_err(LayoutOf { span, normalized_ty, ty_layout }); } name => { @@ -92,11 +126,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { } Err(layout_error) => { - tcx.sess.emit_fatal(Spanned { - node: layout_error.into_diagnostic(), - - span: tcx.def_span(item_def_id.to_def_id()), - }); + tcx.sess.emit_fatal(Spanned { node: layout_error.into_diagnostic(), span }); } } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index e62833b358b..1239d6d91ac 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -90,6 +90,10 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { .typeck_results() .type_dependent_def(expr.hir_id) .map(|(kind, def_id)| Res::Def(kind, def_id)), + hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => { + self.reachable_symbols.insert(def_id); + None + } _ => None, }; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 906a36cdb25..aedc7b22725 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1463,14 +1463,15 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let vis = self.tcx.local_visibility(local_def_id); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let span = self.tcx.def_span(self.item_def_id.to_def_id()); let vis_span = self.tcx.def_span(def_id); if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) { let vis_descr = match vis { ty::Visibility::Public => "public", ty::Visibility::Restricted(vis_def_id) => { - if vis_def_id == self.tcx.parent_module(hir_id).to_local_def_id() { + if vis_def_id + == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id() + { "private" } else if vis_def_id.is_top_level_module() { "crate-private" @@ -1504,7 +1505,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; self.tcx.emit_spanned_lint( lint, - hir_id, + self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), span, PrivateInterfacesOrBoundsLint { item_span: span, diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index ac697a3ae3e..a44dd5ede2f 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" [dependencies] field-offset = "0.3.5" measureme = "10.0.0" -rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_query_system/src/dep_graph/edges.rs b/compiler/rustc_query_system/src/dep_graph/edges.rs new file mode 100644 index 00000000000..6ba3924f65e --- /dev/null +++ b/compiler/rustc_query_system/src/dep_graph/edges.rs @@ -0,0 +1,73 @@ +use crate::dep_graph::DepNodeIndex; +use smallvec::SmallVec; +use std::hash::{Hash, Hasher}; +use std::iter::Extend; +use std::ops::Deref; + +#[derive(Default, Debug)] +pub struct EdgesVec { + max: u32, + edges: SmallVec<[DepNodeIndex; EdgesVec::INLINE_CAPACITY]>, +} + +impl Hash for EdgesVec { + #[inline] + fn hash<H: Hasher>(&self, hasher: &mut H) { + Hash::hash(&self.edges, hasher) + } +} + +impl EdgesVec { + pub const INLINE_CAPACITY: usize = 8; + + #[inline] + pub fn new() -> Self { + Self::default() + } + + #[inline] + pub fn push(&mut self, edge: DepNodeIndex) { + self.max = self.max.max(edge.as_u32()); + self.edges.push(edge); + } + + #[inline] + pub fn max_index(&self) -> u32 { + self.max + } +} + +impl Deref for EdgesVec { + type Target = [DepNodeIndex]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.edges.as_slice() + } +} + +impl FromIterator<DepNodeIndex> for EdgesVec { + #[inline] + fn from_iter<T>(iter: T) -> Self + where + T: IntoIterator<Item = DepNodeIndex>, + { + let mut vec = EdgesVec::new(); + for index in iter { + vec.push(index) + } + vec + } +} + +impl Extend<DepNodeIndex> for EdgesVec { + #[inline] + fn extend<T>(&mut self, iter: T) + where + T: IntoIterator<Item = DepNodeIndex>, + { + for elem in iter { + self.push(elem); + } + } +} diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0d4d13ac20d..fa54e1a2e6a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -8,7 +8,6 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; -use smallvec::{smallvec, SmallVec}; use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use std::fmt::Debug; @@ -19,6 +18,7 @@ use std::sync::atomic::Ordering::Relaxed; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; +use crate::dep_graph::EdgesVec; use crate::ich::StableHashingContext; use crate::query::{QueryContext, QuerySideEffects}; @@ -137,7 +137,7 @@ impl<K: DepKind> DepGraph<K> { let _green_node_index = current.intern_new_node( profiler, DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() }, - smallvec![], + EdgesVec::new(), Fingerprint::ZERO, ); assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); @@ -147,7 +147,7 @@ impl<K: DepKind> DepGraph<K> { profiler, &prev_graph, DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, - smallvec![], + EdgesVec::new(), None, false, ); @@ -356,12 +356,12 @@ impl<K: DepKind> DepGraphData<K> { let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg)); let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { - (with_deps(TaskDepsRef::EvalAlways), smallvec![]) + (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new()) } else { let task_deps = Lock::new(TaskDeps { #[cfg(debug_assertions)] node: Some(key), - reads: SmallVec::new(), + reads: EdgesVec::new(), read_set: Default::default(), phantom_data: PhantomData, }); @@ -486,14 +486,14 @@ impl<K: DepKind> DepGraph<K> { // As long as we only have a low number of reads we can avoid doing a hash // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + let new_read = if task_deps.reads.len() < EdgesVec::INLINE_CAPACITY { task_deps.reads.iter().all(|other| *other != dep_node_index) } else { task_deps.read_set.insert(dep_node_index) }; if new_read { task_deps.reads.push(dep_node_index); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { + if task_deps.reads.len() == EdgesVec::INLINE_CAPACITY { // Fill `read_set` with what we have so far so we can use the hashset // next time task_deps.read_set.extend(task_deps.reads.iter().copied()); @@ -572,7 +572,7 @@ impl<K: DepKind> DepGraph<K> { } } - let mut edges = SmallVec::new(); + let mut edges = EdgesVec::new(); K::read_deps(|task_deps| match task_deps { TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()), TaskDepsRef::EvalAlways => { @@ -629,12 +629,7 @@ impl<K: DepKind> DepGraphData<K> { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.current.prev_index_to_index.lock()[prev_index] } else { - self.current - .new_node_to_index - .get_shard_by_value(dep_node) - .lock() - .get(dep_node) - .copied() + self.current.new_node_to_index.lock_shard_by_value(dep_node).get(dep_node).copied() } } @@ -872,7 +867,7 @@ impl<K: DepKind> DepGraphData<K> { let prev_deps = self.previous.edge_targets_from(prev_dep_node_index); - for &dep_dep_node_index in prev_deps { + for dep_dep_node_index in prev_deps { self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?; } @@ -1201,8 +1196,7 @@ impl<K: DepKind> CurrentDepGraph<K> { edges: EdgesVec, current_fingerprint: Fingerprint, ) -> DepNodeIndex { - let dep_node_index = match self.new_node_to_index.get_shard_by_value(&key).lock().entry(key) - { + let dep_node_index = match self.new_node_to_index.lock_shard_by_value(&key).entry(key) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let dep_node_index = @@ -1308,8 +1302,7 @@ impl<K: DepKind> CurrentDepGraph<K> { let key = prev_graph.index_to_node(prev_index); let edges = prev_graph .edge_targets_from(prev_index) - .iter() - .map(|i| prev_index_to_index[*i].unwrap()) + .map(|i| prev_index_to_index[i].unwrap()) .collect(); let fingerprint = prev_graph.fingerprint_by_index(prev_index); let dep_node_index = self.encoder.borrow().send(profiler, key, fingerprint, edges); @@ -1329,16 +1322,12 @@ impl<K: DepKind> CurrentDepGraph<K> { ) { let node = &prev_graph.index_to_node(prev_index); debug_assert!( - !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node), + !self.new_node_to_index.lock_shard_by_value(node).contains_key(node), "node from previous graph present in new node collection" ); } } -/// The capacity of the `reads` field `SmallVec` -const TASK_DEPS_READS_CAP: usize = 8; -type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; - #[derive(Debug, Clone, Copy)] pub enum TaskDepsRef<'a, K: DepKind> { /// New dependencies can be added to the diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 0fd9e35d6dc..272028d35bf 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,10 +1,12 @@ pub mod debug; mod dep_node; +mod edges; mod graph; mod query; mod serialized; pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId}; +pub use edges::EdgesVec; pub use graph::{ hash_result, DepGraph, DepGraphData, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductMap, @@ -157,4 +159,10 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> fn read_deps<OP>(op: OP) where OP: for<'a> FnOnce(TaskDepsRef<'a, Self>); + + fn from_u16(u: u16) -> Self; + + fn to_u16(self) -> u16; + + const MAX: u16; } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index edddfda6242..4ba0cb31d0b 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -1,6 +1,6 @@ //! The data that we will serialize and deserialize. //! -//! The dep-graph is serialized as a sequence of NodeInfo, with the dependencies +//! Notionally, the dep-graph is a sequence of NodeInfo with the dependencies //! specified inline. The total number of nodes and edges are stored as the last //! 16 bytes of the file, so we can find them easily at decoding time. //! @@ -11,17 +11,42 @@ //! sequence of NodeInfos to the different arrays in SerializedDepGraph. Since the //! node and edge count are stored at the end of the file, all the arrays can be //! pre-allocated with the right length. +//! +//! The encoding of the de-pgraph is generally designed around the fact that fixed-size +//! reads of encoded data are generally faster than variable-sized reads. Ergo we adopt +//! essentially the same varint encoding scheme used in the rmeta format; the edge lists +//! for each node on the graph store a 2-bit integer which is the number of bytes per edge +//! index in that node's edge list. We effectively ignore that an edge index of 0 could be +//! encoded with 0 bytes in order to not require 3 bits to store the byte width of the edges. +//! The overhead of calculating the correct byte width for each edge is mitigated by +//! building edge lists with [`EdgesVec`] which keeps a running max of the edges in a node. +//! +//! When we decode this data, we do not immediately create [`SerializedDepNodeIndex`] and +//! instead keep the data in its denser serialized form which lets us turn our on-disk size +//! efficiency directly into a peak memory reduction. When we convert these encoded-in-memory +//! values into their fully-deserialized type, we use a fixed-size read of the encoded array +//! then mask off any errant bytes we read. The array of edge index bytes is padded to permit this. +//! +//! We also encode and decode the entire rest of each node using [`SerializedNodeHeader`] +//! to let this encoding and decoding be done in one fixed-size operation. These headers contain +//! two [`Fingerprint`]s along with the serialized [`DepKind`], and the number of edge indices +//! in the node and the number of bytes used to encode the edge indices for this node. The +//! [`DepKind`], number of edges, and bytes per edge are all bit-packed together, if they fit. +//! If the number of edges in this node does not fit in the bits available in the header, we +//! store it directly after the header with leb128. use super::query::DepGraphQuery; use super::{DepKind, DepNode, DepNodeIndex}; +use crate::dep_graph::EdgesVec; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fingerprint::PackedFingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_index::{Idx, IndexVec}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; -use rustc_serialize::{Decodable, Decoder, Encodable}; -use smallvec::SmallVec; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::marker::PhantomData; // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits // unused so that we can store multiple index types in `CompressedHybridIndex`, @@ -31,6 +56,16 @@ rustc_index::newtype_index! { pub struct SerializedDepNodeIndex {} } +const DEP_NODE_SIZE: usize = std::mem::size_of::<SerializedDepNodeIndex>(); +/// Amount of padding we need to add to the edge list data so that we can retrieve every +/// SerializedDepNodeIndex with a fixed-size read then mask. +const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; +/// Number of bits we need to store the number of used bytes in a SerializedDepNodeIndex. +/// Note that wherever we encode byte widths like this we actually store the number of bytes used +/// minus 1; for a 4-byte value we technically would have 5 widths to store, but using one byte to +/// store zeroes (which are relatively rare) is a decent tradeoff to save a bit in our bitfields. +const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2; + /// Data for use when recompiling the **current crate**. #[derive(Debug)] pub struct SerializedDepGraph<K: DepKind> { @@ -42,10 +77,10 @@ pub struct SerializedDepGraph<K: DepKind> { /// For each DepNode, stores the list of edges originating from that /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, /// which holds the actual DepNodeIndices of the target nodes. - edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>, - /// A flattened list of all edge targets in the graph. Edge sources are - /// implicit in edge_list_indices. - edge_list_data: Vec<SerializedDepNodeIndex>, + edge_list_indices: IndexVec<SerializedDepNodeIndex, EdgeHeader>, + /// A flattened list of all edge targets in the graph, stored in the same + /// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices. + edge_list_data: Vec<u8>, /// Reciprocal map to `nodes`. index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>, } @@ -64,9 +99,35 @@ impl<K: DepKind> Default for SerializedDepGraph<K> { impl<K: DepKind> SerializedDepGraph<K> { #[inline] - pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { - let targets = self.edge_list_indices[source]; - &self.edge_list_data[targets.0 as usize..targets.1 as usize] + pub fn edge_targets_from( + &self, + source: SerializedDepNodeIndex, + ) -> impl Iterator<Item = SerializedDepNodeIndex> + '_ { + let header = self.edge_list_indices[source]; + let mut raw = &self.edge_list_data[header.start()..]; + // Figure out where the edge list for `source` ends by getting the start index of the next + // edge list, or the end of the array if this is the last edge. + let end = self + .edge_list_indices + .get(source + 1) + .map(|h| h.start()) + .unwrap_or_else(|| self.edge_list_data.len() - DEP_NODE_PAD); + + // The number of edges for this node is implicitly stored in the combination of the byte + // width and the length. + let bytes_per_index = header.bytes_per_index(); + let len = (end - header.start()) / bytes_per_index; + + // LLVM doesn't hoist EdgeHeader::mask so we do it ourselves. + let mask = header.mask(); + (0..len).map(move |_| { + // Doing this slicing in this order ensures that the first bounds check suffices for + // all the others. + let index = &raw[..DEP_NODE_SIZE]; + raw = &raw[bytes_per_index..]; + let index = u32::from_le_bytes(index.try_into().unwrap()) & mask; + SerializedDepNodeIndex::from_u32(index) + }) } #[inline] @@ -84,11 +145,42 @@ impl<K: DepKind> SerializedDepGraph<K> { self.fingerprints[dep_node_index] } + #[inline] pub fn node_count(&self) -> usize { self.index.len() } } +/// A packed representation of an edge's start index and byte width. +/// +/// This is packed by stealing 2 bits from the start index, which means we only accomodate edge +/// data arrays up to a quarter of our address space. Which seems fine. +#[derive(Debug, Clone, Copy)] +struct EdgeHeader { + repr: usize, +} + +impl EdgeHeader { + #[inline] + fn start(self) -> usize { + self.repr >> DEP_NODE_WIDTH_BITS + } + + #[inline] + fn bytes_per_index(self) -> usize { + (self.repr & mask(DEP_NODE_WIDTH_BITS)) + 1 + } + + #[inline] + fn mask(self) -> u32 { + mask(self.bytes_per_index() * 8) as u32 + } +} + +fn mask(bits: usize) -> usize { + usize::MAX >> ((std::mem::size_of::<usize>() * 8) - bits) +} + impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> for SerializedDepGraph<K> { @@ -107,32 +199,58 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> debug!(?node_count, ?edge_count); + let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); + let mut nodes = IndexVec::with_capacity(node_count); let mut fingerprints = IndexVec::with_capacity(node_count); let mut edge_list_indices = IndexVec::with_capacity(node_count); - let mut edge_list_data = Vec::with_capacity(edge_count); + // This estimation assumes that all of the encoded bytes are for the edge lists or for the + // fixed-size node headers. But that's not necessarily true; if any edge list has a length + // that spills out of the size we can bit-pack into SerializedNodeHeader then some of the + // total serialized size is also used by leb128-encoded edge list lengths. Neglecting that + // contribution to graph_bytes means our estimation of the bytes needed for edge_list_data + // slightly overshoots. But it cannot overshoot by much; consider that the worse case is + // for a node with length 64, which means the spilled 1-byte leb128 length is 1 byte of at + // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128 + // length is about the same fractional overhead and it amortizes for yet greater lengths. + let mut edge_list_data = Vec::with_capacity( + graph_bytes - node_count * std::mem::size_of::<SerializedNodeHeader<K>>(), + ); for _index in 0..node_count { - let dep_node: DepNode<K> = Decodable::decode(d); - let _i: SerializedDepNodeIndex = nodes.push(dep_node); + // Decode the header for this edge; the header packs together as many of the fixed-size + // fields as possible to limit the number of times we update decoder state. + let node_header = SerializedNodeHeader { bytes: d.read_array(), _marker: PhantomData }; + + let _i: SerializedDepNodeIndex = nodes.push(node_header.node()); debug_assert_eq!(_i.index(), _index); - let fingerprint: Fingerprint = Decodable::decode(d); - let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint); + let _i: SerializedDepNodeIndex = fingerprints.push(node_header.fingerprint()); debug_assert_eq!(_i.index(), _index); - // Deserialize edges -- sequence of DepNodeIndex - let len = d.read_usize(); - let start = edge_list_data.len().try_into().unwrap(); - for _ in 0..len { - let edge = Decodable::decode(d); - edge_list_data.push(edge); - } - let end = edge_list_data.len().try_into().unwrap(); - let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end)); + // If the length of this node's edge list is small, the length is stored in the header. + // If it is not, we fall back to another decoder call. + let num_edges = node_header.len().unwrap_or_else(|| d.read_usize()); + + // The edges index list uses the same varint strategy as rmeta tables; we select the + // number of byte elements per-array not per-element. This lets us read the whole edge + // list for a node with one decoder call and also use the on-disk format in memory. + let edges_len_bytes = node_header.bytes_per_index() * num_edges; + // The in-memory structure for the edges list stores the byte width of the edges on + // this node with the offset into the global edge data array. + let edges_header = node_header.edges_header(&edge_list_data); + + edge_list_data.extend(d.read_raw_bytes(edges_len_bytes)); + + let _i: SerializedDepNodeIndex = edge_list_indices.push(edges_header); debug_assert_eq!(_i.index(), _index); } + // When we access the edge list data, we do a fixed-size read from the edge list data then + // mask off the bytes that aren't for that edge index, so the last read may dangle off the + // end of the array. This padding ensure it doesn't. + edge_list_data.extend(&[0u8; DEP_NODE_PAD]); + let index: FxHashMap<_, _> = nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); @@ -140,11 +258,154 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> } } -#[derive(Debug, Encodable, Decodable)] -pub struct NodeInfo<K: DepKind> { +/// A packed representation of all the fixed-size fields in a `NodeInfo`. +/// +/// This stores in one byte array: +/// * The `Fingerprint` in the `NodeInfo` +/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo` +/// * The `DepKind`'s discriminant (a u16, but not all bits are used...) +/// * The byte width of the encoded edges for this node +/// * In whatever bits remain, the length of the edge list for this node, if it fits +struct SerializedNodeHeader<K> { + // 2 bytes for the DepNode + // 16 for Fingerprint in DepNode + // 16 for Fingerprint in NodeInfo + bytes: [u8; 34], + _marker: PhantomData<K>, +} + +// The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only +// to make the implementation of `SerializedNodeHeader` simpler. +struct Unpacked<K> { + len: Option<usize>, + bytes_per_index: usize, + kind: K, + hash: PackedFingerprint, + fingerprint: Fingerprint, +} + +// Bit fields, where +// M: bits used to store the length of a node's edge list +// N: bits used to store the byte width of elements of the edge list +// are +// 0..M length of the edge +// M..M+N bytes per index +// M+N..16 kind +impl<K: DepKind> SerializedNodeHeader<K> { + const TOTAL_BITS: usize = std::mem::size_of::<K>() * 8; + const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; + const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS; + const KIND_BITS: usize = Self::TOTAL_BITS - K::MAX.leading_zeros() as usize; + const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1; + + #[inline] + fn new(node_info: &NodeInfo<K>) -> Self { + debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS); + + let NodeInfo { node, fingerprint, edges } = node_info; + + let mut head = node.kind.to_u16(); + + let free_bytes = edges.max_index().leading_zeros() as usize / 8; + let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1); + head |= (bytes_per_index as u16) << Self::KIND_BITS; + + // Encode number of edges + 1 so that we can reserve 0 to indicate that the len doesn't fit + // in this bitfield. + if edges.len() <= Self::MAX_INLINE_LEN { + head |= (edges.len() as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS); + } + + let hash: Fingerprint = node.hash.into(); + + // Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong. + let mut bytes = [0u8; 34]; + bytes[..2].copy_from_slice(&head.to_le_bytes()); + bytes[2..18].copy_from_slice(&hash.to_le_bytes()); + bytes[18..].copy_from_slice(&fingerprint.to_le_bytes()); + + #[cfg(debug_assertions)] + { + let res = Self { bytes, _marker: PhantomData }; + assert_eq!(node_info.fingerprint, res.fingerprint()); + assert_eq!(node_info.node, res.node()); + if let Some(len) = res.len() { + assert_eq!(node_info.edges.len(), len); + } + } + Self { bytes, _marker: PhantomData } + } + + #[inline] + fn unpack(&self) -> Unpacked<K> { + let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap()); + let hash = self.bytes[2..18].try_into().unwrap(); + let fingerprint = self.bytes[18..].try_into().unwrap(); + + let kind = head & mask(Self::KIND_BITS) as u16; + let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16; + let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS); + + Unpacked { + len: len.checked_sub(1), + bytes_per_index: bytes_per_index as usize + 1, + kind: DepKind::from_u16(kind), + hash: Fingerprint::from_le_bytes(hash).into(), + fingerprint: Fingerprint::from_le_bytes(fingerprint), + } + } + + #[inline] + fn len(&self) -> Option<usize> { + self.unpack().len + } + + #[inline] + fn bytes_per_index(&self) -> usize { + self.unpack().bytes_per_index + } + + #[inline] + fn fingerprint(&self) -> Fingerprint { + self.unpack().fingerprint + } + + #[inline] + fn node(&self) -> DepNode<K> { + let Unpacked { kind, hash, .. } = self.unpack(); + DepNode { kind, hash } + } + + #[inline] + fn edges_header(&self, edge_list_data: &[u8]) -> EdgeHeader { + EdgeHeader { + repr: (edge_list_data.len() << DEP_NODE_WIDTH_BITS) | (self.bytes_per_index() - 1), + } + } +} + +#[derive(Debug)] +struct NodeInfo<K: DepKind> { node: DepNode<K>, fingerprint: Fingerprint, - edges: SmallVec<[DepNodeIndex; 8]>, + edges: EdgesVec, +} + +impl<K: DepKind> Encodable<FileEncoder> for NodeInfo<K> { + fn encode(&self, e: &mut FileEncoder) { + let header = SerializedNodeHeader::new(self); + e.emit_raw_bytes(&header.bytes); + + if header.len().is_none() { + e.emit_usize(self.edges.len()); + } + + let bytes_per_index = header.bytes_per_index(); + for node_index in self.edges.iter() { + let bytes = node_index.as_u32().to_le_bytes(); + e.emit_raw_bytes(&bytes[..bytes_per_index]); + } + } } struct Stat<K: DepKind> { @@ -303,7 +564,7 @@ impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> { profiler: &SelfProfilerRef, node: DepNode<K>, fingerprint: Fingerprint, - edges: SmallVec<[DepNodeIndex; 8]>, + edges: EdgesVec, ) -> DepNodeIndex { let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph"); let node = NodeInfo { node, fingerprint, edges }; diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index e673d5b8c6e..b2177be0e36 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -5,7 +5,7 @@ use crate::ich::StableHashingContext; use rustc_ast as ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_span::{BytePos, NormalizedPos, SourceFile}; +use rustc_span::SourceFile; use std::assert_matches::assert_matches; use smallvec::SmallVec; @@ -67,8 +67,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { src: _, ref src_hash, external_src: _, - start_pos, - end_pos: _, + start_pos: _, + source_len: _, lines: _, ref multibyte_chars, ref non_narrow_chars, @@ -79,62 +79,37 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { src_hash.hash_stable(hcx, hasher); - // We are always in `Lines` form by the time we reach here. - assert!(self.lines.borrow().is_lines()); - self.lines(|lines| { + { + // We are always in `Lines` form by the time we reach here. + assert!(self.lines.read().is_lines()); + let lines = self.lines(); // We only hash the relative position within this source_file lines.len().hash_stable(hcx, hasher); for &line in lines.iter() { - stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); + line.hash_stable(hcx, hasher); } - }); + } // We only hash the relative position within this source_file multibyte_chars.len().hash_stable(hcx, hasher); for &char_pos in multibyte_chars.iter() { - stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); + char_pos.hash_stable(hcx, hasher); } non_narrow_chars.len().hash_stable(hcx, hasher); for &char_pos in non_narrow_chars.iter() { - stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); + char_pos.hash_stable(hcx, hasher); } normalized_pos.len().hash_stable(hcx, hasher); for &char_pos in normalized_pos.iter() { - stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher); + char_pos.hash_stable(hcx, hasher); } cnum.hash_stable(hcx, hasher); } } -fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 { - pos.0 - source_file_start.0 -} - -fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) { - let rustc_span::MultiByteChar { pos, bytes } = mbc; - - (pos.0 - source_file_start.0, bytes as u32) -} - -fn stable_non_narrow_char( - swc: rustc_span::NonNarrowChar, - source_file_start: BytePos, -) -> (u32, u32) { - let pos = swc.pos(); - let width = swc.width(); - - (pos.0 - source_file_start.0, width as u32) -} - -fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) { - let NormalizedPos { pos, diff } = np; - - (pos.0 - source_file_start.0, diff) -} - impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 8c9e9cfad60..1944ac443ea 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -4,6 +4,7 @@ #![feature(min_specialization)] #![feature(extern_types)] #![feature(let_chains)] +#![feature(inline_const)] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index a96230fdc94..0240f012da0 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -2,7 +2,7 @@ use crate::dep_graph::DepNodeIndex; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::{self, Sharded}; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::OnceLock; use rustc_index::{Idx, IndexVec}; use std::fmt::Debug; use std::hash::Hash; @@ -55,7 +55,7 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { let key_hash = sharded::make_hash(key); - let lock = self.cache.get_shard_by_hash(key_hash).lock(); + let lock = self.cache.lock_shard_by_hash(key_hash); let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key); if let Some((_, value)) = result { Some(*value) } else { None } @@ -63,7 +63,7 @@ where #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.get_shard_by_value(&key).lock(); + let mut lock = self.cache.lock_shard_by_value(&key); // We may be overwriting another value. This is all right, since the dep-graph // will check that the fingerprint matches. lock.insert(key, (value, index)); @@ -87,12 +87,12 @@ impl<'tcx, V: 'tcx> CacheSelector<'tcx, V> for SingleCacheSelector { } pub struct SingleCache<V> { - cache: Lock<Option<(V, DepNodeIndex)>>, + cache: OnceLock<(V, DepNodeIndex)>, } impl<V> Default for SingleCache<V> { fn default() -> Self { - SingleCache { cache: Lock::new(None) } + SingleCache { cache: OnceLock::new() } } } @@ -105,16 +105,16 @@ where #[inline(always)] fn lookup(&self, _key: &()) -> Option<(V, DepNodeIndex)> { - *self.cache.lock() + self.cache.get().copied() } #[inline] fn complete(&self, _key: (), value: V, index: DepNodeIndex) { - *self.cache.lock() = Some((value, index)); + self.cache.set((value, index)).ok(); } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - if let Some(value) = self.cache.lock().as_ref() { + if let Some(value) = self.cache.get() { f(&(), &value.0, value.1) } } @@ -148,13 +148,13 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - let lock = self.cache.get_shard_by_hash(key.index() as u64).lock(); + let lock = self.cache.lock_shard_by_hash(key.index() as u64); if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None } } #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.get_shard_by_hash(key.index() as u64).lock(); + let mut lock = self.cache.lock_shard_by_hash(key.index() as u64); lock.insert(key, (value, index)); } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 9cba549a3b5..6c01dc3c00d 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -552,7 +552,9 @@ pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Regis // which in turn will wait on X causing a deadlock. We have a false dependency from // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here // only considers the true dependency and won't detect a cycle. - assert!(found_cycle); + if !found_cycle { + panic!("deadlock detected"); + } // FIXME: Ensure this won't cause a deadlock before we return for waiter in wakelist.into_iter() { diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 4fa168965a7..07db15e6d8b 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -158,7 +158,7 @@ where cache.complete(key, result, dep_node_index); let job = { - let mut lock = state.active.get_shard_by_value(&key).lock(); + let mut lock = state.active.lock_shard_by_value(&key); match lock.remove(&key).unwrap() { QueryResult::Started(job) => job, QueryResult::Poisoned => panic!(), @@ -180,7 +180,7 @@ where // Poison the query so jobs waiting on it panic. let state = self.state; let job = { - let mut shard = state.active.get_shard_by_value(&self.key).lock(); + let mut shard = state.active.lock_shard_by_value(&self.key); let job = match shard.remove(&self.key).unwrap() { QueryResult::Started(job) => job, QueryResult::Poisoned => panic!(), @@ -303,7 +303,7 @@ where Qcx: QueryContext, { let state = query.query_state(qcx); - let mut state_lock = state.active.get_shard_by_value(&key).lock(); + let mut state_lock = state.active.lock_shard_by_value(&key); // For the parallel compiler we need to check both the query cache and query state structures // while holding the state lock to ensure that 1) the query has not yet completed and 2) the diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index f98918cba88..33fde285524 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -58,6 +58,10 @@ resolve_cannot_determine_import_resolution = cannot determine resolution for the import .note = import resolution is stuck, try simplifying other imports +resolve_cannot_determine_macro_resolution = + cannot determine resolution for the {$kind} `{$path}` + .note = import resolution is stuck, try simplifying macro imports + resolve_cannot_find_ident_in_this_scope = cannot find {$expected} `{$ident}` in this scope diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d99fc07a7cd..e9edfb53b44 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2753,7 +2753,13 @@ fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> { for item in items { if let ItemKind::Use(..) = item.kind { if is_span_suitable_for_use_injection(item.span) { - return Some(item.span.shrink_to_lo()); + let mut lo = item.span.lo(); + for attr in &item.attrs { + if attr.span.eq_ctxt(item.span) { + lo = std::cmp::min(lo, attr.span.lo()); + } + } + return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e4b89c65853..85c9171e78a 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -655,6 +655,16 @@ pub(crate) struct CannotDetermineImportResolution { } #[derive(Diagnostic)] +#[diag(resolve_cannot_determine_macro_resolution)] +#[note] +pub(crate) struct CannotDetermineMacroResolution { + #[primary_span] + pub(crate) span: Span, + pub(crate) kind: &'static str, + pub(crate) path: String, +} + +#[derive(Diagnostic)] #[diag(resolve_cannot_be_reexported_private, code = "E0364")] pub(crate) struct CannotBeReexportedPrivate { #[primary_span] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fa04a594555..486d60eab21 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -313,7 +313,7 @@ enum LifetimeRibKind { /// Resolves elided lifetimes to `'static`, but gives a warning that this behavior /// is a bug and will be reverted soon. - AnonymousWarnToStatic(NodeId), + AnonymousWarn(NodeId), /// Signal we cannot find which should be the anonymous lifetime. ElisionFailure, @@ -1154,7 +1154,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } LifetimeRibKind::AnonymousCreateParameter { .. } | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarnToStatic(_) + | LifetimeRibKind::AnonymousWarn(_) | LifetimeRibKind::Elided(_) | LifetimeRibKind::ElisionFailure | LifetimeRibKind::ConcreteAnonConst(_) @@ -1522,7 +1522,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // lifetime would be illegal. LifetimeRibKind::Item | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarnToStatic(_) + | LifetimeRibKind::AnonymousWarn(_) | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), // An anonymous lifetime is legal here, and bound to the right // place, go ahead. @@ -1585,7 +1585,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { | LifetimeRibKind::Generics { .. } | LifetimeRibKind::ElisionFailure | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarnToStatic(_) => {} + | LifetimeRibKind::AnonymousWarn(_) => {} } } @@ -1625,8 +1625,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } - LifetimeRibKind::AnonymousWarnToStatic(node_id) => { - self.record_lifetime_res(lifetime.id, LifetimeRes::Static, elision_candidate); + LifetimeRibKind::AnonymousWarn(node_id) => { let msg = if elided { "`&` without an explicit lifetime name cannot be used here" } else { @@ -1642,7 +1641,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { span: lifetime.ident.span, }, ); - return; } LifetimeRibKind::AnonymousReportError => { let (msg, note) = if elided { @@ -1840,7 +1838,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // impl Foo for std::cell::Ref<u32> // note lack of '_ // async fn foo(_: std::cell::Ref<u32>) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } - | LifetimeRibKind::AnonymousWarnToStatic(_) => { + | LifetimeRibKind::AnonymousWarn(_) => { let sess = self.r.tcx.sess; let mut err = rustc_errors::struct_span_err!( sess, @@ -2936,33 +2934,30 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { kind: LifetimeBinderKind::ConstItem, }, |this| { - this.with_lifetime_rib( - LifetimeRibKind::AnonymousWarnToStatic(item.id), - |this| { - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); + this.with_lifetime_rib(LifetimeRibKind::AnonymousWarn(item.id), |this| { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); - this.visit_generics(generics); - this.visit_ty(ty); - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); - } - }, - ); + this.visit_generics(generics); + this.visit_ty(ty); + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_body(expr, None); + } + }); }, ); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b757f42eaa0..a4175de464c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -34,7 +34,7 @@ use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArg use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{Lrc, MappedReadGuard}; +use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; use rustc_errors::{ Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage, }; @@ -1544,7 +1544,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { )) } - fn cstore(&self) -> MappedReadGuard<'_, CStore> { + fn cstore(&self) -> FreezeReadGuard<'_, CStore> { CStore::from_tcx(self.tcx) } @@ -1599,7 +1599,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); // Make sure we don't mutate the cstore from here on. - self.tcx.untracked().cstore.leak(); + self.tcx.untracked().cstore.freeze(); } fn traits_in_scope( diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1199290a4d1..82060716575 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -2,7 +2,8 @@ //! interface provided by `Resolver` to macro expander. use crate::errors::{ - self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive, + self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope, + MacroExpectedFound, RemoveSurroundingDerive, }; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; @@ -719,13 +720,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // even if speculative `resolve_path` returned nothing previously, so we skip this // less informative error if the privacy error is reported elsewhere. if this.privacy_errors.is_empty() { - let msg = format!( - "cannot determine resolution for the {} `{}`", - kind.descr(), - Segment::names_to_string(path) - ); - let msg_note = "import resolution is stuck, try simplifying macro imports"; - this.tcx.sess.struct_span_err(span, msg).note(msg_note).emit(); + this.tcx.sess.emit_err(CannotDetermineMacroResolution { + span, + kind: kind.descr(), + path: Segment::names_to_string(path), + }); } } }; diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 0ffc537eee0..f1b7e8d9ae0 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -353,7 +353,7 @@ impl<'a> MemDecoder<'a> { } #[inline] - fn read_array<const N: usize>(&mut self) -> [u8; N] { + pub fn read_array<const N: usize>(&mut self) -> [u8; N] { self.read_raw_bytes(N).try_into().unwrap() } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f00472f181d..29de4c8856e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -381,6 +381,24 @@ pub enum DebugInfo { Full, } +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum DebugInfoCompression { + None, + Zlib, + Zstd, +} + +impl ToString for DebugInfoCompression { + fn to_string(&self) -> String { + match self { + DebugInfoCompression::None => "none", + DebugInfoCompression::Zlib => "zlib", + DebugInfoCompression::Zstd => "zstd", + } + .to_owned() + } +} + /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform /// uses DWARF for debug-information. @@ -1015,6 +1033,7 @@ impl Default for Options { crate_types: Vec::new(), optimize: OptLevel::No, debuginfo: DebugInfo::None, + debuginfo_compression: DebugInfoCompression::None, lint_opts: Vec::new(), lint_cap: None, describe_lints: false, @@ -1084,12 +1103,6 @@ impl Options { pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) } - - #[allow(rustc::bad_opt_access)] - pub fn incremental_relative_spans(&self) -> bool { - self.unstable_opts.incremental_relative_spans - || (self.unstable_features.is_nightly_build() && self.incremental.is_some()) - } } impl UnstableOptions { @@ -2160,12 +2173,6 @@ fn collect_print_requests( prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); - if out.is_some() && !unstable_opts.unstable_options { - handler.early_error( - "the `-Z unstable-options` flag must also be passed to \ - enable the path print option", - ); - } let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { Some((_, PrintKind::TargetSpec)) => { if unstable_opts.unstable_options { @@ -2283,6 +2290,13 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf if max_g > max_c { DebugInfo::Full } else { cg.debuginfo } } +fn select_debuginfo_compression( + _handler: &EarlyErrorHandler, + unstable_opts: &UnstableOptions, +) -> DebugInfoCompression { + unstable_opts.debuginfo_compression +} + pub(crate) fn parse_assert_incr_state( handler: &EarlyErrorHandler, opt_assertion: &Option<String>, @@ -2758,6 +2772,8 @@ pub fn build_session_options( // for more details. let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); let debuginfo = select_debuginfo(matches, &cg); + let debuginfo_compression: DebugInfoCompression = + select_debuginfo_compression(handler, &unstable_opts); let mut search_paths = vec![]; for s in &matches.opt_strs("L") { @@ -2834,6 +2850,7 @@ pub fn build_session_options( crate_types, optimize: opt_level, debuginfo, + debuginfo_compression, lint_opts, lint_cap, describe_lints, @@ -2959,6 +2976,7 @@ pub mod nightly_options { ) { let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); let really_allows_unstable_options = match_is_nightly_build(matches); + let mut nightly_options_on_stable = 0; for opt in flags.iter() { if opt.stability == OptionStability::Stable { @@ -2979,20 +2997,27 @@ pub mod nightly_options { } match opt.stability { OptionStability::Unstable => { + nightly_options_on_stable += 1; let msg = format!( "the option `{}` is only accepted on the nightly compiler", opt.name ); let _ = handler.early_error_no_abort(msg); - handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>"); - handler.early_help( - "consider switching to a nightly toolchain: `rustup default nightly`", - ); - handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>"); } OptionStability::Stable => {} } } + if nightly_options_on_stable > 0 { + handler + .early_help("consider switching to a nightly toolchain: `rustup default nightly`"); + handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>"); + handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>"); + handler.early_error(format!( + "{} nightly option{} were parsed", + nightly_options_on_stable, + if nightly_options_on_stable > 1 { "s" } else { "" } + )); + } } } @@ -3119,11 +3144,11 @@ impl PpMode { /// how the hash should be calculated when adding a new command-line argument. pub(crate) mod dep_tracking { use super::{ - BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType, - InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, - OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks, - SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, - TraitSolver, TrimmedDefPaths, + BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, + ErrorOutputType, InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, + LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, + Passes, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, + SymbolManglingVersion, TraitSolver, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -3201,6 +3226,7 @@ pub(crate) mod dep_tracking { OptLevel, LtoCli, DebugInfo, + DebugInfoCompression, UnstableFeatures, NativeLib, NativeLibKind, diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index c53a355b533..d816842b02b 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -7,7 +7,7 @@ use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; use rustc_data_structures::owned_slice::OwnedSlice; -use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock}; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -258,8 +258,8 @@ pub trait CrateStore: std::fmt::Debug { pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; pub struct Untracked { - pub cstore: RwLock<Box<CrateStoreDyn>>, + pub cstore: FreezeLock<Box<CrateStoreDyn>>, /// Reference span for definitions. pub source_span: AppendOnlyIndexVec<LocalDefId, Span>, - pub definitions: RwLock<Definitions>, + pub definitions: FreezeLock<Definitions>, } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 40099de707b..7c2068a157c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -139,6 +139,7 @@ top_level_options!( /// can influence whether overflow checks are done or not. debug_assertions: bool [TRACKED], debuginfo: DebugInfo [TRACKED], + debuginfo_compression: DebugInfoCompression [TRACKED], lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH], lint_cap: Option<lint::Level> [TRACKED_NO_CRATE_HASH], describe_lints: bool [UNTRACKED], @@ -376,6 +377,7 @@ mod desc { "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`"; + pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; @@ -782,6 +784,19 @@ mod parse { true } + pub(crate) fn parse_debuginfo_compression( + slot: &mut DebugInfoCompression, + v: Option<&str>, + ) -> bool { + match v { + Some("none") => *slot = DebugInfoCompression::None, + Some("zlib") => *slot = DebugInfoCompression::Zlib, + Some("zstd") => *slot = DebugInfoCompression::Zstd, + _ => return false, + }; + true + } + pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool { match v.and_then(LinkerFlavorCli::from_str) { Some(lf) => *slot = Some(lf), @@ -1424,6 +1439,8 @@ options! { "emit discriminators and other data necessary for AutoFDO"), debug_macros: bool = (false, parse_bool, [TRACKED], "emit line numbers debug info inside macros (default: no)"), + debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED], + "compress debug info sections (none, zlib, zstd, default: none)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], "deduplicate identical diagnostics (default: yes)"), dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], @@ -1524,9 +1541,6 @@ options! { incremental_info: bool = (false, parse_bool, [UNTRACKED], "print high-level information about incremental reuse (or the lack thereof) \ (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")] - incremental_relative_spans: bool = (false, parse_bool, [TRACKED], - "hash spans relative to their parent item for incr. comp. (default: no)"), incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], "verify incr. comp. hashes of green query instances (default: no)"), inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 86db2edab7b..9bff9017881 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -204,6 +204,12 @@ pub struct Session { /// The version of the rustc process, possibly including a commit hash and description. pub cfg_version: &'static str, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec<String>, } pub struct PerfStats { @@ -1325,6 +1331,7 @@ pub fn build_session( target_override: Option<Target>, cfg_version: &'static str, ice_file: Option<PathBuf>, + expanded_args: Vec<String>, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1467,6 +1474,7 @@ pub fn build_session( target_features: Default::default(), unstable_target_features: Default::default(), cfg_version, + expanded_args, }; validate_commandline_args_with_session_available(&sess); diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 5334a75dc06..73b8e060dd8 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -4,16 +4,17 @@ //! until stable MIR is complete. use std::fmt::Debug; -use std::ops::Index; -use std::string::ToString; +use std::ops::{ControlFlow, Index}; use crate::rustc_internal; +use crate::stable_mir::CompilerError; use crate::{ rustc_smir::Tables, stable_mir::{self, with}, }; use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; +use rustc_middle::mir::interpret::AllocId; use rustc_middle::ty::TyCtxt; use rustc_session::EarlyErrorHandler; pub use rustc_span::def_id::{CrateNum, DefId}; @@ -134,6 +135,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::ImplDef(self.create_def_id(did)) } + pub fn prov(&mut self, aid: AllocId) -> stable_mir::ty::Prov { + stable_mir::ty::Prov(self.create_alloc_id(aid)) + } + fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { // FIXME: this becomes inefficient when we have too many ids for (i, &d) in self.def_ids.iter().enumerate() { @@ -145,6 +150,16 @@ impl<'tcx> Tables<'tcx> { self.def_ids.push(did); stable_mir::DefId(id) } + + fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::AllocId { + // FIXME: this becomes inefficient when we have too many ids + if let Some(i) = self.alloc_ids.iter().position(|a| *a == aid) { + return stable_mir::AllocId(i); + }; + let id = self.def_ids.len(); + self.alloc_ids.push(aid); + stable_mir::AllocId(id) + } } pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { @@ -152,37 +167,68 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { } pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { - crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f); + crate::stable_mir::run(Tables { tcx, def_ids: vec![], alloc_ids: vec![], types: vec![] }, f); } /// A type that provides internal information but that can still be used for debug purpose. -pub type Opaque = impl Debug + ToString + Clone; +#[derive(Clone)] +pub struct Opaque(String); + +impl std::fmt::Display for Opaque { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::fmt::Debug for Opaque { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque { - format!("{value:?}") + Opaque(format!("{value:?}")) } -pub struct StableMir { +pub struct StableMir<B = (), C = ()> +where + B: Send, + C: Send, +{ args: Vec<String>, - callback: fn(TyCtxt<'_>), + callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>, + result: Option<ControlFlow<B, C>>, } -impl StableMir { +impl<B, C> StableMir<B, C> +where + B: Send, + C: Send, +{ /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>)) -> Self { - StableMir { args, callback } + pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self { + StableMir { args, callback, result: None } } /// Runs the compiler against given target and tests it with `test_function` - pub fn run(&mut self) { - rustc_driver::catch_fatal_errors(|| { - RunCompiler::new(&self.args.clone(), self).run().unwrap(); - }) - .unwrap(); + pub fn run(&mut self) -> Result<C, CompilerError<B>> { + let compiler_result = + rustc_driver::catch_fatal_errors(|| RunCompiler::new(&self.args.clone(), self).run()); + match (compiler_result, self.result.take()) { + (Ok(Ok(())), Some(ControlFlow::Continue(value))) => Ok(value), + (Ok(Ok(())), Some(ControlFlow::Break(value))) => Err(CompilerError::Interrupted(value)), + (Ok(Ok(_)), None) => Err(CompilerError::Skipped), + (Ok(Err(_)), _) => Err(CompilerError::CompilationFailed), + (Err(_), _) => Err(CompilerError::ICE), + } } } -impl Callbacks for StableMir { +impl<B, C> Callbacks for StableMir<B, C> +where + B: Send, + C: Send, +{ /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) fn after_analysis<'tcx>( @@ -192,9 +238,14 @@ impl Callbacks for StableMir { queries: &'tcx Queries<'tcx>, ) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { - rustc_internal::run(tcx, || (self.callback)(tcx)); - }); - // No need to keep going. - Compilation::Stop + rustc_internal::run(tcx, || { + self.result = Some((self.callback)(tcx)); + }); + if self.result.as_ref().is_some_and(|val| val.is_continue()) { + Compilation::Continue + } else { + Compilation::Stop + } + }) } } diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 33c75250adc..166c8bda9e1 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -1,7 +1,6 @@ use rustc_middle::mir::interpret::{alloc_range, AllocRange, ConstValue, Pointer}; use crate::{ - rustc_internal::opaque, rustc_smir::{Stable, Tables}, stable_mir::mir::Mutability, stable_mir::ty::{Allocation, ProvenanceMap}, @@ -113,7 +112,7 @@ pub(super) fn allocation_filter<'tcx>( .iter() .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end()) { - ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), opaque(prov))); + ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), tables.prov(*prov))); } Allocation { bytes: bytes, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d36835d37f5..7e533f990fd 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -1,5 +1,5 @@ //! Module that implements what will become the rustc side of Stable MIR. -//! + //! This module is responsible for building Stable MIR components from internal components. //! //! This module is not intended to be invoked directly by users. It will eventually @@ -10,12 +10,13 @@ use crate::rustc_internal::{self, opaque}; use crate::stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx}; use crate::stable_mir::ty::{FloatTy, GenericParamDef, IntTy, Movability, RigidTy, TyKind, UintTy}; -use crate::stable_mir::{self, Context}; +use crate::stable_mir::{self, CompilerError, Context}; use rustc_hir as hir; -use rustc_middle::mir::interpret::alloc_range; +use rustc_middle::mir::interpret::{alloc_range, AllocId}; use rustc_middle::mir::{self, ConstantKind}; use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_span::ErrorGuaranteed; use rustc_target::abi::FieldIdx; use tracing::debug; @@ -37,9 +38,18 @@ impl<'tcx> Context for Tables<'tcx> { }) } + fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String { + self.tcx.def_path_str(self[def_id]) + } + + fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Span { + self.tcx.def_span(self[def_id]).stable(self) + } + fn all_local_items(&mut self) -> stable_mir::CrateItems { self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect() } + fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> { Some(self.crate_item(self.tcx.entry_fn(())?.0)) } @@ -72,8 +82,8 @@ impl<'tcx> Context for Tables<'tcx> { impl_trait.stable(self) } - fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body { - let def_id = self[item.0]; + fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body { + let def_id = self[item]; let mir = self.tcx.optimized_mir(def_id); stable_mir::mir::Body { blocks: mir @@ -97,8 +107,13 @@ impl<'tcx> Context for Tables<'tcx> { } fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind { - let ty = self.types[ty.0]; - ty.stable(self) + self.types[ty.0].clone().stable(self) + } + + fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty { + let n = self.types.len(); + self.types.push(MaybeStable::Stable(kind)); + stable_mir::ty::Ty(n) } fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { @@ -122,19 +137,47 @@ impl<'tcx> Context for Tables<'tcx> { } } +#[derive(Clone)] +pub enum MaybeStable<S, R> { + Stable(S), + Rustc(R), +} + +impl<'tcx, S, R> MaybeStable<S, R> { + fn stable(self, tables: &mut Tables<'tcx>) -> S + where + R: Stable<'tcx, T = S>, + { + match self { + MaybeStable::Stable(s) => s, + MaybeStable::Rustc(r) => r.stable(tables), + } + } +} + +impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> { + fn eq(&self, other: &R) -> bool { + match self { + MaybeStable::Stable(_) => false, + MaybeStable::Rustc(r) => r == other, + } + } +} + pub struct Tables<'tcx> { pub tcx: TyCtxt<'tcx>, pub def_ids: Vec<DefId>, - pub types: Vec<Ty<'tcx>>, + pub alloc_ids: Vec<AllocId>, + pub types: Vec<MaybeStable<stable_mir::ty::TyKind, Ty<'tcx>>>, } impl<'tcx> Tables<'tcx> { fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty { - if let Some(id) = self.types.iter().position(|&t| t == ty) { + if let Some(id) = self.types.iter().position(|t| *t == ty) { return stable_mir::ty::Ty(id); } let id = self.types.len(); - self.types.push(ty); + self.types.push(MaybeStable::Rustc(ty)); stable_mir::ty::Ty(id) } } @@ -1090,14 +1133,13 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { tables, )) } - ty::ParamCt(param) => stable_mir::ty::ConstantKind::ParamCt(opaque(¶m)), + ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)), ty::ErrorCt(_) => unreachable!(), ty::InferCt(_) => unreachable!(), ty::BoundCt(_, _) => unimplemented!(), ty::PlaceholderCt(_) => unimplemented!(), ty::Unevaluated(uv) => { stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { - ty: tables.intern_ty(self.ty()), def: tables.const_def(uv.def), args: uv.args.stable(tables), promoted: None, @@ -1105,10 +1147,19 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { } ty::ExprCt(_) => unimplemented!(), }, + ty: tables.intern_ty(self.ty()), } } } +impl<'tcx> Stable<'tcx> for ty::ParamConst { + type T = stable_mir::ty::ParamConst; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::ParamConst; + ParamConst { index: self.index, name: self.name.to_string() } + } +} + impl<'tcx> Stable<'tcx> for ty::ParamTy { type T = stable_mir::ty::ParamTy; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { @@ -1177,22 +1228,27 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef { } impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { - type T = stable_mir::ty::ConstantKind; + type T = stable_mir::ty::Const; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { match *self { - ConstantKind::Ty(c) => c.stable(tables).literal, - ConstantKind::Unevaluated(unev_const, ty) => { - stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { - ty: tables.intern_ty(ty), - def: tables.const_def(unev_const.def), - args: unev_const.args.stable(tables), - promoted: unev_const.promoted.map(|u| u.as_u32()), - }) - } - ConstantKind::Val(val, ty) => { - stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(ty, val, tables)) - } + ConstantKind::Ty(c) => c.stable(tables), + ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const { + literal: stable_mir::ty::ConstantKind::Unevaluated( + stable_mir::ty::UnevaluatedConst { + def: tables.const_def(unev_const.def), + args: unev_const.args.stable(tables), + promoted: unev_const.promoted.map(|u| u.as_u32()), + }, + ), + ty: tables.intern_ty(ty), + }, + ConstantKind::Val(val, ty) => stable_mir::ty::Const { + literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( + ty, val, tables, + )), + ty: tables.intern_ty(ty), + }, } } } @@ -1446,3 +1502,9 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span { opaque(self) } } + +impl<T> From<ErrorGuaranteed> for CompilerError<T> { + fn from(_error: ErrorGuaranteed) -> Self { + CompilerError::CompilationFailed + } +} diff --git a/compiler/rustc_smir/src/stable_mir/fold.rs b/compiler/rustc_smir/src/stable_mir/fold.rs new file mode 100644 index 00000000000..831cfb40a15 --- /dev/null +++ b/compiler/rustc_smir/src/stable_mir/fold.rs @@ -0,0 +1,230 @@ +use std::ops::ControlFlow; + +use crate::rustc_internal::Opaque; + +use super::ty::{ + Allocation, Binder, Const, ConstDef, ConstantKind, ExistentialPredicate, FnSig, GenericArgKind, + GenericArgs, Promoted, RigidTy, TermKind, Ty, TyKind, UnevaluatedConst, +}; + +pub trait Folder: Sized { + type Break; + fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> { + ty.super_fold(self) + } + fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> { + c.super_fold(self) + } +} + +pub trait Foldable: Sized + Clone { + fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + self.super_fold(folder) + } + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self>; +} + +impl Foldable for Ty { + fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + folder.visit_ty(self) + } + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let mut kind = self.kind(); + match &mut kind { + super::ty::TyKind::RigidTy(ty) => *ty = ty.fold(folder)?, + super::ty::TyKind::Alias(_, alias) => alias.args = alias.args.fold(folder)?, + super::ty::TyKind::Param(_) => {} + super::ty::TyKind::Bound(_, _) => {} + } + ControlFlow::Continue(kind.into()) + } +} + +impl Foldable for Const { + fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + folder.fold_const(self) + } + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let mut this = self.clone(); + match &mut this.literal { + super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?, + super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?, + super::ty::ConstantKind::Param(_) => {} + } + this.ty = this.ty.fold(folder)?; + ControlFlow::Continue(this) + } +} + +impl Foldable for Opaque { + fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for Allocation { + fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for UnevaluatedConst { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let UnevaluatedConst { def, args, promoted } = self; + ControlFlow::Continue(UnevaluatedConst { + def: def.fold(folder)?, + args: args.fold(folder)?, + promoted: promoted.fold(folder)?, + }) + } +} + +impl Foldable for ConstDef { + fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(self.clone()) + } +} + +impl<T: Foldable> Foldable for Option<T> { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(match self { + Some(val) => Some(val.fold(folder)?), + None => None, + }) + } +} + +impl Foldable for Promoted { + fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(self.clone()) + } +} + +impl Foldable for GenericArgs { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(GenericArgs(self.0.fold(folder)?)) + } +} + +impl Foldable for GenericArgKind { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let mut this = self.clone(); + match &mut this { + GenericArgKind::Lifetime(lt) => *lt = lt.fold(folder)?, + GenericArgKind::Type(t) => *t = t.fold(folder)?, + GenericArgKind::Const(c) => *c = c.fold(folder)?, + } + ControlFlow::Continue(this) + } +} + +impl Foldable for RigidTy { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let mut this = self.clone(); + match &mut this { + RigidTy::Bool + | RigidTy::Char + | RigidTy::Int(_) + | RigidTy::Uint(_) + | RigidTy::Float(_) + | RigidTy::Never + | RigidTy::Foreign(_) + | RigidTy::Str => {} + RigidTy::Array(t, c) => { + *t = t.fold(folder)?; + *c = c.fold(folder)?; + } + RigidTy::Slice(inner) => *inner = inner.fold(folder)?, + RigidTy::RawPtr(ty, _) => *ty = ty.fold(folder)?, + RigidTy::Ref(_, ty, _) => *ty = ty.fold(folder)?, + RigidTy::FnDef(_, args) => *args = args.fold(folder)?, + RigidTy::FnPtr(sig) => *sig = sig.fold(folder)?, + RigidTy::Closure(_, args) => *args = args.fold(folder)?, + RigidTy::Generator(_, args, _) => *args = args.fold(folder)?, + RigidTy::Dynamic(pred, r, _) => { + *pred = pred.fold(folder)?; + *r = r.fold(folder)?; + } + RigidTy::Tuple(fields) => *fields = fields.fold(folder)?, + RigidTy::Adt(_, args) => *args = args.fold(folder)?, + } + ControlFlow::Continue(this) + } +} + +impl<T: Foldable> Foldable for Vec<T> { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let mut this = self.clone(); + for arg in &mut this { + *arg = arg.fold(folder)?; + } + ControlFlow::Continue(this) + } +} + +impl<T: Foldable> Foldable for Binder<T> { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(Self { + value: self.value.fold(folder)?, + bound_vars: self.bound_vars.clone(), + }) + } +} + +impl Foldable for ExistentialPredicate { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + let mut this = self.clone(); + match &mut this { + ExistentialPredicate::Trait(tr) => tr.generic_args = tr.generic_args.fold(folder)?, + ExistentialPredicate::Projection(p) => { + p.term = p.term.fold(folder)?; + p.generic_args = p.generic_args.fold(folder)?; + } + ExistentialPredicate::AutoTrait(_) => {} + } + ControlFlow::Continue(this) + } +} + +impl Foldable for TermKind { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(match self { + TermKind::Type(t) => TermKind::Type(t.fold(folder)?), + TermKind::Const(c) => TermKind::Const(c.fold(folder)?), + }) + } +} + +impl Foldable for FnSig { + fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { + ControlFlow::Continue(Self { + inputs_and_output: self.inputs_and_output.fold(folder)?, + c_variadic: self.c_variadic, + unsafety: self.unsafety, + abi: self.abi.clone(), + }) + } +} + +pub enum Never {} + +/// In order to instantiate a `Foldable`'s generic parameters with specific arguments, +/// `GenericArgs` can be used as a `Folder` that replaces all mentions of generic params +/// with the entries in its list. +impl Folder for GenericArgs { + type Break = Never; + + fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> { + ControlFlow::Continue(match ty.kind() { + TyKind::Param(p) => self[p], + _ => *ty, + }) + } + + fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> { + ControlFlow::Continue(match &c.literal { + ConstantKind::Param(p) => self[p.clone()].clone(), + _ => c.clone(), + }) + } +} diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 72f719c2a5e..449ca4b8145 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -1,6 +1,6 @@ use crate::rustc_internal::Opaque; use crate::stable_mir::ty::{ - AdtDef, ClosureDef, Const, ConstantKind, GeneratorDef, GenericArgs, Movability, Region, + AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region, }; use crate::stable_mir::{self, ty::Ty, Span}; @@ -352,7 +352,7 @@ type UserTypeAnnotationIndex = usize; pub struct Constant { pub span: Span, pub user_ty: Option<UserTypeAnnotationIndex>, - pub literal: ConstantKind, + pub literal: Const, } #[derive(Clone, Debug)] @@ -391,7 +391,7 @@ pub enum Mutability { Mut, } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Safety { Unsafe, Normal, diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index 1b834628175..508e3aa1291 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -12,14 +12,18 @@ //! If you need an internal construct, consider using `rustc_internal` or `rustc_smir`. use std::cell::Cell; +use std::fmt; +use std::fmt::Debug; use self::ty::{ GenericPredicates, Generics, ImplDef, ImplTrait, Span, TraitDecl, TraitDef, Ty, TyKind, }; use crate::rustc_smir::Tables; +pub mod fold; pub mod mir; pub mod ty; +pub mod visitor; /// Use String for now but we should replace it. pub type Symbol = String; @@ -28,9 +32,22 @@ pub type Symbol = String; pub type CrateNum = usize; /// A unique identification number for each item accessible for the current compilation unit. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct DefId(pub(crate) usize); +impl Debug for DefId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DefId:") + .field("id", &self.0) + .field("name", &with(|cx| cx.name_of_def_id(*self))) + .finish() + } +} + +/// A unique identification number for each provenance +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct AllocId(pub(crate) usize); + /// A list of crate items. pub type CrateItems = Vec<CrateItem>; @@ -40,6 +57,20 @@ pub type TraitDecls = Vec<TraitDef>; /// A list of impl trait decls. pub type ImplTraitDecls = Vec<ImplDef>; +/// An error type used to represent an error that has already been reported by the compiler. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CompilerError<T> { + /// Internal compiler error (I.e.: Compiler crashed). + ICE, + /// Compilation failed. + CompilationFailed, + /// Compilation was interrupted. + Interrupted(T), + /// Compilation skipped. This happens when users invoke rustc to retrieve information such as + /// --version. + Skipped, +} + /// Holds information about a crate. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Crate { @@ -56,7 +87,11 @@ pub struct CrateItem(pub(crate) DefId); impl CrateItem { pub fn body(&self) -> mir::Body { - with(|cx| cx.mir_body(self)) + with(|cx| cx.mir_body(self.0)) + } + + pub fn span(&self) -> ty::Span { + with(|cx| cx.span_of_an_item(self.0)) } } @@ -107,7 +142,7 @@ pub trait Context { fn entry_fn(&mut self) -> Option<CrateItem>; /// Retrieve all items of the local crate that have a MIR associated with them. fn all_local_items(&mut self) -> CrateItems; - fn mir_body(&mut self, item: &CrateItem) -> mir::Body; + fn mir_body(&mut self, item: DefId) -> mir::Body; fn all_trait_decls(&mut self) -> TraitDecls; fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl; fn all_trait_impls(&mut self) -> ImplTraitDecls; @@ -122,9 +157,18 @@ pub trait Context { /// Find a crate with the given name. fn find_crate(&self, name: &str) -> Option<Crate>; + /// Prints the name of given `DefId` + fn name_of_def_id(&self, def_id: DefId) -> String; + + /// `Span` of an item + fn span_of_an_item(&mut self, def_id: DefId) -> Span; + /// Obtain the representation of a type. fn ty_kind(&mut self, ty: Ty) -> TyKind; + /// Create a new `Ty` from scratch without information from rustc. + fn mk_ty(&mut self, kind: TyKind) -> Ty; + /// HACK: Until we have fully stable consumers, we need an escape hatch /// to get `DefId`s out of `CrateItem`s. fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>)); diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index d49f3243777..54cba1263b7 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1,18 +1,36 @@ -use super::{mir::Mutability, mir::Safety, with, DefId}; +use super::{ + mir::Safety, + mir::{Body, Mutability}, + with, AllocId, DefId, +}; use crate::rustc_internal::Opaque; +use std::fmt::{self, Debug, Formatter}; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct Ty(pub usize); +impl Debug for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Ty").field("id", &self.0).field("kind", &self.kind()).finish() + } +} + impl Ty { pub fn kind(&self) -> TyKind { with(|context| context.ty_kind(*self)) } } +impl From<TyKind> for Ty { + fn from(value: TyKind) -> Self { + with(|context| context.mk_ty(value)) + } +} + #[derive(Debug, Clone)] pub struct Const { pub literal: ConstantKind, + pub ty: Ty, } type Ident = Opaque; @@ -88,6 +106,12 @@ pub struct ForeignDef(pub(crate) DefId); #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct FnDef(pub(crate) DefId); +impl FnDef { + pub fn body(&self) -> Body { + with(|ctx| ctx.mir_body(self.0)) + } +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct ClosureDef(pub(crate) DefId); @@ -121,6 +145,22 @@ pub struct ImplDef(pub(crate) DefId); #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec<GenericArgKind>); +impl std::ops::Index<ParamTy> for GenericArgs { + type Output = Ty; + + fn index(&self, index: ParamTy) -> &Self::Output { + self.0[index.index as usize].expect_ty() + } +} + +impl std::ops::Index<ParamConst> for GenericArgs { + type Output = Const; + + fn index(&self, index: ParamConst) -> &Self::Output { + self.0[index.index as usize].expect_const() + } +} + #[derive(Clone, Debug)] pub enum GenericArgKind { Lifetime(Region), @@ -128,6 +168,28 @@ pub enum GenericArgKind { Const(Const), } +impl GenericArgKind { + /// Panic if this generic argument is not a type, otherwise + /// return the type. + #[track_caller] + pub fn expect_ty(&self) -> &Ty { + match self { + GenericArgKind::Type(ty) => ty, + _ => panic!("{self:?}"), + } + } + + /// Panic if this generic argument is not a const, otherwise + /// return the const. + #[track_caller] + pub fn expect_const(&self) -> &Const { + match self { + GenericArgKind::Const(c) => c, + _ => panic!("{self:?}"), + } + } +} + #[derive(Clone, Debug)] pub enum TermKind { Type(Ty), @@ -260,7 +322,9 @@ pub struct BoundTy { pub type Bytes = Vec<Option<u8>>; pub type Size = usize; -pub type Prov = Opaque; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Prov(pub(crate) AllocId); pub type Align = u64; pub type Promoted = u32; pub type InitMaskMaterialized = Vec<u64>; @@ -285,12 +349,17 @@ pub struct Allocation { pub enum ConstantKind { Allocated(Allocation), Unevaluated(UnevaluatedConst), - ParamCt(Opaque), + Param(ParamConst), +} + +#[derive(Clone, Debug)] +pub struct ParamConst { + pub index: u32, + pub name: String, } #[derive(Clone, Debug)] pub struct UnevaluatedConst { - pub ty: Ty, pub def: ConstDef, pub args: GenericArgs, pub promoted: Option<Promoted>, diff --git a/compiler/rustc_smir/src/stable_mir/visitor.rs b/compiler/rustc_smir/src/stable_mir/visitor.rs new file mode 100644 index 00000000000..c86063d2ed6 --- /dev/null +++ b/compiler/rustc_smir/src/stable_mir/visitor.rs @@ -0,0 +1,187 @@ +use std::ops::ControlFlow; + +use crate::rustc_internal::Opaque; + +use super::ty::{ + Allocation, Binder, Const, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, + Promoted, RigidTy, TermKind, Ty, UnevaluatedConst, +}; + +pub trait Visitor: Sized { + type Break; + fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break> { + ty.super_visit(self) + } + fn visit_const(&mut self, c: &Const) -> ControlFlow<Self::Break> { + c.super_visit(self) + } +} + +pub trait Visitable { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.super_visit(visitor) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break>; +} + +impl Visitable for Ty { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + visitor.visit_ty(self) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self.kind() { + super::ty::TyKind::RigidTy(ty) => ty.visit(visitor)?, + super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor)?, + super::ty::TyKind::Param(_) => {} + super::ty::TyKind::Bound(_, _) => {} + } + ControlFlow::Continue(()) + } +} + +impl Visitable for Const { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + visitor.visit_const(self) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match &self.literal { + super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, + super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, + super::ty::ConstantKind::Param(_) => {} + } + self.ty.visit(visitor) + } +} + +impl Visitable for Opaque { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for Allocation { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for UnevaluatedConst { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + let UnevaluatedConst { def, args, promoted } = self; + def.visit(visitor)?; + args.visit(visitor)?; + promoted.visit(visitor) + } +} + +impl Visitable for ConstDef { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl<T: Visitable> Visitable for Option<T> { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + Some(val) => val.visit(visitor), + None => ControlFlow::Continue(()), + } + } +} + +impl Visitable for Promoted { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for GenericArgs { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.0.visit(visitor) + } +} + +impl Visitable for GenericArgKind { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + GenericArgKind::Lifetime(lt) => lt.visit(visitor), + GenericArgKind::Type(t) => t.visit(visitor), + GenericArgKind::Const(c) => c.visit(visitor), + } + } +} + +impl Visitable for RigidTy { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + RigidTy::Bool + | RigidTy::Char + | RigidTy::Int(_) + | RigidTy::Uint(_) + | RigidTy::Float(_) + | RigidTy::Never + | RigidTy::Foreign(_) + | RigidTy::Str => ControlFlow::Continue(()), + RigidTy::Array(t, c) => { + t.visit(visitor)?; + c.visit(visitor) + } + RigidTy::Slice(inner) => inner.visit(visitor), + RigidTy::RawPtr(ty, _) => ty.visit(visitor), + RigidTy::Ref(_, ty, _) => ty.visit(visitor), + RigidTy::FnDef(_, args) => args.visit(visitor), + RigidTy::FnPtr(sig) => sig.visit(visitor), + RigidTy::Closure(_, args) => args.visit(visitor), + RigidTy::Generator(_, args, _) => args.visit(visitor), + RigidTy::Dynamic(pred, r, _) => { + pred.visit(visitor)?; + r.visit(visitor) + } + RigidTy::Tuple(fields) => fields.visit(visitor), + RigidTy::Adt(_, args) => args.visit(visitor), + } + } +} + +impl<T: Visitable> Visitable for Vec<T> { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + for arg in self { + arg.visit(visitor)?; + } + ControlFlow::Continue(()) + } +} + +impl<T: Visitable> Visitable for Binder<T> { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.value.visit(visitor) + } +} + +impl Visitable for ExistentialPredicate { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + ExistentialPredicate::Trait(tr) => tr.generic_args.visit(visitor), + ExistentialPredicate::Projection(p) => { + p.term.visit(visitor)?; + p.generic_args.visit(visitor) + } + ExistentialPredicate::AutoTrait(_) => ControlFlow::Continue(()), + } + } +} + +impl Visitable for TermKind { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + TermKind::Type(t) => t.visit(visitor), + TermKind::Const(c) => c.visit(visitor), + } + } +} + +impl Visitable for FnSig { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.inputs_and_output.visit(visitor) + } +} diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 26cd54210d0..450d5455ff9 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -11,26 +11,19 @@ mod tests; /// is detected at runtime. pub fn analyze_source_file( src: &str, - source_file_start_pos: BytePos, -) -> (Vec<BytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) { - let mut lines = vec![source_file_start_pos]; +) -> (Vec<RelativeBytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) { + let mut lines = vec![RelativeBytePos::from_u32(0)]; let mut multi_byte_chars = vec![]; let mut non_narrow_chars = vec![]; // Calls the right implementation, depending on hardware support available. - analyze_source_file_dispatch( - src, - source_file_start_pos, - &mut lines, - &mut multi_byte_chars, - &mut non_narrow_chars, - ); + analyze_source_file_dispatch(src, &mut lines, &mut multi_byte_chars, &mut non_narrow_chars); // The code above optimistically registers a new line *after* each \n // it encounters. If that point is already outside the source_file, remove // it again. if let Some(&last_line_start) = lines.last() { - let source_file_end = source_file_start_pos + BytePos::from_usize(src.len()); + let source_file_end = RelativeBytePos::from_usize(src.len()); assert!(source_file_end >= last_line_start); if last_line_start == source_file_end { lines.pop(); @@ -43,14 +36,12 @@ pub fn analyze_source_file( cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { fn analyze_source_file_dispatch(src: &str, - source_file_start_pos: BytePos, - lines: &mut Vec<BytePos>, + lines: &mut Vec<RelativeBytePos>, multi_byte_chars: &mut Vec<MultiByteChar>, non_narrow_chars: &mut Vec<NonNarrowChar>) { if is_x86_feature_detected!("sse2") { unsafe { analyze_source_file_sse2(src, - source_file_start_pos, lines, multi_byte_chars, non_narrow_chars); @@ -58,7 +49,7 @@ cfg_if::cfg_if! { } else { analyze_source_file_generic(src, src.len(), - source_file_start_pos, + RelativeBytePos::from_u32(0), lines, multi_byte_chars, non_narrow_chars); @@ -72,8 +63,7 @@ cfg_if::cfg_if! { /// SSE2 intrinsics to quickly find all newlines. #[target_feature(enable = "sse2")] unsafe fn analyze_source_file_sse2(src: &str, - output_offset: BytePos, - lines: &mut Vec<BytePos>, + lines: &mut Vec<RelativeBytePos>, multi_byte_chars: &mut Vec<MultiByteChar>, non_narrow_chars: &mut Vec<NonNarrowChar>) { #[cfg(target_arch = "x86")] @@ -129,8 +119,7 @@ cfg_if::cfg_if! { if control_char_mask == newlines_mask { // All control characters are newlines, record them let mut newlines_mask = 0xFFFF0000 | newlines_mask as u32; - let output_offset = output_offset + - BytePos::from_usize(chunk_index * CHUNK_SIZE + 1); + let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); loop { let index = newlines_mask.trailing_zeros(); @@ -140,7 +129,7 @@ cfg_if::cfg_if! { break } - lines.push(BytePos(index) + output_offset); + lines.push(RelativeBytePos(index) + output_offset); // Clear the bit, so we can find the next one. newlines_mask &= (!1) << index; @@ -165,7 +154,7 @@ cfg_if::cfg_if! { intra_chunk_offset = analyze_source_file_generic( &src[scan_start .. ], CHUNK_SIZE - intra_chunk_offset, - BytePos::from_usize(scan_start) + output_offset, + RelativeBytePos::from_usize(scan_start), lines, multi_byte_chars, non_narrow_chars @@ -177,7 +166,7 @@ cfg_if::cfg_if! { if tail_start < src.len() { analyze_source_file_generic(&src[tail_start ..], src.len() - tail_start, - output_offset + BytePos::from_usize(tail_start), + RelativeBytePos::from_usize(tail_start), lines, multi_byte_chars, non_narrow_chars); @@ -187,13 +176,12 @@ cfg_if::cfg_if! { // The target (or compiler version) does not support SSE2 ... fn analyze_source_file_dispatch(src: &str, - source_file_start_pos: BytePos, - lines: &mut Vec<BytePos>, + lines: &mut Vec<RelativeBytePos>, multi_byte_chars: &mut Vec<MultiByteChar>, non_narrow_chars: &mut Vec<NonNarrowChar>) { analyze_source_file_generic(src, src.len(), - source_file_start_pos, + RelativeBytePos::from_u32(0), lines, multi_byte_chars, non_narrow_chars); @@ -207,8 +195,8 @@ cfg_if::cfg_if! { fn analyze_source_file_generic( src: &str, scan_len: usize, - output_offset: BytePos, - lines: &mut Vec<BytePos>, + output_offset: RelativeBytePos, + lines: &mut Vec<RelativeBytePos>, multi_byte_chars: &mut Vec<MultiByteChar>, non_narrow_chars: &mut Vec<NonNarrowChar>, ) -> usize { @@ -230,11 +218,11 @@ fn analyze_source_file_generic( // This is an ASCII control character, it could be one of the cases // that are interesting to us. - let pos = BytePos::from_usize(i) + output_offset; + let pos = RelativeBytePos::from_usize(i) + output_offset; match byte { b'\n' => { - lines.push(pos + BytePos(1)); + lines.push(pos + RelativeBytePos(1)); } b'\t' => { non_narrow_chars.push(NonNarrowChar::Tab(pos)); @@ -250,7 +238,7 @@ fn analyze_source_file_generic( let c = src[i..].chars().next().unwrap(); char_len = c.len_utf8(); - let pos = BytePos::from_usize(i) + output_offset; + let pos = RelativeBytePos::from_usize(i) + output_offset; if char_len > 1 { assert!((2..=4).contains(&char_len)); diff --git a/compiler/rustc_span/src/analyze_source_file/tests.rs b/compiler/rustc_span/src/analyze_source_file/tests.rs index 66aefc9a787..0c77d080c17 100644 --- a/compiler/rustc_span/src/analyze_source_file/tests.rs +++ b/compiler/rustc_span/src/analyze_source_file/tests.rs @@ -3,29 +3,28 @@ use super::*; macro_rules! test { (case: $test_name:ident, text: $text:expr, - source_file_start_pos: $source_file_start_pos:expr, lines: $lines:expr, multi_byte_chars: $multi_byte_chars:expr, non_narrow_chars: $non_narrow_chars:expr,) => { #[test] fn $test_name() { - let (lines, multi_byte_chars, non_narrow_chars) = - analyze_source_file($text, BytePos($source_file_start_pos)); + let (lines, multi_byte_chars, non_narrow_chars) = analyze_source_file($text); - let expected_lines: Vec<BytePos> = $lines.into_iter().map(BytePos).collect(); + let expected_lines: Vec<RelativeBytePos> = + $lines.into_iter().map(RelativeBytePos).collect(); assert_eq!(lines, expected_lines); let expected_mbcs: Vec<MultiByteChar> = $multi_byte_chars .into_iter() - .map(|(pos, bytes)| MultiByteChar { pos: BytePos(pos), bytes }) + .map(|(pos, bytes)| MultiByteChar { pos: RelativeBytePos(pos), bytes }) .collect(); assert_eq!(multi_byte_chars, expected_mbcs); let expected_nncs: Vec<NonNarrowChar> = $non_narrow_chars .into_iter() - .map(|(pos, width)| NonNarrowChar::new(BytePos(pos), width)) + .map(|(pos, width)| NonNarrowChar::new(RelativeBytePos(pos), width)) .collect(); assert_eq!(non_narrow_chars, expected_nncs); @@ -36,7 +35,6 @@ macro_rules! test { test!( case: empty_text, text: "", - source_file_start_pos: 0, lines: vec![], multi_byte_chars: vec![], non_narrow_chars: vec![], @@ -45,7 +43,6 @@ test!( test!( case: newlines_short, text: "a\nc", - source_file_start_pos: 0, lines: vec![0, 2], multi_byte_chars: vec![], non_narrow_chars: vec![], @@ -54,7 +51,6 @@ test!( test!( case: newlines_long, text: "012345678\nabcdef012345678\na", - source_file_start_pos: 0, lines: vec![0, 10, 26], multi_byte_chars: vec![], non_narrow_chars: vec![], @@ -63,7 +59,6 @@ test!( test!( case: newline_and_multi_byte_char_in_same_chunk, text: "01234β789\nbcdef0123456789abcdef", - source_file_start_pos: 0, lines: vec![0, 11], multi_byte_chars: vec![(5, 2)], non_narrow_chars: vec![], @@ -72,7 +67,6 @@ test!( test!( case: newline_and_control_char_in_same_chunk, text: "01234\u{07}6789\nbcdef0123456789abcdef", - source_file_start_pos: 0, lines: vec![0, 11], multi_byte_chars: vec![], non_narrow_chars: vec![(5, 0)], @@ -81,7 +75,6 @@ test!( test!( case: multi_byte_char_short, text: "aβc", - source_file_start_pos: 0, lines: vec![0], multi_byte_chars: vec![(1, 2)], non_narrow_chars: vec![], @@ -90,7 +83,6 @@ test!( test!( case: multi_byte_char_long, text: "0123456789abcΔf012345β", - source_file_start_pos: 0, lines: vec![0], multi_byte_chars: vec![(13, 2), (22, 2)], non_narrow_chars: vec![], @@ -99,7 +91,6 @@ test!( test!( case: multi_byte_char_across_chunk_boundary, text: "0123456789abcdeΔ123456789abcdef01234", - source_file_start_pos: 0, lines: vec![0], multi_byte_chars: vec![(15, 2)], non_narrow_chars: vec![], @@ -108,7 +99,6 @@ test!( test!( case: multi_byte_char_across_chunk_boundary_tail, text: "0123456789abcdeΔ....", - source_file_start_pos: 0, lines: vec![0], multi_byte_chars: vec![(15, 2)], non_narrow_chars: vec![], @@ -117,7 +107,6 @@ test!( test!( case: non_narrow_short, text: "0\t2", - source_file_start_pos: 0, lines: vec![0], multi_byte_chars: vec![], non_narrow_chars: vec![(1, 4)], @@ -126,7 +115,6 @@ test!( test!( case: non_narrow_long, text: "01\t3456789abcdef01234567\u{07}9", - source_file_start_pos: 0, lines: vec![0], multi_byte_chars: vec![], non_narrow_chars: vec![(2, 4), (24, 0)], @@ -135,8 +123,7 @@ test!( test!( case: output_offset_all, text: "01\t345\n789abcΔf01234567\u{07}9\nbcΔf", - source_file_start_pos: 1000, - lines: vec![0 + 1000, 7 + 1000, 27 + 1000], - multi_byte_chars: vec![(13 + 1000, 2), (29 + 1000, 2)], - non_narrow_chars: vec![(2 + 1000, 4), (24 + 1000, 0)], + lines: vec![0, 7, 27], + multi_byte_chars: vec![(13, 2), (29, 2)], + non_narrow_chars: vec![(2, 4), (24, 0)], ); diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index 886112769a9..fbfc5c22fcb 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -1,5 +1,5 @@ use crate::source_map::SourceMap; -use crate::{BytePos, SourceFile, SpanData}; +use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData}; use rustc_data_structures::sync::Lrc; use std::ops::Range; @@ -37,6 +37,7 @@ impl CacheEntry { self.file_index = file_idx; } + let pos = self.file.relative_position(pos); let line_index = self.file.lookup_line(pos).unwrap(); let line_bounds = self.file.line_bounds(line_index); self.line_number = line_index + 1; @@ -79,7 +80,7 @@ impl<'sm> CachingSourceMapView<'sm> { pub fn byte_pos_to_line_and_col( &mut self, pos: BytePos, - ) -> Option<(Lrc<SourceFile>, usize, BytePos)> { + ) -> Option<(Lrc<SourceFile>, usize, RelativeBytePos)> { self.time_stamp += 1; // Check if the position is in one of the cached lines @@ -88,11 +89,8 @@ impl<'sm> CachingSourceMapView<'sm> { let cache_entry = &mut self.line_cache[cache_idx as usize]; cache_entry.touch(self.time_stamp); - return Some(( - cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line.start, - )); + let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32()); + return Some((cache_entry.file.clone(), cache_entry.line_number, col)); } // No cache hit ... @@ -108,7 +106,8 @@ impl<'sm> CachingSourceMapView<'sm> { let cache_entry = &mut self.line_cache[oldest]; cache_entry.update(new_file_and_idx, pos, self.time_stamp); - Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start)) + let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32()); + Some((cache_entry.file.clone(), cache_entry.line_number, col)) } pub fn span_data_to_lines_and_cols( diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 62fe49fe2a2..68724c48037 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -33,7 +33,7 @@ extern crate rustc_macros; #[macro_use] extern crate tracing; -use rustc_data_structures::AtomicRef; +use rustc_data_structures::{cold_path, AtomicRef}; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -64,7 +64,7 @@ pub mod fatal_error; pub mod profiling; use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher}; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc}; use std::borrow::Cow; use std::cmp::{self, Ordering}; @@ -510,10 +510,6 @@ impl SpanData { pub fn is_dummy(self) -> bool { self.lo.0 == 0 && self.hi.0 == 0 } - #[inline] - pub fn is_visible(self, sm: &SourceMap) -> bool { - !self.is_dummy() && sm.is_span_accessible(self.span()) - } /// Returns `true` if `self` fully encloses `other`. pub fn contains(self, other: Self) -> bool { self.lo <= other.lo && other.hi <= self.hi @@ -573,15 +569,9 @@ impl Span { self.data().with_parent(ctxt) } - /// Returns `true` if this is a dummy span with any hygienic context. - #[inline] - pub fn is_dummy(self) -> bool { - self.data_untracked().is_dummy() - } - #[inline] pub fn is_visible(self, sm: &SourceMap) -> bool { - self.data_untracked().is_visible(sm) + !self.is_dummy() && sm.is_span_accessible(self) } /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. @@ -1107,27 +1097,27 @@ impl fmt::Debug for SpanData { } /// Identifies an offset of a multi-byte character in a `SourceFile`. -#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)] +#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)] pub struct MultiByteChar { - /// The absolute offset of the character in the `SourceMap`. - pub pos: BytePos, + /// The relative offset of the character in the `SourceFile`. + pub pos: RelativeBytePos, /// The number of bytes, `>= 2`. pub bytes: u8, } /// Identifies an offset of a non-narrow character in a `SourceFile`. -#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)] +#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)] pub enum NonNarrowChar { /// Represents a zero-width character. - ZeroWidth(BytePos), + ZeroWidth(RelativeBytePos), /// Represents a wide (full-width) character. - Wide(BytePos), + Wide(RelativeBytePos), /// Represents a tab character, represented visually with a width of 4 characters. - Tab(BytePos), + Tab(RelativeBytePos), } impl NonNarrowChar { - fn new(pos: BytePos, width: usize) -> Self { + fn new(pos: RelativeBytePos, width: usize) -> Self { match width { 0 => NonNarrowChar::ZeroWidth(pos), 2 => NonNarrowChar::Wide(pos), @@ -1136,8 +1126,8 @@ impl NonNarrowChar { } } - /// Returns the absolute offset of the character in the `SourceMap`. - pub fn pos(&self) -> BytePos { + /// Returns the relative offset of the character in the `SourceFile`. + pub fn pos(&self) -> RelativeBytePos { match *self { NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p, } @@ -1153,10 +1143,10 @@ impl NonNarrowChar { } } -impl Add<BytePos> for NonNarrowChar { +impl Add<RelativeBytePos> for NonNarrowChar { type Output = Self; - fn add(self, rhs: BytePos) -> Self { + fn add(self, rhs: RelativeBytePos) -> Self { match self { NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs), NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs), @@ -1165,10 +1155,10 @@ impl Add<BytePos> for NonNarrowChar { } } -impl Sub<BytePos> for NonNarrowChar { +impl Sub<RelativeBytePos> for NonNarrowChar { type Output = Self; - fn sub(self, rhs: BytePos) -> Self { + fn sub(self, rhs: RelativeBytePos) -> Self { match self { NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs), NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs), @@ -1178,10 +1168,10 @@ impl Sub<BytePos> for NonNarrowChar { } /// Identifies an offset of a character that was normalized away from `SourceFile`. -#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)] +#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)] pub struct NormalizedPos { - /// The absolute offset of the character in the `SourceMap`. - pub pos: BytePos, + /// The relative offset of the character in the `SourceFile`. + pub pos: RelativeBytePos, /// The difference between original and normalized string at position. pub diff: u32, } @@ -1206,7 +1196,6 @@ pub enum ExternalSourceKind { AbsentOk, /// A failed attempt has been made to load the external source. AbsentErr, - Unneeded, } impl ExternalSource { @@ -1293,7 +1282,7 @@ impl SourceFileHash { #[derive(Clone)] pub enum SourceFileLines { /// The source file lines, in decoded (random-access) form. - Lines(Vec<BytePos>), + Lines(Vec<RelativeBytePos>), /// The source file lines, in undecoded difference list form. Diffs(SourceFileDiffs), @@ -1314,11 +1303,6 @@ impl SourceFileLines { /// small crates where very little of `std`'s metadata is used. #[derive(Clone)] pub struct SourceFileDiffs { - /// Position of the first line. Note that this is always encoded as a - /// `BytePos` because it is often much larger than any of the - /// differences. - line_start: BytePos, - /// Always 1, 2, or 4. Always as small as possible, while being big /// enough to hold the length of the longest line in the source file. /// The 1 case is by far the most common. @@ -1348,13 +1332,13 @@ pub struct SourceFile { pub src_hash: SourceFileHash, /// The external source code (used for external crates, which will have a `None` /// value as `self.src`. - pub external_src: Lock<ExternalSource>, + pub external_src: FreezeLock<ExternalSource>, /// The start position of this source in the `SourceMap`. pub start_pos: BytePos, - /// The end position of this source in the `SourceMap`. - pub end_pos: BytePos, + /// The byte length of this source. + pub source_len: RelativeBytePos, /// Locations of lines beginnings in the source code. - pub lines: Lock<SourceFileLines>, + pub lines: FreezeLock<SourceFileLines>, /// Locations of multi-byte characters in the source code. pub multibyte_chars: Vec<MultiByteChar>, /// Width of characters that are not narrow in the source code. @@ -1373,10 +1357,10 @@ impl Clone for SourceFile { name: self.name.clone(), src: self.src.clone(), src_hash: self.src_hash, - external_src: Lock::new(self.external_src.borrow().clone()), + external_src: self.external_src.clone(), start_pos: self.start_pos, - end_pos: self.end_pos, - lines: Lock::new(self.lines.borrow().clone()), + source_len: self.source_len, + lines: self.lines.clone(), multibyte_chars: self.multibyte_chars.clone(), non_narrow_chars: self.non_narrow_chars.clone(), normalized_pos: self.normalized_pos.clone(), @@ -1390,68 +1374,67 @@ impl<S: Encoder> Encodable<S> for SourceFile { fn encode(&self, s: &mut S) { self.name.encode(s); self.src_hash.encode(s); - self.start_pos.encode(s); - self.end_pos.encode(s); + // Do not encode `start_pos` as it's global state for this session. + self.source_len.encode(s); // We are always in `Lines` form by the time we reach here. - assert!(self.lines.borrow().is_lines()); - self.lines(|lines| { - // Store the length. - s.emit_u32(lines.len() as u32); - - // Compute and store the difference list. - if lines.len() != 0 { - let max_line_length = if lines.len() == 1 { - 0 - } else { - lines - .array_windows() - .map(|&[fst, snd]| snd - fst) - .map(|bp| bp.to_usize()) - .max() - .unwrap() - }; - - let bytes_per_diff: usize = match max_line_length { - 0..=0xFF => 1, - 0x100..=0xFFFF => 2, - _ => 4, - }; - - // Encode the number of bytes used per diff. - s.emit_u8(bytes_per_diff as u8); - - // Encode the first element. - lines[0].encode(s); - - // Encode the difference list. - let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst); - let num_diffs = lines.len() - 1; - let mut raw_diffs; - match bytes_per_diff { - 1 => { - raw_diffs = Vec::with_capacity(num_diffs); - for diff in diff_iter { - raw_diffs.push(diff.0 as u8); - } + assert!(self.lines.read().is_lines()); + let lines = self.lines(); + // Store the length. + s.emit_u32(lines.len() as u32); + + // Compute and store the difference list. + if lines.len() != 0 { + let max_line_length = if lines.len() == 1 { + 0 + } else { + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() + }; + + let bytes_per_diff: usize = match max_line_length { + 0..=0xFF => 1, + 0x100..=0xFFFF => 2, + _ => 4, + }; + + // Encode the number of bytes used per diff. + s.emit_u8(bytes_per_diff as u8); + + // Encode the first element. + assert_eq!(lines[0], RelativeBytePos(0)); + + // Encode the difference list. + let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst); + let num_diffs = lines.len() - 1; + let mut raw_diffs; + match bytes_per_diff { + 1 => { + raw_diffs = Vec::with_capacity(num_diffs); + for diff in diff_iter { + raw_diffs.push(diff.0 as u8); } - 2 => { - raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); - for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes()); - } + } + 2 => { + raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); + for diff in diff_iter { + raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes()); } - 4 => { - raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); - for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); - } + } + 4 => { + raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); + for diff in diff_iter { + raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); } - _ => unreachable!(), } - s.emit_raw_bytes(&raw_diffs); + _ => unreachable!(), } - }); + s.emit_raw_bytes(&raw_diffs); + } self.multibyte_chars.encode(s); self.non_narrow_chars.encode(s); @@ -1465,26 +1448,17 @@ impl<D: Decoder> Decodable<D> for SourceFile { fn decode(d: &mut D) -> SourceFile { let name: FileName = Decodable::decode(d); let src_hash: SourceFileHash = Decodable::decode(d); - let start_pos: BytePos = Decodable::decode(d); - let end_pos: BytePos = Decodable::decode(d); + let source_len: RelativeBytePos = Decodable::decode(d); let lines = { let num_lines: u32 = Decodable::decode(d); if num_lines > 0 { // Read the number of bytes used per diff. let bytes_per_diff = d.read_u8() as usize; - // Read the first element. - let line_start: BytePos = Decodable::decode(d); - // Read the difference list. let num_diffs = num_lines as usize - 1; let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec(); - SourceFileLines::Diffs(SourceFileDiffs { - line_start, - bytes_per_diff, - num_diffs, - raw_diffs, - }) + SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }) } else { SourceFileLines::Lines(vec![]) } @@ -1496,14 +1470,14 @@ impl<D: Decoder> Decodable<D> for SourceFile { let cnum: CrateNum = Decodable::decode(d); SourceFile { name, - start_pos, - end_pos, + start_pos: BytePos::from_u32(0), + source_len, src: None, src_hash, // Unused - the metadata decoder will construct // a new SourceFile, filling in `external_src` properly - external_src: Lock::new(ExternalSource::Unneeded), - lines: Lock::new(lines), + external_src: FreezeLock::frozen(ExternalSource::Unneeded), + lines: FreezeLock::new(lines), multibyte_chars, non_narrow_chars, normalized_pos, @@ -1523,102 +1497,116 @@ impl SourceFile { pub fn new( name: FileName, mut src: String, - start_pos: BytePos, hash_kind: SourceFileHashAlgorithm, - ) -> Self { + ) -> Result<Self, OffsetOverflowError> { // Compute the file hash before any normalization. let src_hash = SourceFileHash::new(hash_kind, &src); - let normalized_pos = normalize_src(&mut src, start_pos); + let normalized_pos = normalize_src(&mut src); let name_hash = { let mut hasher: StableHasher = StableHasher::new(); name.hash(&mut hasher); hasher.finish() }; - let end_pos = start_pos.to_usize() + src.len(); - assert!(end_pos <= u32::MAX as usize); + let source_len = src.len(); + let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?; let (lines, multibyte_chars, non_narrow_chars) = - analyze_source_file::analyze_source_file(&src, start_pos); + analyze_source_file::analyze_source_file(&src); - SourceFile { + Ok(SourceFile { name, src: Some(Lrc::new(src)), src_hash, - external_src: Lock::new(ExternalSource::Unneeded), - start_pos, - end_pos: Pos::from_usize(end_pos), - lines: Lock::new(SourceFileLines::Lines(lines)), + external_src: FreezeLock::frozen(ExternalSource::Unneeded), + start_pos: BytePos::from_u32(0), + source_len: RelativeBytePos::from_u32(source_len), + lines: FreezeLock::frozen(SourceFileLines::Lines(lines)), multibyte_chars, non_narrow_chars, normalized_pos, name_hash, cnum: LOCAL_CRATE, - } + }) } - pub fn lines<F, R>(&self, f: F) -> R - where - F: FnOnce(&[BytePos]) -> R, - { - let mut guard = self.lines.borrow_mut(); - match &*guard { - SourceFileLines::Lines(lines) => f(lines), - SourceFileLines::Diffs(SourceFileDiffs { - mut line_start, - bytes_per_diff, - num_diffs, - raw_diffs, - }) => { - // Convert from "diffs" form to "lines" form. - let num_lines = num_diffs + 1; - let mut lines = Vec::with_capacity(num_lines); - lines.push(line_start); - - assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff); - match bytes_per_diff { - 1 => { - lines.extend(raw_diffs.into_iter().map(|&diff| { - line_start = line_start + BytePos(diff as u32); - line_start - })); - } - 2 => { - lines.extend((0..*num_diffs).map(|i| { - let pos = bytes_per_diff * i; - let bytes = [raw_diffs[pos], raw_diffs[pos + 1]]; - let diff = u16::from_le_bytes(bytes); - line_start = line_start + BytePos(diff as u32); - line_start - })); - } - 4 => { - lines.extend((0..*num_diffs).map(|i| { - let pos = bytes_per_diff * i; - let bytes = [ - raw_diffs[pos], - raw_diffs[pos + 1], - raw_diffs[pos + 2], - raw_diffs[pos + 3], - ]; - let diff = u32::from_le_bytes(bytes); - line_start = line_start + BytePos(diff); - line_start - })); - } - _ => unreachable!(), - } - let res = f(&lines); - *guard = SourceFileLines::Lines(lines); - res + /// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it. + fn convert_diffs_to_lines_frozen(&self) { + let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return }; + + let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard { + SourceFileLines::Diffs(diffs) => diffs, + SourceFileLines::Lines(..) => { + FreezeWriteGuard::freeze(guard); + return; + } + }; + + // Convert from "diffs" form to "lines" form. + let num_lines = num_diffs + 1; + let mut lines = Vec::with_capacity(num_lines); + let mut line_start = RelativeBytePos(0); + lines.push(line_start); + + assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff); + match bytes_per_diff { + 1 => { + lines.extend(raw_diffs.into_iter().map(|&diff| { + line_start = line_start + RelativeBytePos(diff as u32); + line_start + })); + } + 2 => { + lines.extend((0..*num_diffs).map(|i| { + let pos = bytes_per_diff * i; + let bytes = [raw_diffs[pos], raw_diffs[pos + 1]]; + let diff = u16::from_le_bytes(bytes); + line_start = line_start + RelativeBytePos(diff as u32); + line_start + })); } + 4 => { + lines.extend((0..*num_diffs).map(|i| { + let pos = bytes_per_diff * i; + let bytes = [ + raw_diffs[pos], + raw_diffs[pos + 1], + raw_diffs[pos + 2], + raw_diffs[pos + 3], + ]; + let diff = u32::from_le_bytes(bytes); + line_start = line_start + RelativeBytePos(diff); + line_start + })); + } + _ => unreachable!(), } + + *guard = SourceFileLines::Lines(lines); + + FreezeWriteGuard::freeze(guard); + } + + pub fn lines(&self) -> &[RelativeBytePos] { + if let Some(SourceFileLines::Lines(lines)) = self.lines.get() { + return &lines[..]; + } + + cold_path(|| { + self.convert_diffs_to_lines_frozen(); + if let Some(SourceFileLines::Lines(lines)) = self.lines.get() { + return &lines[..]; + } + unreachable!() + }) } /// Returns the `BytePos` of the beginning of the current line. pub fn line_begin_pos(&self, pos: BytePos) -> BytePos { + let pos = self.relative_position(pos); let line_index = self.lookup_line(pos).unwrap(); - self.lines(|lines| lines[line_index]) + let line_start_pos = self.lines()[line_index]; + self.absolute_position(line_start_pos) } /// Add externally loaded source. @@ -1629,35 +1617,37 @@ impl SourceFile { where F: FnOnce() -> Option<String>, { - if matches!( - *self.external_src.borrow(), - ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. } - ) { + if !self.external_src.is_frozen() { let src = get_src(); - let mut external_src = self.external_src.borrow_mut(); - // Check that no-one else have provided the source while we were getting it - if let ExternalSource::Foreign { - kind: src_kind @ ExternalSourceKind::AbsentOk, .. - } = &mut *external_src - { - if let Some(mut src) = src { - // The src_hash needs to be computed on the pre-normalized src. - if self.src_hash.matches(&src) { - normalize_src(&mut src, BytePos::from_usize(0)); - *src_kind = ExternalSourceKind::Present(Lrc::new(src)); - return true; - } + let src = src.and_then(|mut src| { + // The src_hash needs to be computed on the pre-normalized src. + self.src_hash.matches(&src).then(|| { + normalize_src(&mut src); + src + }) + }); + + self.external_src.try_write().map(|mut external_src| { + if let ExternalSource::Foreign { + kind: src_kind @ ExternalSourceKind::AbsentOk, + .. + } = &mut *external_src + { + *src_kind = if let Some(src) = src { + ExternalSourceKind::Present(Lrc::new(src)) + } else { + ExternalSourceKind::AbsentErr + }; } else { - *src_kind = ExternalSourceKind::AbsentErr; + panic!("unexpected state {:?}", *external_src) } - false - } else { - self.src.is_some() || external_src.get_source().is_some() - } - } else { - self.src.is_some() || self.external_src.borrow().get_source().is_some() + // Freeze this so we don't try to load the source again. + FreezeWriteGuard::freeze(external_src) + }); } + + self.src.is_some() || self.external_src.read().get_source().is_some() } /// Gets a line from the list of pre-computed line-beginnings. @@ -1675,9 +1665,8 @@ impl SourceFile { } let begin = { - let line = self.lines(|lines| lines.get(line_number).copied())?; - let begin: BytePos = line - self.start_pos; - begin.to_usize() + let line = self.lines().get(line_number).copied()?; + line.to_usize() }; if let Some(ref src) = self.src { @@ -1700,30 +1689,44 @@ impl SourceFile { } pub fn count_lines(&self) -> usize { - self.lines(|lines| lines.len()) + self.lines().len() + } + + #[inline] + pub fn absolute_position(&self, pos: RelativeBytePos) -> BytePos { + BytePos::from_u32(pos.to_u32() + self.start_pos.to_u32()) + } + + #[inline] + pub fn relative_position(&self, pos: BytePos) -> RelativeBytePos { + RelativeBytePos::from_u32(pos.to_u32() - self.start_pos.to_u32()) + } + + #[inline] + pub fn end_position(&self) -> BytePos { + self.absolute_position(self.source_len) } /// Finds the line containing the given position. The return value is the /// index into the `lines` array of this `SourceFile`, not the 1-based line /// number. If the source_file is empty or the position is located before the /// first line, `None` is returned. - pub fn lookup_line(&self, pos: BytePos) -> Option<usize> { - self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1)) + pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> { + self.lines().partition_point(|x| x <= &pos).checked_sub(1) } pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> { if self.is_empty() { - return self.start_pos..self.end_pos; + return self.start_pos..self.start_pos; } - self.lines(|lines| { - assert!(line_index < lines.len()); - if line_index == (lines.len() - 1) { - lines[line_index]..self.end_pos - } else { - lines[line_index]..lines[line_index + 1] - } - }) + let lines = self.lines(); + assert!(line_index < lines.len()); + if line_index == (lines.len() - 1) { + self.absolute_position(lines[line_index])..self.end_position() + } else { + self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1]) + } } /// Returns whether or not the file contains the given `SourceMap` byte @@ -1732,17 +1735,19 @@ impl SourceFile { /// returns true still contain one byte position according to this function. #[inline] pub fn contains(&self, byte_pos: BytePos) -> bool { - byte_pos >= self.start_pos && byte_pos <= self.end_pos + byte_pos >= self.start_pos && byte_pos <= self.end_position() } #[inline] pub fn is_empty(&self) -> bool { - self.start_pos == self.end_pos + self.source_len.to_u32() == 0 } /// Calculates the original byte position relative to the start of the file /// based on the given byte position. - pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos { + pub fn original_relative_byte_pos(&self, pos: BytePos) -> RelativeBytePos { + let pos = self.relative_position(pos); + // Diff before any records is 0. Otherwise use the previously recorded // diff as that applies to the following characters until a new diff // is recorded. @@ -1752,7 +1757,7 @@ impl SourceFile { Err(i) => self.normalized_pos[i - 1].diff, }; - BytePos::from_u32(pos.0 - self.start_pos.0 + diff) + RelativeBytePos::from_u32(pos.0 + diff) } /// Calculates a normalized byte position from a byte offset relative to the @@ -1777,8 +1782,8 @@ impl SourceFile { BytePos::from_u32(self.start_pos.0 + offset - diff) } - /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. - pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { + /// Converts an relative `RelativeBytePos` to a `CharPos` relative to the `SourceFile`. + fn bytepos_to_file_charpos(&self, bpos: RelativeBytePos) -> CharPos { // The number of extra bytes due to multibyte chars in the `SourceFile`. let mut total_extra_bytes = 0; @@ -1796,18 +1801,18 @@ impl SourceFile { } } - assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32()); - CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize) + assert!(total_extra_bytes <= bpos.to_u32()); + CharPos(bpos.to_usize() - total_extra_bytes as usize) } /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a - /// given `BytePos`. - pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) { + /// given `RelativeBytePos`. + fn lookup_file_pos(&self, pos: RelativeBytePos) -> (usize, CharPos) { let chpos = self.bytepos_to_file_charpos(pos); match self.lookup_line(pos) { Some(a) => { let line = a + 1; // Line numbers start at 1 - let linebpos = self.lines(|lines| lines[a]); + let linebpos = self.lines()[a]; let linechpos = self.bytepos_to_file_charpos(linebpos); let col = chpos - linechpos; debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); @@ -1823,10 +1828,11 @@ impl SourceFile { /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based) /// column offset when displayed, for a given `BytePos`. pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) { + let pos = self.relative_position(pos); let (line, col_or_chpos) = self.lookup_file_pos(pos); if line > 0 { let col = col_or_chpos; - let linebpos = self.lines(|lines| lines[line - 1]); + let linebpos = self.lines()[line - 1]; let col_display = { let start_width_idx = self .non_narrow_chars @@ -1861,16 +1867,10 @@ impl SourceFile { } /// Normalizes the source code and records the normalizations. -fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> { +fn normalize_src(src: &mut String) -> Vec<NormalizedPos> { let mut normalized_pos = vec![]; remove_bom(src, &mut normalized_pos); normalize_newlines(src, &mut normalized_pos); - - // Offset all the positions by start_pos to match the final file positions. - for np in &mut normalized_pos { - np.pos.0 += start_pos.0; - } - normalized_pos } @@ -1878,7 +1878,7 @@ fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> { fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) { if src.starts_with('\u{feff}') { src.drain(..3); - normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 }); + normalized_pos.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 }); } } @@ -1913,7 +1913,7 @@ fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) cursor += idx - gap_len; gap_len += 1; normalized_pos.push(NormalizedPos { - pos: BytePos::from_usize(cursor + 1), + pos: RelativeBytePos::from_usize(cursor + 1), diff: original_gap + gap_len as u32, }); } @@ -2015,6 +2015,10 @@ impl_pos! { #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct BytePos(pub u32); + /// A byte offset relative to file beginning. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct RelativeBytePos(pub u32); + /// A character offset. /// /// Because of multibyte UTF-8 characters, a byte offset @@ -2036,6 +2040,24 @@ impl<D: Decoder> Decodable<D> for BytePos { } } +impl<H: HashStableContext> HashStable<H> for RelativeBytePos { + fn hash_stable(&self, hcx: &mut H, hasher: &mut StableHasher) { + self.0.hash_stable(hcx, hasher); + } +} + +impl<S: Encoder> Encodable<S> for RelativeBytePos { + fn encode(&self, s: &mut S) { + s.emit_u32(self.0); + } +} + +impl<D: Decoder> Decodable<D> for RelativeBytePos { + fn decode(d: &mut D) -> RelativeBytePos { + RelativeBytePos(d.read_u32()) + } +} + // _____________________________________________________________________________ // Loc, SourceFileAndLine, SourceFileAndBytePos // diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 1cff021ba41..68727a6c40e 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -14,13 +14,10 @@ pub use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; -use rustc_data_structures::sync::{ - AtomicU32, IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock, -}; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock}; use std::cmp; use std::hash::Hash; use std::path::{self, Path, PathBuf}; -use std::sync::atomic::Ordering; use std::fs; use std::io; @@ -187,9 +184,6 @@ pub(super) struct SourceMapFiles { } pub struct SourceMap { - /// The address space below this value is currently used by the files in the source map. - used_address_space: AtomicU32, - files: RwLock<SourceMapFiles>, file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>, // This is used to apply the file path remapping as specified via @@ -215,7 +209,6 @@ impl SourceMap { hash_kind: SourceFileHashAlgorithm, ) -> SourceMap { SourceMap { - used_address_space: AtomicU32::new(0), files: Default::default(), file_loader: IntoDynSyncSend(file_loader), path_mapping, @@ -267,26 +260,26 @@ impl SourceMap { self.files.borrow().stable_id_to_source_file.get(&stable_id).cloned() } - fn allocate_address_space(&self, size: usize) -> Result<usize, OffsetOverflowError> { - let size = u32::try_from(size).map_err(|_| OffsetOverflowError)?; - - loop { - let current = self.used_address_space.load(Ordering::Relaxed); - let next = current - .checked_add(size) - // Add one so there is some space between files. This lets us distinguish - // positions in the `SourceMap`, even in the presence of zero-length files. - .and_then(|next| next.checked_add(1)) - .ok_or(OffsetOverflowError)?; - - if self - .used_address_space - .compare_exchange(current, next, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { - return Ok(usize::try_from(current).unwrap()); - } - } + fn register_source_file( + &self, + file_id: StableSourceFileId, + mut file: SourceFile, + ) -> Result<Lrc<SourceFile>, OffsetOverflowError> { + let mut files = self.files.borrow_mut(); + + file.start_pos = BytePos(if let Some(last_file) = files.source_files.last() { + // Add one so there is some space between files. This lets us distinguish + // positions in the `SourceMap`, even in the presence of zero-length files. + last_file.end_position().0.checked_add(1).ok_or(OffsetOverflowError)? + } else { + 0 + }); + + let file = Lrc::new(file); + files.source_files.push(file.clone()); + files.stable_id_to_source_file.insert(file_id, file.clone()); + + Ok(file) } /// Creates a new `SourceFile`. @@ -310,32 +303,18 @@ impl SourceMap { let (filename, _) = self.path_mapping.map_filename_prefix(&filename); let file_id = StableSourceFileId::new_from_name(&filename, LOCAL_CRATE); - - let lrc_sf = match self.source_file_by_stable_id(file_id) { - Some(lrc_sf) => lrc_sf, + match self.source_file_by_stable_id(file_id) { + Some(lrc_sf) => Ok(lrc_sf), None => { - let start_pos = self.allocate_address_space(src.len())?; - - let source_file = Lrc::new(SourceFile::new( - filename, - src, - Pos::from_usize(start_pos), - self.hash_kind, - )); + let source_file = SourceFile::new(filename, src, self.hash_kind)?; // Let's make sure the file_id we generated above actually matches // the ID we generate for the SourceFile we just created. debug_assert_eq!(StableSourceFileId::new(&source_file), file_id); - let mut files = self.files.borrow_mut(); - - files.source_files.push(source_file.clone()); - files.stable_id_to_source_file.insert(file_id, source_file.clone()); - - source_file + self.register_source_file(file_id, source_file) } - }; - Ok(lrc_sf) + } } /// Allocates a new `SourceFile` representing a source file from an external @@ -347,78 +326,37 @@ impl SourceMap { filename: FileName, src_hash: SourceFileHash, name_hash: Hash128, - source_len: usize, + source_len: u32, cnum: CrateNum, - file_local_lines: Lock<SourceFileLines>, - mut file_local_multibyte_chars: Vec<MultiByteChar>, - mut file_local_non_narrow_chars: Vec<NonNarrowChar>, - mut file_local_normalized_pos: Vec<NormalizedPos>, - original_start_pos: BytePos, + file_local_lines: FreezeLock<SourceFileLines>, + multibyte_chars: Vec<MultiByteChar>, + non_narrow_chars: Vec<NonNarrowChar>, + normalized_pos: Vec<NormalizedPos>, metadata_index: u32, ) -> Lrc<SourceFile> { - let start_pos = self - .allocate_address_space(source_len) - .expect("not enough address space for imported source file"); - - let end_pos = Pos::from_usize(start_pos + source_len); - let start_pos = Pos::from_usize(start_pos); - - // Translate these positions into the new global frame of reference, - // now that the offset of the SourceFile is known. - // - // These are all unsigned values. `original_start_pos` may be larger or - // smaller than `start_pos`, but `pos` is always larger than both. - // Therefore, `(pos - original_start_pos) + start_pos` won't overflow - // but `start_pos - original_start_pos` might. So we use the former - // form rather than pre-computing the offset into a local variable. The - // compiler backend can optimize away the repeated computations in a - // way that won't trigger overflow checks. - match &mut *file_local_lines.borrow_mut() { - SourceFileLines::Lines(lines) => { - for pos in lines { - *pos = (*pos - original_start_pos) + start_pos; - } - } - SourceFileLines::Diffs(SourceFileDiffs { line_start, .. }) => { - *line_start = (*line_start - original_start_pos) + start_pos; - } - } - for mbc in &mut file_local_multibyte_chars { - mbc.pos = (mbc.pos - original_start_pos) + start_pos; - } - for swc in &mut file_local_non_narrow_chars { - *swc = (*swc - original_start_pos) + start_pos; - } - for nc in &mut file_local_normalized_pos { - nc.pos = (nc.pos - original_start_pos) + start_pos; - } + let source_len = RelativeBytePos::from_u32(source_len); - let source_file = Lrc::new(SourceFile { + let source_file = SourceFile { name: filename, src: None, src_hash, - external_src: Lock::new(ExternalSource::Foreign { + external_src: FreezeLock::new(ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, metadata_index, }), - start_pos, - end_pos, + start_pos: BytePos(0), + source_len, lines: file_local_lines, - multibyte_chars: file_local_multibyte_chars, - non_narrow_chars: file_local_non_narrow_chars, - normalized_pos: file_local_normalized_pos, + multibyte_chars, + non_narrow_chars, + normalized_pos, name_hash, cnum, - }); - - let mut files = self.files.borrow_mut(); - - files.source_files.push(source_file.clone()); - files - .stable_id_to_source_file - .insert(StableSourceFileId::new(&source_file), source_file.clone()); + }; - source_file + let file_id = StableSourceFileId::new(&source_file); + self.register_source_file(file_id, source_file) + .expect("not enough address space for imported source file") } /// If there is a doctest offset, applies it to the line. @@ -452,6 +390,7 @@ impl SourceMap { pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceFile>> { let f = self.lookup_source_file(pos); + let pos = f.relative_position(pos); match f.lookup_line(pos) { Some(line) => Ok(SourceFileAndLine { sf: f, line }), None => Err(f), @@ -547,7 +486,9 @@ impl SourceMap { return true; } let f = (*self.files.borrow().source_files)[lo].clone(); - f.lookup_line(sp.lo()) != f.lookup_line(sp.hi()) + let lo = f.relative_position(sp.lo()); + let hi = f.relative_position(sp.hi()); + f.lookup_line(lo) != f.lookup_line(hi) } #[instrument(skip(self), level = "trace")] @@ -623,11 +564,11 @@ impl SourceMap { end: (local_end.sf.name.clone(), local_end.sf.start_pos), }))) } else { - self.ensure_source_file_source_present(local_begin.sf.clone()); + self.ensure_source_file_source_present(&local_begin.sf); let start_index = local_begin.pos.to_usize(); let end_index = local_end.pos.to_usize(); - let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize(); + let source_len = local_begin.sf.source_len.to_usize(); if start_index > end_index || end_index > source_len { return Err(SpanSnippetError::MalformedForSourcemap(MalformedSourceMapPositions { @@ -640,7 +581,7 @@ impl SourceMap { if let Some(ref src) = local_begin.sf.src { extract_source(src, start_index, end_index) - } else if let Some(src) = local_begin.sf.external_src.borrow().get_source() { + } else if let Some(src) = local_begin.sf.external_src.read().get_source() { extract_source(src, start_index, end_index) } else { Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() }) @@ -932,7 +873,7 @@ impl SourceMap { let sp = sp.data(); let local_begin = self.lookup_byte_offset(sp.lo); let start_index = local_begin.pos.to_usize(); - let src = local_begin.sf.external_src.borrow(); + let src = local_begin.sf.external_src.read(); let snippet = if let Some(ref src) = local_begin.sf.src { Some(&src[start_index..]) @@ -1034,7 +975,7 @@ impl SourceMap { return 1; } - let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize(); + let source_len = local_begin.sf.source_len.to_usize(); debug!("source_len=`{:?}`", source_len); // Ensure indexes are also not malformed. if start_index > end_index || end_index > source_len - 1 { @@ -1042,7 +983,7 @@ impl SourceMap { return 1; } - let src = local_begin.sf.external_src.borrow(); + let src = local_begin.sf.external_src.read(); let snippet = if let Some(src) = &local_begin.sf.src { src @@ -1089,7 +1030,7 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool { + pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool { source_file.add_external_src(|| { let FileName::Real(ref name) = source_file.name else { return None; diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 686b3b00d70..e393db02064 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -1,6 +1,6 @@ use super::*; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{FreezeLock, Lrc}; fn init_source_map() -> SourceMap { let sm = SourceMap::new(FilePathMapping::empty()); @@ -50,6 +50,7 @@ impl SourceMap { fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { let idx = self.lookup_source_file_idx(bpos); let sf = &(*self.files.borrow().source_files)[idx]; + let bpos = sf.relative_position(bpos); sf.bytepos_to_file_charpos(bpos) } } @@ -230,8 +231,7 @@ fn t10() { let SourceFile { name, src_hash, - start_pos, - end_pos, + source_len, lines, multibyte_chars, non_narrow_chars, @@ -244,13 +244,12 @@ fn t10() { name, src_hash, name_hash, - (end_pos - start_pos).to_usize(), + source_len.to_u32(), CrateNum::new(0), - lines, + FreezeLock::new(lines.read().clone()), multibyte_chars, non_narrow_chars, normalized_pos, - start_pos, 0, ); diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 1eea0f63ca0..93ab154601f 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -1,9 +1,3 @@ -// Spans are encoded using 1-bit tag and 2 different encoding formats (one for each tag value). -// One format is used for keeping span data inline, -// another contains index into an out-of-line span interner. -// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd. -// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28 - use crate::def_id::{DefIndex, LocalDefId}; use crate::hygiene::SyntaxContext; use crate::SPAN_TRACK; @@ -13,59 +7,69 @@ use rustc_data_structures::fx::FxIndexSet; /// A compressed span. /// -/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span` -/// is a form that only takes up 8 bytes, with less space for the length, parent and -/// context. The vast majority (99.9%+) of `SpanData` instances will fit within -/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are +/// [`SpanData`] is 16 bytes, which is too big to stick everywhere. `Span` only +/// takes up 8 bytes, with less space for the length, parent and context. The +/// vast majority (99.9%+) of `SpanData` instances can be made to fit within +/// those 8 bytes. Any `SpanData` whose fields don't fit into a `Span` are /// stored in a separate interner table, and the `Span` will index into that /// table. Interning is rare enough that the cost is low, but common enough /// that the code is exercised regularly. /// /// An earlier version of this code used only 4 bytes for `Span`, but that was /// slower because only 80--90% of spans could be stored inline (even less in -/// very large crates) and so the interner was used a lot more. +/// very large crates) and so the interner was used a lot more. That version of +/// the code also predated the storage of parents. +/// +/// There are four different span forms. /// -/// Inline (compressed) format with no parent: -/// - `span.base_or_index == span_data.lo` -/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) -/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`) +/// Inline-context format (requires non-huge length, non-huge context, and no parent): +/// - `span.lo_or_index == span_data.lo` +/// - `span.len_with_tag_or_marker == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) +/// - `span.ctxt_or_parent_or_marker == span_data.ctxt` (must be `<= MAX_CTXT`) /// -/// Interned format with inline `SyntaxContext`: -/// - `span.base_or_index == index` (indexes into the interner table) -/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero) -/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`) +/// Inline-parent format (requires non-huge length, root context, and non-huge parent): +/// - `span.lo_or_index == span_data.lo` +/// - `span.len_with_tag_or_marker & !PARENT_TAG == len == span_data.hi - span_data.lo` +/// (must be `<= MAX_LEN`) +/// - `span.len_with_tag_or_marker` has top bit (`PARENT_TAG`) set +/// - `span.ctxt_or_parent_or_marker == span_data.parent` (must be `<= MAX_CTXT`) /// -/// Inline (compressed) format with root context: -/// - `span.base_or_index == span_data.lo` -/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) -/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set -/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`) +/// Partially-interned format (requires non-huge context): +/// - `span.lo_or_index == index` (indexes into the interner table) +/// - `span.len_with_tag_or_marker == BASE_LEN_INTERNED_MARKER` +/// - `span.ctxt_or_parent_or_marker == span_data.ctxt` (must be `<= MAX_CTXT`) /// -/// Interned format: -/// - `span.base_or_index == index` (indexes into the interner table) -/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero) -/// - `span.ctxt_or_tag == CTXT_TAG` +/// Fully-interned format (all cases not covered above): +/// - `span.lo_or_index == index` (indexes into the interner table) +/// - `span.len_with_tag_or_marker == BASE_LEN_INTERNED_MARKER` +/// - `span.ctxt_or_parent_or_marker == CTXT_INTERNED_MARKER` /// -/// The inline form uses 0 for the tag value (rather than 1) so that we don't -/// need to mask out the tag bit when getting the length, and so that the -/// dummy span can be all zeroes. +/// The partially-interned form requires looking in the interning table for +/// lo and length, but the context is stored inline as well as interned. +/// This is useful because context lookups are often done in isolation, and +/// inline lookups are quicker. /// /// Notes about the choice of field sizes: -/// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base` -/// values never cause interning. The number of bits needed for `base` +/// - `lo` is 32 bits in both `Span` and `SpanData`, which means that `lo` +/// values never cause interning. The number of bits needed for `lo` /// depends on the crate size. 32 bits allows up to 4 GiB of code in a crate. -/// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits -/// in `SpanData`, which means that large `len` values will cause interning. -/// The number of bits needed for `len` does not depend on the crate size. -/// The most common numbers of bits for `len` are from 0 to 7, with a peak usually -/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough -/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur -/// dozens of times in a typical crate. -/// - `ctxt_or_tag` is 16 bits in `Span` and 32 bits in `SpanData`, which means that -/// large `ctxt` values will cause interning. The number of bits needed for -/// `ctxt` values depend partly on the crate size and partly on the form of -/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag`, -/// but larger crates might need more than 16 bits. +/// Having no compression on this field means there is no performance cliff +/// if a crate exceeds a particular size. +/// - `len` is ~15 bits in `Span` (a u16, minus 1 bit for PARENT_TAG) and 32 +/// bits in `SpanData`, which means that large `len` values will cause +/// interning. The number of bits needed for `len` does not depend on the +/// crate size. The most common numbers of bits for `len` are from 0 to 7, +/// with a peak usually at 3 or 4, and then it drops off quickly from 8 +/// onwards. 15 bits is enough for 99.99%+ of cases, but larger values +/// (sometimes 20+ bits) might occur dozens of times in a typical crate. +/// - `ctxt_or_parent_or_marker` is 16 bits in `Span` and two 32 bit fields in +/// `SpanData`, which means intering will happen if `ctxt` is large, if +/// `parent` is large, or if both values are non-zero. The number of bits +/// needed for `ctxt` values depend partly on the crate size and partly on +/// the form of the code. No crates in `rustc-perf` need more than 15 bits +/// for `ctxt_or_parent_or_marker`, but larger crates might need more than 16 +/// bits. The number of bits needed for `parent` hasn't been measured, +/// because `parent` isn't currently used by default. /// /// In order to reliably use parented spans in incremental compilation, /// the dependency to the parent definition's span. This is performed @@ -74,19 +78,22 @@ use rustc_data_structures::fx::FxIndexSet; #[derive(Clone, Copy, Eq, PartialEq, Hash)] #[rustc_pass_by_value] pub struct Span { - base_or_index: u32, - len_or_tag: u16, - ctxt_or_tag: u16, + lo_or_index: u32, + len_with_tag_or_marker: u16, + ctxt_or_parent_or_marker: u16, } -const LEN_TAG: u16 = 0b1111_1111_1111_1111; -const PARENT_MASK: u16 = 0b1000_0000_0000_0000; -const MAX_LEN: u32 = 0b0111_1111_1111_1111; -const CTXT_TAG: u32 = 0b1111_1111_1111_1111; -const MAX_CTXT: u32 = CTXT_TAG - 1; +// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from +// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.) +const MAX_LEN: u32 = 0b0111_1111_1111_1110; +const MAX_CTXT: u32 = 0b0111_1111_1111_1110; +const PARENT_TAG: u16 = 0b1000_0000_0000_0000; +const BASE_LEN_INTERNED_MARKER: u16 = 0b1111_1111_1111_1111; +const CTXT_INTERNED_MARKER: u16 = 0b1111_1111_1111_1111; -/// Dummy span, both position and length are zero, syntax context is zero as well. -pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_tag: 0 }; +/// The dummy span has zero position, length, and context, and no parent. +pub const DUMMY_SP: Span = + Span { lo_or_index: 0, len_with_tag_or_marker: 0, ctxt_or_parent_or_marker: 0 }; impl Span { #[inline] @@ -100,39 +107,43 @@ impl Span { std::mem::swap(&mut lo, &mut hi); } - let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); - - if len <= MAX_LEN && ctxt2 <= MAX_CTXT { - let len_or_tag = len as u16; - debug_assert_eq!(len_or_tag & PARENT_MASK, 0); + let (lo2, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); - if let Some(parent) = parent { - // Inline format with parent. - let len_or_tag = len_or_tag | PARENT_MASK; - let parent2 = parent.local_def_index.as_u32(); - if ctxt2 == SyntaxContext::root().as_u32() - && parent2 <= MAX_CTXT - && len_or_tag < LEN_TAG - { - debug_assert_ne!(len_or_tag, LEN_TAG); - return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 }; - } - } else { - // Inline format with ctxt. - debug_assert_ne!(len_or_tag, LEN_TAG); + if len <= MAX_LEN { + if ctxt2 <= MAX_CTXT && parent.is_none() { + // Inline-context format. return Span { - base_or_index: base, - len_or_tag: len as u16, - ctxt_or_tag: ctxt2 as u16, + lo_or_index: lo2, + len_with_tag_or_marker: len as u16, + ctxt_or_parent_or_marker: ctxt2 as u16, + }; + } else if ctxt2 == SyntaxContext::root().as_u32() + && let Some(parent) = parent + && let parent2 = parent.local_def_index.as_u32() + && parent2 <= MAX_CTXT + { + // Inline-parent format. + return Span { + lo_or_index: lo2, + len_with_tag_or_marker: PARENT_TAG | len as u16, + ctxt_or_parent_or_marker: parent2 as u16 }; } } - // Interned format. + // Partially-interned or fully-interned format. let index = with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })); - let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16; - Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag } + let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT { + ctxt2 as u16 // partially-interned + } else { + CTXT_INTERNED_MARKER // fully-interned + }; + Span { + lo_or_index: index, + len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, + ctxt_or_parent_or_marker, + } } #[inline] @@ -148,56 +159,80 @@ impl Span { /// This function must not be used outside the incremental engine. #[inline] pub fn data_untracked(self) -> SpanData { - if self.len_or_tag != LEN_TAG { - // Inline format. - if self.len_or_tag & PARENT_MASK == 0 { - debug_assert!(self.len_or_tag as u32 <= MAX_LEN); + if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if self.len_with_tag_or_marker & PARENT_TAG == 0 { + // Inline-context format. + let len = self.len_with_tag_or_marker as u32; + debug_assert!(len <= MAX_LEN); SpanData { - lo: BytePos(self.base_or_index), - hi: BytePos(self.base_or_index + self.len_or_tag as u32), - ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32), + lo: BytePos(self.lo_or_index), + hi: BytePos(self.lo_or_index + len), + ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), parent: None, } } else { - let len = self.len_or_tag & !PARENT_MASK; - debug_assert!(len as u32 <= MAX_LEN); - let parent = - LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) }; + // Inline-parent format. + let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; + debug_assert!(len <= MAX_LEN); + let parent = LocalDefId { + local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32), + }; SpanData { - lo: BytePos(self.base_or_index), - hi: BytePos(self.base_or_index + len as u32), + lo: BytePos(self.lo_or_index), + hi: BytePos(self.lo_or_index + len), ctxt: SyntaxContext::root(), parent: Some(parent), } } } else { - // Interned format. - let index = self.base_or_index; + // Fully-interned or partially-interned format. In either case, + // the interned value contains all the data, so we don't need to + // distinguish them. + let index = self.lo_or_index; with_span_interner(|interner| interner.spans[index as usize]) } } + /// Returns `true` if this is a dummy span with any hygienic context. + #[inline] + pub fn is_dummy(self) -> bool { + if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + // Inline-context or inline-parent format. + let lo = self.lo_or_index; + let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; + debug_assert!(len <= MAX_LEN); + lo == 0 && len == 0 + } else { + // Fully-interned or partially-interned format. + let index = self.lo_or_index; + let data = with_span_interner(|interner| interner.spans[index as usize]); + data.lo == BytePos(0) && data.hi == BytePos(0) + } + } + /// This function is used as a fast path when decoding the full `SpanData` is not necessary. + /// It's a cut-down version of `data_untracked`. #[inline] pub fn ctxt(self) -> SyntaxContext { - let ctxt_or_tag = self.ctxt_or_tag as u32; - // Check for interned format. - if self.len_or_tag == LEN_TAG { - if ctxt_or_tag == CTXT_TAG { - // Fully interned format. - let index = self.base_or_index; - with_span_interner(|interner| interner.spans[index as usize].ctxt) + if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if self.len_with_tag_or_marker & PARENT_TAG == 0 { + // Inline-context format. + SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) } else { - // Interned format with inline ctxt. - SyntaxContext::from_u32(ctxt_or_tag) + // Inline-parent format. We know that the SyntaxContext is root. + SyntaxContext::root() } - } else if self.len_or_tag & PARENT_MASK == 0 { - // Inline format with inline ctxt. - SyntaxContext::from_u32(ctxt_or_tag) } else { - // Inline format with inline parent. - // We know that the SyntaxContext is root. - SyntaxContext::root() + if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. This path avoids looking up the + // interned value, and is the whole point of the + // partially-interned format. + SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) + } else { + // Fully-interned format. + let index = self.lo_or_index; + with_span_interner(|interner| interner.spans[index as usize].ctxt) + } } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 656deebb5d0..3247d5e46ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -387,6 +387,7 @@ symbols! { asm_sym, asm_unwind, assert, + assert_eq, assert_eq_macro, assert_inhabited, assert_macro, @@ -1639,6 +1640,7 @@ symbols! { unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_from_mut, + unsafe_cell_raw_get, unsafe_no_drop_flag, unsafe_pin_internals, unsize, diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index a242ad6d1d7..cb88fa89058 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -3,24 +3,21 @@ use super::*; #[test] fn test_lookup_line() { let source = "abcdefghijklm\nabcdefghij\n...".to_owned(); - let sf = SourceFile::new( - FileName::Anon(Hash64::ZERO), - source, - BytePos(3), - SourceFileHashAlgorithm::Sha256, - ); - sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)])); + let mut sf = + SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256) + .unwrap(); + sf.start_pos = BytePos(3); + assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]); - assert_eq!(sf.lookup_line(BytePos(0)), None); - assert_eq!(sf.lookup_line(BytePos(3)), Some(0)); - assert_eq!(sf.lookup_line(BytePos(4)), Some(0)); + assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0)); + assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0)); - assert_eq!(sf.lookup_line(BytePos(16)), Some(0)); - assert_eq!(sf.lookup_line(BytePos(17)), Some(1)); - assert_eq!(sf.lookup_line(BytePos(18)), Some(1)); + assert_eq!(sf.lookup_line(RelativeBytePos(13)), Some(0)); + assert_eq!(sf.lookup_line(RelativeBytePos(14)), Some(1)); + assert_eq!(sf.lookup_line(RelativeBytePos(15)), Some(1)); - assert_eq!(sf.lookup_line(BytePos(28)), Some(2)); - assert_eq!(sf.lookup_line(BytePos(29)), Some(2)); + assert_eq!(sf.lookup_line(RelativeBytePos(25)), Some(2)); + assert_eq!(sf.lookup_line(RelativeBytePos(26)), Some(2)); } #[test] diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8d573def9bb..5d75974279e 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -36,7 +36,10 @@ pub enum PassMode { Ignore, /// Pass the argument directly. /// - /// The argument has a layout abi of `Scalar`, `Vector` or in rare cases `Aggregate`. + /// The argument has a layout abi of `Scalar` or `Vector`. + /// Unfortunately due to past mistakes, in rare cases on wasm, it can also be `Aggregate`. + /// This is bad since it leaks LLVM implementation details into the ABI. + /// (Also see <https://github.com/rust-lang/rust/issues/115666>.) Direct(ArgAttributes), /// Pass a pair's elements directly in two arguments. /// @@ -55,6 +58,29 @@ pub enum PassMode { Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool }, } +impl PassMode { + /// Checks if these two `PassMode` are equal enough to be considered "the same for all + /// function call ABIs". However, the `Layout` can also impact ABI decisions, + /// so that needs to be compared as well! + pub fn eq_abi(&self, other: &Self) -> bool { + match (self, other) { + (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type + (PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2), + (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2), + (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1.eq_abi(c2) && pad1 == pad2, + ( + PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, + PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, + ) => a1.eq_abi(a2) && s1 == s2, + ( + PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 }, + PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 }, + ) => a1.eq_abi(a2) && e1.eq_abi(e2) && s1 == s2, + _ => false, + } + } +} + // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest // of this module pub use attr_impl::ArgAttribute; @@ -127,6 +153,24 @@ impl ArgAttributes { pub fn contains(&self, attr: ArgAttribute) -> bool { self.regular.contains(attr) } + + /// Checks if these two `ArgAttributes` are equal enough to be considered "the same for all + /// function call ABIs". + pub fn eq_abi(&self, other: &Self) -> bool { + // There's only one regular attribute that matters for the call ABI: InReg. + // Everything else is things like noalias, dereferenceable, nonnull, ... + // (This also applies to pointee_size, pointee_align.) + if self.regular.contains(ArgAttribute::InReg) != other.regular.contains(ArgAttribute::InReg) + { + return false; + } + // We also compare the sign extension mode -- this could let the callee make assumptions + // about bits that conceptually were not even passed. + if self.arg_ext != other.arg_ext { + return false; + } + return true; + } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] @@ -272,6 +316,14 @@ impl CastTarget { acc.max(align) }) } + + /// Checks if these two `CastTarget` are equal enough to be considered "the same for all + /// function call ABIs". + pub fn eq_abi(&self, other: &Self) -> bool { + let CastTarget { prefix: prefix_l, rest: rest_l, attrs: attrs_l } = self; + let CastTarget { prefix: prefix_r, rest: rest_r, attrs: attrs_r } = other; + prefix_l == prefix_r && rest_l == rest_r && attrs_l.eq_abi(attrs_r) + } } /// Return value from the `homogeneous_aggregate` test function. @@ -465,6 +517,7 @@ pub struct ArgAbi<'a, Ty> { } impl<'a, Ty> ArgAbi<'a, Ty> { + /// This defines the "default ABI" for that type, that is then later adjusted in `fn_abi_adjust_for_abi`. pub fn new( cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, @@ -478,6 +531,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), ), Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), + // The `Aggregate` ABI should always be adjusted later. Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } @@ -570,6 +624,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn is_ignore(&self) -> bool { matches!(self.mode, PassMode::Ignore) } + + /// Checks if these two `ArgAbi` are equal enough to be considered "the same for all + /// function call ABIs". + pub fn eq_abi(&self, other: &Self) -> bool { + // Ideally we'd just compare the `mode`, but that is not enough -- for some modes LLVM will look + // at the type. + self.layout.eq_abi(&other.layout) && self.mode.eq_abi(&other.mode) + } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs index 0eb2309ecb2..796b752ff9d 100644 --- a/compiler/rustc_target/src/abi/call/wasm.rs +++ b/compiler/rustc_target/src/abi/call/wasm.rs @@ -61,6 +61,10 @@ where /// The purpose of this ABI is for matching the WebAssembly standard. This /// intentionally diverges from the C ABI and is specifically crafted to take /// advantage of LLVM's support of multiple returns in WebAssembly. +/// +/// This ABI is *bad*! It uses `PassMode::Direct` for `abi::Aggregate` types, which leaks LLVM +/// implementation details into the ABI. It's just hard to fix because ABIs are hard to change. +/// Also see <https://github.com/rust-lang/rust/issues/115666>. pub fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) { if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index c47767101a4..b61e02ba761 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -354,6 +354,12 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( // FIXME(associated_const_equality): Also add associated consts to // the requirements here. if item.kind == ty::AssocKind::Type { + // associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + if tcx.generics_require_sized_self(item.def_id) { + continue; + } + requirements .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args)); } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 5c2cbe39953..63ae83c8ef4 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -537,7 +537,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning. /// - /// Goals for the next step get directly added the the nested goals of the `EvalCtxt`. + /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> { let tcx = self.tcx(); let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e47e228774e..df094af4f1f 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -244,7 +244,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { // Finally we construct the actual value of the associated type. let term = match assoc_def.item.kind { ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), - ty::AssocKind::Const => bug!("associated const projection is not supported yet"), + ty::AssocKind::Const => { + if tcx.features().associated_const_equality { + bug!("associated const projection is not supported yet") + } else { + ty::EarlyBinder::bind( + ty::Const::new_error_with_message( + tcx, + tcx.type_of(assoc_def.item.def_id).instantiate_identity(), + DUMMY_SP, + "associated const projection is not supported yet", + ) + .into(), + ) + } + } ty::AssocKind::Fn => unreachable!("we should never project to a fn"), }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 457d5420ca3..746a38f956a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2920,6 +2920,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { rustc_transmute::Reason::DstIsTooBig => { format!("The size of `{src}` is smaller than the size of `{dst}`") } + rustc_transmute::Reason::SrcSizeOverflow => { + format!( + "values of the type `{src}` are too big for the current architecture" + ) + } + rustc_transmute::Reason::DstSizeOverflow => { + format!( + "values of the type `{dst}` are too big for the current architecture" + ) + } rustc_transmute::Reason::DstHasStricterAlignment { src_min_align, dst_min_align, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 611ec6b00ef..d6ac7208715 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -838,7 +838,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.param_env, real_trait_pred_and_base_ty, ); - if self.predicate_may_hold(&obligation) { + let sized_obligation = Obligation::new( + self.tcx, + obligation.cause.clone(), + obligation.param_env, + ty::TraitRef::from_lang_item( + self.tcx, + hir::LangItem::Sized, + obligation.cause.span, + [base_ty], + ), + ); + if self.predicate_may_hold(&obligation) + && self.predicate_must_hold_modulo_regions(&sized_obligation) + { let call_node = self.tcx.hir().get(*call_hir_id); let msg = "consider dereferencing here"; let is_receiver = matches!( @@ -1792,7 +1805,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } else { err.note(format!( - "`{}` is implemented for `{:?}`, but not for `{:?}`", + "`{}` is implemented for `{}`, but not for `{}`", trait_pred.print_modifiers_and_trait_path(), suggested_ty, trait_pred.skip_binder().self_ty(), diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 339baf611f3..32bbd626d4e 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -57,16 +57,12 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { let ty = OpportunisticRegionResolver::new(self).fold_ty(ty); // We do not expect existential variables in implied bounds. - // We may however encounter unconstrained lifetime variables in invalid - // code. See #110161 for context. + // We may however encounter unconstrained lifetime variables + // in very rare cases. + // + // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for + // an example. assert!(!ty.has_non_region_infer()); - if ty.has_infer() { - self.tcx.sess.delay_span_bug( - self.tcx.def_span(body_id), - "skipped implied_outlives_bounds due to unconstrained lifetimes", - ); - return vec![]; - } let mut canonical_var_values = OriginalQueryValues::default(); let canonical_ty = diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8a24f96743a..eadac70057c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -535,6 +535,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let assoc_types: Vec<_> = tcx .associated_items(trait_predicate.def_id()) .in_definition_order() + // Associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, ) diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 37e00c0e4bc..0cdc978a3d0 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -8,9 +8,6 @@ tracing = "0.1" rustc_middle = { path = "../rustc_middle" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } -rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index e8ddb0a4396..49f24f66b24 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -189,6 +189,8 @@ pub(crate) mod rustc { Unspecified, /// This error will be surfaced elsewhere by rustc, so don't surface it. UnknownLayout, + /// Overflow size + SizeOverflow, TypeError(ErrorGuaranteed), } @@ -196,6 +198,7 @@ pub(crate) mod rustc { fn from(err: &LayoutError<'tcx>) -> Self { match err { LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout, + LayoutError::SizeOverflow(..) => Self::SizeOverflow, err => unimplemented!("{:?}", err), } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 05ad4a4a12a..af2ad547480 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -64,6 +64,10 @@ pub enum Reason { SrcLayoutUnknown, /// The layout of dst is unknown DstLayoutUnknown, + /// The size of src is overflow + SrcSizeOverflow, + /// The size of dst is overflow + DstSizeOverflow, } #[cfg(feature = "rustc")] diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index b223a90f751..c0141f1f841 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -85,6 +85,8 @@ mod rustc { (_, Err(Err::UnknownLayout)) => Answer::No(Reason::DstLayoutUnknown), (Err(Err::Unspecified), _) => Answer::No(Reason::SrcIsUnspecified), (_, Err(Err::Unspecified)) => Answer::No(Reason::DstIsUnspecified), + (Err(Err::SizeOverflow), _) => Answer::No(Reason::SrcSizeOverflow), + (_, Err(Err::SizeOverflow)) => Answer::No(Reason::DstSizeOverflow), (Ok(src), Ok(dst)) => { MaybeTransmutableQuery { src, dst, scope, assume, context }.answer() } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 802391f1aad..3ffe670d87a 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -520,6 +520,8 @@ fn fn_abi_adjust_for_abi<'tcx>( _ => return, } + // `Aggregate` ABI must be adjusted to ensure that ABI-compatible Rust types are passed + // the same way. let size = arg.layout.size; if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index ed7b3496894..904f1b38740 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -7,6 +7,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, }; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, AdtDef, EarlyBinder, GenericArgsRef, ReprOptions, Ty, TyCtxt, TypeVisitableExt, }; @@ -937,7 +938,7 @@ fn record_layout_for_printing_outlined<'tcx>( // (delay format until we actually need it) let record = |kind, packed, opt_discr_size, variants| { - let type_desc = format!("{:?}", layout.ty); + let type_desc = with_no_trimmed_paths!(format!("{}", layout.ty)); cx.tcx.sess.code_stats.record_type_size( kind, type_desc, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 34fd31e49e1..1fc5d9359a4 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -19,13 +19,32 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> // needs drop. let adt_has_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant); - let res = - drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some(); + let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false) + .filter(filter_array_elements(tcx, query.param_env)) + .next() + .is_some(); debug!("needs_drop_raw({:?}) = {:?}", query, res); res } +/// HACK: in order to not mistakenly assume that `[PhantomData<T>; N]` requires drop glue +/// we check the element type for drop glue. The correct fix would be looking at the +/// entirety of the code around `needs_drop_components` and this file and come up with +/// logic that is easier to follow while not repeating any checks that may thus diverge. +fn filter_array_elements<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> impl Fn(&Result<Ty<'tcx>, AlwaysRequiresDrop>) -> bool { + move |ty| match ty { + Ok(ty) => match *ty.kind() { + ty::Array(elem, _) => tcx.needs_drop_raw(param_env.and(elem)), + _ => true, + }, + Err(AlwaysRequiresDrop) => true, + } +} + fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -37,6 +56,7 @@ fn has_significant_drop_raw<'tcx>( adt_consider_insignificant_dtor(tcx), true, ) + .filter(filter_array_elements(tcx, query.param_env)) .next() .is_some(); debug!("has_significant_drop_raw({:?}) = {:?}", query, res); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e0abc7f04f5..e348591ebba 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -574,16 +574,16 @@ rustc_index::newtype_index! { pub struct TyVid {} } -/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct IntVid { - pub index: u32, +rustc_index::newtype_index! { + /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. + #[debug_format = "?{}i"] + pub struct IntVid {} } -/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct FloatVid { - pub index: u32, +rustc_index::newtype_index! { + /// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. + #[debug_format = "?{}f"] + pub struct FloatVid {} } /// A placeholder for a type that hasn't been inferred yet. @@ -645,11 +645,11 @@ impl UnifyKey for IntVid { type Value = Option<IntVarValue>; #[inline] // make this function eligible for inlining - it is quite hot. fn index(&self) -> u32 { - self.index + self.as_u32() } #[inline] fn from_index(i: u32) -> IntVid { - IntVid { index: i } + IntVid::from_u32(i) } fn tag() -> &'static str { "IntVid" @@ -662,11 +662,11 @@ impl UnifyKey for FloatVid { type Value = Option<FloatVarValue>; #[inline] fn index(&self) -> u32 { - self.index + self.as_u32() } #[inline] fn from_index(i: u32) -> FloatVid { - FloatVid { index: i } + FloatVid::from_u32(i) } fn tag() -> &'static str { "FloatVid" @@ -770,18 +770,6 @@ impl fmt::Debug for FloatVarValue { } } -impl fmt::Debug for IntVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "?{}i", self.index) - } -} - -impl fmt::Debug for FloatVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "?{}f", self.index) - } -} - impl fmt::Debug for Variance { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { diff --git a/config.example.toml b/config.example.toml index 5c4bee87553..2e0558c3f1b 100644 --- a/config.example.toml +++ b/config.example.toml @@ -294,9 +294,11 @@ changelog-seen = 2 # Enable a build of the extended Rust tool set which is not only the compiler # but also tools such as Cargo. This will also produce "combined installers" -# which are used to install Rust and Cargo together. This is disabled by -# default. The `tools` option (immediately below) specifies which tools should -# be built if `extended = true`. +# which are used to install Rust and Cargo together. +# The `tools` (check `config.example.toml` to see its default value) option specifies +# which tools should be built if `extended = true`. +# +# This is disabled by default. #extended = false # Set of tools to be included in the installation. diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 28950a43d2d..e6c793a6516 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -753,6 +753,22 @@ impl Display for BorrowMutError { } } +// This ensures the panicking code is outlined from `borrow_mut` for `RefCell`. +#[inline(never)] +#[track_caller] +#[cold] +fn panic_already_borrowed(err: BorrowMutError) -> ! { + panic!("already borrowed: {:?}", err) +} + +// This ensures the panicking code is outlined from `borrow` for `RefCell`. +#[inline(never)] +#[track_caller] +#[cold] +fn panic_already_mutably_borrowed(err: BorrowError) -> ! { + panic!("already mutably borrowed: {:?}", err) +} + // Positive values represent the number of `Ref` active. Negative values // represent the number of `RefMut` active. Multiple `RefMut`s can only be // active at a time if they refer to distinct, nonoverlapping components of a @@ -934,7 +950,10 @@ impl<T: ?Sized> RefCell<T> { #[inline] #[track_caller] pub fn borrow(&self) -> Ref<'_, T> { - self.try_borrow().expect("already mutably borrowed") + match self.try_borrow() { + Ok(b) => b, + Err(err) => panic_already_mutably_borrowed(err), + } } /// Immutably borrows the wrapped value, returning an error if the value is currently mutably @@ -1027,7 +1046,10 @@ impl<T: ?Sized> RefCell<T> { #[inline] #[track_caller] pub fn borrow_mut(&self) -> RefMut<'_, T> { - self.try_borrow_mut().expect("already borrowed") + match self.try_borrow_mut() { + Ok(b) => b, + Err(err) => panic_already_borrowed(err), + } } /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed. @@ -2143,6 +2165,7 @@ impl<T: ?Sized> UnsafeCell<T> { #[inline(always)] #[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] + #[rustc_diagnostic_item = "unsafe_cell_raw_get"] pub const fn raw_get(this: *const Self) -> *mut T { // We can just cast the pointer from `UnsafeCell<T>` to `T` because of // #[repr(transparent)]. This exploits std's special status, there is diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index b84e4b35b1c..b6b36886604 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -87,20 +87,54 @@ impl From<char> for u128 { } } -/// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing -/// if the code point is greater than U+00FF. +/// Maps a `char` with code point in U+0000..=U+00FF to a byte in 0x00..=0xFF with same value, +/// failing if the code point is greater than U+00FF. /// /// See [`impl From<u8> for char`](char#impl-From<u8>-for-char) for details on the encoding. #[stable(feature = "u8_from_char", since = "1.59.0")] impl TryFrom<char> for u8 { type Error = TryFromCharError; + /// Tries to convert a [`char`] into a [`u8`]. + /// + /// # Examples + /// + /// ``` + /// let a = 'ÿ'; // U+00FF + /// let b = 'Ā'; // U+0100 + /// assert_eq!(u8::try_from(a), Ok(0xFF_u8)); + /// assert!(u8::try_from(b).is_err()); + /// ``` #[inline] fn try_from(c: char) -> Result<u8, Self::Error> { u8::try_from(u32::from(c)).map_err(|_| TryFromCharError(())) } } +/// Maps a `char` with code point in U+0000..=U+FFFF to a `u16` in 0x0000..=0xFFFF with same value, +/// failing if the code point is greater than U+FFFF. +/// +/// This corresponds to the UCS-2 encoding, as specified in ISO/IEC 10646:2003. +#[stable(feature = "u16_from_char", since = "CURRENT_RUSTC_VERSION")] +impl TryFrom<char> for u16 { + type Error = TryFromCharError; + + /// Tries to convert a [`char`] into a [`u16`]. + /// + /// # Examples + /// + /// ``` + /// let trans_rights = '⚧'; // U+26A7 + /// let ninjas = '🥷'; // U+1F977 + /// assert_eq!(u16::try_from(trans_rights), Ok(0x26A7_u16)); + /// assert!(u16::try_from(ninjas).is_err()); + /// ``` + #[inline] + fn try_from(c: char) -> Result<u16, Self::Error> { + u16::try_from(u32::from(c)).map_err(|_| TryFromCharError(())) + } +} + /// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF. /// /// Unicode is designed such that this effectively decodes bytes diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 515b8d20ead..4ac956e7b76 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -9,8 +9,58 @@ use crate::unicode::{self, conversions}; use super::*; impl char { + /// The lowest valid code point a `char` can have, `'\0'`. + /// + /// Unlike integer types, `char` actually has a gap in the middle, + /// meaning that the range of possible `char`s is smaller than you + /// might expect. Ranges of `char` will automatically hop this gap + /// for you: + /// + /// ``` + /// #![feature(char_min)] + /// let dist = u32::from(char::MAX) - u32::from(char::MIN); + /// let size = (char::MIN..=char::MAX).count() as u32; + /// assert!(size < dist); + /// ``` + /// + /// Despite this gap, the `MIN` and [`MAX`] values can be used as bounds for + /// all `char` values. + /// + /// [`MAX`]: char::MAX + /// + /// # Examples + /// + /// ``` + /// #![feature(char_min)] + /// # fn something_which_returns_char() -> char { 'a' } + /// let c: char = something_which_returns_char(); + /// assert!(char::MIN <= c); + /// + /// let value_at_min = u32::from(char::MIN); + /// assert_eq!(char::from_u32(value_at_min), Some('\0')); + /// ``` + #[unstable(feature = "char_min", issue = "114298")] + pub const MIN: char = '\0'; + /// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// + /// Unlike integer types, `char` actually has a gap in the middle, + /// meaning that the range of possible `char`s is smaller than you + /// might expect. Ranges of `char` will automatically hop this gap + /// for you: + /// + /// ``` + /// #![feature(char_min)] + /// let dist = u32::from(char::MAX) - u32::from(char::MIN); + /// let size = (char::MIN..=char::MAX).count() as u32; + /// assert!(size < dist); + /// ``` + /// + /// Despite this gap, the [`MIN`] and `MAX` values can be used as bounds for + /// all `char` values. + /// + /// [`MIN`]: char::MIN + /// /// # Examples /// /// ``` @@ -18,7 +68,7 @@ impl char { /// let c: char = something_which_returns_char(); /// assert!(c <= char::MAX); /// - /// let value_at_max = char::MAX as u32; + /// let value_at_max = u32::from(char::MAX); /// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); /// assert_eq!(char::from_u32(value_at_max + 1), None); /// ``` diff --git a/library/core/src/error.md b/library/core/src/error.md index 7771b8adc92..a5deb71e6b8 100644 --- a/library/core/src/error.md +++ b/library/core/src/error.md @@ -37,7 +37,7 @@ responsibilities they cover: The panic and error systems are not entirely distinct. Often times errors that are anticipated runtime failures in an API might instead represent bugs to a caller. For these situations the standard library provides APIs for -constructing panics with an `Error` as it's source. +constructing panics with an `Error` as its source. * [`Result::unwrap`] * [`Result::expect`] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index eafbaba9ef3..4c76662ac09 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1130,7 +1130,10 @@ extern "rust-intrinsic" { /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly /// unsafe**. `transmute` should be the absolute last resort. /// - /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub]. + /// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub], + /// unless the pointer was originally created *from* an integer. + /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::invalid], + /// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.) /// Any attempt to use the resulting value for integer operations will abort const-evaluation. /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the /// Rust memory model and should be avoided. See below for alternatives.) @@ -2704,9 +2707,13 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes, and must remain valid even +/// when `dst` is written for `count * size_of::<T>()` bytes. (This means if the memory ranges +/// overlap, the two pointers must not be subject to aliasing restrictions relative to each +/// other.) /// -/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even +/// when `src` is read for `count * size_of::<T>()` bytes. /// /// * Both `src` and `dst` must be properly aligned. /// diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index b99346b6ba6..cab195dad9b 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -12,7 +12,8 @@ //! //! Typical usage will look like this: //! -//! ```rust +#![cfg_attr(bootstrap, doc = "```rust,ignore")] +#![cfg_attr(not(bootstrap), doc = "```rust")] //! #![feature(core_intrinsics, custom_mir)] //! #![allow(internal_features)] //! @@ -62,7 +63,8 @@ //! //! # Examples //! -//! ```rust +#![cfg_attr(bootstrap, doc = "```rust,ignore")] +#![cfg_attr(not(bootstrap), doc = "```rust")] //! #![feature(core_intrinsics, custom_mir)] //! #![allow(internal_features)] //! @@ -317,7 +319,8 @@ define!( /// /// # Examples /// - /// ```rust + #[cfg_attr(bootstrap, doc = "```rust,ignore")] + #[cfg_attr(not(bootstrap), doc = "```rust")] /// #![allow(internal_features)] /// #![feature(custom_mir, core_intrinsics)] /// @@ -361,6 +364,11 @@ define!( #[doc(hidden)] fn __internal_make_place<T>(place: T) -> *mut T ); +define!( + "mir_debuginfo", + #[doc(hidden)] + fn __debuginfo<T>(name: &'static str, s: T) +); /// Macro for generating custom MIR. /// @@ -371,6 +379,7 @@ pub macro mir { ( $(type RET = $ret_ty:ty ;)? $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* + $(debug $dbg_name:ident => $dbg_data:expr ;)* { $($entry:tt)* @@ -394,26 +403,32 @@ pub macro mir { $( let $local_decl $(: $local_decl_ty)? ; )* - ::core::intrinsics::mir::__internal_extract_let!($($entry)*); $( ::core::intrinsics::mir::__internal_extract_let!($($block)*); )* { - // Finally, the contents of the basic blocks - ::core::intrinsics::mir::__internal_remove_let!({ - {} - { $($entry)* } - }); + // Now debuginfo $( + __debuginfo(stringify!($dbg_name), $dbg_data); + )* + + { + // Finally, the contents of the basic blocks ::core::intrinsics::mir::__internal_remove_let!({ {} - { $($block)* } + { $($entry)* } }); - )* + $( + ::core::intrinsics::mir::__internal_remove_let!({ + {} + { $($block)* } + }); + )* - RET + RET + } } } }} diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index ce18bffe714..c1d8cc4ff57 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,5 +1,7 @@ use crate::cmp; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::iter::{ + adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess, +}; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -98,26 +100,18 @@ where } } - impl_fold_via_try_fold! { fold -> try_fold } - #[inline] - fn for_each<F: FnMut(Self::Item)>(mut self, f: F) { - // The default implementation would use a unit accumulator, so we can - // avoid a stateful closure by folding over the remaining number - // of items we wish to return instead. - fn check<'a, Item>( - mut action: impl FnMut(Item) + 'a, - ) -> impl FnMut(usize, Item) -> Option<usize> + 'a { - move |more, x| { - action(x); - more.checked_sub(1) - } - } + fn fold<B, F>(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + Self::spec_fold(self, init, f) + } - let remaining = self.n; - if remaining > 0 { - self.iter.try_fold(remaining - 1, check(f)); - } + #[inline] + fn for_each<F: FnMut(Self::Item)>(self, f: F) { + Self::spec_for_each(self, f) } #[inline] @@ -249,3 +243,72 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} + +trait SpecTake: Iterator { + fn spec_fold<B, F>(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B; + + fn spec_for_each<F: FnMut(Self::Item)>(self, f: F); +} + +impl<I: Iterator> SpecTake for Take<I> { + #[inline] + default fn spec_fold<B, F>(mut self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + use crate::ops::NeverShortCircuit; + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } + + #[inline] + default fn spec_for_each<F: FnMut(Self::Item)>(mut self, f: F) { + // The default implementation would use a unit accumulator, so we can + // avoid a stateful closure by folding over the remaining number + // of items we wish to return instead. + fn check<'a, Item>( + mut action: impl FnMut(Item) + 'a, + ) -> impl FnMut(usize, Item) -> Option<usize> + 'a { + move |more, x| { + action(x); + more.checked_sub(1) + } + } + + let remaining = self.n; + if remaining > 0 { + self.iter.try_fold(remaining - 1, check(f)); + } + } +} + +impl<I: Iterator + TrustedRandomAccess> SpecTake for Take<I> { + #[inline] + fn spec_fold<B, F>(mut self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let mut acc = init; + let end = self.n.min(self.iter.size()); + for i in 0..end { + // SAFETY: i < end <= self.iter.size() and we discard the iterator at the end + let val = unsafe { self.iter.__iterator_get_unchecked(i) }; + acc = f(acc, val); + } + acc + } + + #[inline] + fn spec_for_each<F: FnMut(Self::Item)>(mut self, mut f: F) { + let end = self.n.min(self.iter.size()); + for i in 0..end { + // SAFETY: i < end <= self.iter.size() and we discard the iterator at the end + let val = unsafe { self.iter.__iterator_get_unchecked(i) }; + f(val); + } + } +} diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 462f7170a55..44feb0a5638 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,3 +1,4 @@ +use crate::ascii::Char as AsciiChar; use crate::convert::TryFrom; use crate::mem; use crate::num::NonZeroUsize; @@ -14,7 +15,7 @@ macro_rules! unsafe_impl_trusted_step { unsafe impl TrustedStep for $type {} )*}; } -unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -484,6 +485,48 @@ impl Step for char { } } +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +impl Step for AsciiChar { + #[inline] + fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> Option<usize> { + Step::steps_between(&start.to_u8(), &end.to_u8()) + } + + #[inline] + fn forward_checked(start: AsciiChar, count: usize) -> Option<AsciiChar> { + let end = Step::forward_checked(start.to_u8(), count)?; + AsciiChar::from_u8(end) + } + + #[inline] + fn backward_checked(start: AsciiChar, count: usize) -> Option<AsciiChar> { + let end = Step::backward_checked(start.to_u8(), count)?; + + // SAFETY: Values below that of a valid ASCII character are also valid ASCII + Some(unsafe { AsciiChar::from_u8_unchecked(end) }) + } + + #[inline] + unsafe fn forward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { + // SAFETY: Caller asserts that result is a valid ASCII character, + // and therefore it is a valid u8. + let end = unsafe { Step::forward_unchecked(start.to_u8(), count) }; + + // SAFETY: Caller asserts that result is a valid ASCII character. + unsafe { AsciiChar::from_u8_unchecked(end) } + } + + #[inline] + unsafe fn backward_unchecked(start: AsciiChar, count: usize) -> AsciiChar { + // SAFETY: Caller asserts that result is a valid ASCII character, + // and therefore it is a valid u8. + let end = unsafe { Step::backward_unchecked(start.to_u8(), count) }; + + // SAFETY: Caller asserts that result is a valid ASCII character. + unsafe { AsciiChar::from_u8_unchecked(end) } + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f39c4176440..c3edd3a9d7d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -20,11 +20,19 @@ // FIXME: Fill me in with more detail when the interface settles //! This library is built on the assumption of a few existing symbols: //! -//! * `memcpy`, `memcmp`, `memset`, `strlen` - These are core memory routines which are -//! often generated by LLVM. Additionally, this library can make explicit -//! calls to these functions. Their signatures are the same as found in C. -//! These functions are often provided by the system libc, but can also be -//! provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! * `memcpy`, `memmove`, `memset`, `memcmp`, `bcmp`, `strlen` - These are core memory routines +//! which are generated by Rust codegen backends. Additionally, this library can make explicit +//! calls to `strlen`. Their signatures are the same as found in C, but there are extra +//! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if +//! the `n` parameter is 0, the function is assumed to not be UB. Furthermore, for `memcpy`, if +//! source and target pointer are equal, the function is assumed to not be UB. +//! (Note that these are [standard assumptions](https://reviews.llvm.org/D86993) among compilers.) +//! These functions are often provided by the system libc, but can also be provided by the +//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). +//! Note that the library does not guarantee that it will always make these assumptions, so Rust +//! user code directly calling the C functions should follow the C specification! The advice for +//! Rust user code is to call the functions provided by this library instead (such as +//! `ptr::copy`). //! //! * `rust_begin_panic` - This function takes four arguments, a //! `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments @@ -152,7 +160,6 @@ #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_from_ref)] #![feature(const_slice_index)] -#![feature(const_slice_is_ascii)] #![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 732fcce0f29..bc701d97bbb 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1126,6 +1126,11 @@ impl<T> fmt::Debug for Discriminant<T> { /// /// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations /// +/// The value of a [`Discriminant<T>`] is independent of any *lifetimes* in `T`. As such, reading +/// or writing a `Discriminant<Foo<'a>>` as a `Discriminant<Foo<'b>>` (whether via [`transmute`] or +/// otherwise) is always sound. Note that this is **not** true for other kinds of generic +/// parameters; `Discriminant<Foo<A>>` and `Discriminant<Foo<B>>` might be incompatible. +/// /// # Examples /// /// This can be used to compare enums that carry data, while disregarding diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs index 3806977f70e..8d62684f8d3 100644 --- a/library/core/src/num/dec2flt/fpu.rs +++ b/library/core/src/num/dec2flt/fpu.rs @@ -8,6 +8,17 @@ pub use fpu_precision::set_precision; // round to 80 bits causing double rounding to happen when values are eventually represented as // 32/64 bit float values. To overcome this, the FPU control word can be set so that the // computations are performed in the desired precision. +// +// Note that normally, it is Undefined Behavior to alter the FPU control word while Rust code runs. +// The compiler assumes that the control word is always in its default state. However, in this +// particular case the semantics with the altered control word are actually *more faithful* +// to Rust semantics than the default -- arguably it is all the code that runs *outside* of the scope +// of a `set_precision` guard that is wrong. +// In other words, we are only using this to work around <https://github.com/rust-lang/rust/issues/114479>. +// Sometimes killing UB with UB actually works... +// (If this is used to set 32bit precision, there is still a risk that the compiler moves some 64bit +// operation into the scope of the `set_precision` guard. So it's not like this is totally sound. +// But it's not really any less sound than the default state of 80bit precision...) #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] mod fpu_precision { use core::arch::asm; diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs index 8589e2bbd4f..2538991564a 100644 --- a/library/core/src/num/dec2flt/number.rs +++ b/library/core/src/num/dec2flt/number.rs @@ -51,6 +51,7 @@ impl Number { /// There is an exception: disguised fast-path cases, where we can shift /// powers-of-10 from the exponent to the significant digits. pub fn try_fast_path<F: RawFloat>(&self) -> Option<F> { + // Here we need to work around <https://github.com/rust-lang/rust/issues/114479>. // The fast path crucially depends on arithmetic being rounded to the correct number of bits // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit. diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5939dedbd1d..7f8d673c179 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -41,6 +41,20 @@ macro_rules! nonzero_integers { /// with the exception that `0` is not a valid instance. #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")] /// including in FFI. + /// + /// Thanks to the [null pointer optimization], + #[doc = concat!("`", stringify!($Ty), "` and `Option<", stringify!($Ty), ">`")] + /// are guaranteed to have the same size and alignment: + /// + /// ``` + /// # use std::mem::{size_of, align_of}; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// + #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::<Option<", stringify!($Ty), ">>());")] + #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")] + /// ``` + /// + /// [null pointer optimization]: crate::option#representation #[$stability] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index ba5e6ddc752..cc596293ca3 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -11,7 +11,7 @@ use crate::hash::Hash; /// The `..` syntax is a `RangeFull`: /// /// ``` -/// assert_eq!((..), std::ops::RangeFull); +/// assert_eq!(.., std::ops::RangeFull); /// ``` /// /// It does not have an [`IntoIterator`] implementation, so you can't use it in diff --git a/library/core/src/option.rs b/library/core/src/option.rs index becb6330997..f2909a81d49 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -119,7 +119,7 @@ //! # Representation //! //! Rust guarantees to optimize the following types `T` such that -//! [`Option<T>`] has the same size as `T`: +//! [`Option<T>`] has the same size and alignment as `T`: //! //! * [`Box<U>`] //! * `&U` diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 01e36044899..41e67fd8435 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -795,7 +795,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid] for both reads and writes. +/// * Both `x` and `y` must be [valid] for both reads and writes. They must remain valid even when the +/// other pointer is written. (This means if the memory ranges overlap, the two pointers must not +/// be subject to aliasing restrictions relative to each other.) /// /// * Both `x` and `y` must be properly aligned. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9dbb3f9d322..6d623b82c1c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -109,7 +109,7 @@ impl<T: ?Sized> *mut T { /// with [`cast_mut`] on `*const T` and may have documentation value if used instead of implicit /// coercion. /// - /// [`cast_mut`]: #method.cast_mut + /// [`cast_mut`]: pointer::cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_diagnostic_item = "ptr_cast_const"] @@ -121,7 +121,7 @@ impl<T: ?Sized> *mut T { /// Casts a pointer to its raw bits. /// /// This is equivalent to `as usize`, but is more specific to enhance readability. - /// The inverse method is [`from_bits`](#method.from_bits-1). + /// The inverse method is [`from_bits`](pointer#method.from_bits-1). /// /// In particular, `*p as usize` and `p as usize` will both compile for /// pointers to numeric types but do very different things, so using this @@ -157,7 +157,7 @@ impl<T: ?Sized> *mut T { /// Creates a pointer from its raw bits. /// /// This is equivalent to `as *mut T`, but is more specific to enhance readability. - /// The inverse method is [`to_bits`](#method.to_bits-1). + /// The inverse method is [`to_bits`](pointer#method.to_bits-1). /// /// # Examples /// @@ -307,7 +307,7 @@ impl<T: ?Sized> *mut T { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// [`as_mut`]: #method.as_mut /// /// # Safety @@ -373,7 +373,7 @@ impl<T: ?Sized> *mut T { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Safety @@ -628,7 +628,7 @@ impl<T: ?Sized> *mut T { /// For the shared counterpart see [`as_ref`]. /// /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// /// # Safety /// @@ -693,7 +693,7 @@ impl<T: ?Sized> *mut T { /// For the shared counterpart see [`as_uninit_ref`]. /// /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: #method.as_uninit_ref-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 /// /// # Safety /// @@ -783,7 +783,7 @@ impl<T: ?Sized> *mut T { /// /// This function is the inverse of [`offset`]. /// - /// [`offset`]: #method.offset-1 + /// [`offset`]: pointer#method.offset-1 /// /// # Safety /// @@ -2064,7 +2064,7 @@ impl<T> *mut [T] { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: #method.as_ref-1 + /// [`as_ref`]: pointer#method.as_ref-1 /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut /// /// # Safety diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e0fd347a049..6b3c4343ed3 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -43,9 +43,27 @@ use crate::slice::{self, SliceIndex}; /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr` /// is never used for mutation. /// +/// # Representation +/// +/// Thanks to the [null pointer optimization], +/// `NonNull<T>` and `Option<NonNull<T>>` +/// are guaranteed to have the same size and alignment: +/// +/// ``` +/// # use std::mem::{size_of, align_of}; +/// use std::ptr::NonNull; +/// +/// assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>()); +/// assert_eq!(align_of::<NonNull<i16>>(), align_of::<Option<NonNull<i16>>>()); +/// +/// assert_eq!(size_of::<NonNull<str>>(), size_of::<Option<NonNull<str>>>()); +/// assert_eq!(align_of::<NonNull<str>>(), align_of::<Option<NonNull<str>>>()); +/// ``` +/// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html /// [`PhantomData`]: crate::marker::PhantomData /// [`UnsafeCell<T>`]: crate::cell::UnsafeCell +/// [null pointer optimization]: crate::option#representation #[stable(feature = "nonnull", since = "1.25.0")] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index f3311f76a7f..5dc53caba0d 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -10,7 +10,7 @@ use crate::ops; impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")] + #[rustc_const_stable(feature = "const_slice_is_ascii", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn is_ascii(&self) -> bool { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 23cebdb6c3b..d5b0ab92c09 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2322,7 +2322,7 @@ impl str { /// assert!(!non_ascii.is_ascii()); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")] + #[rustc_const_stable(feature = "const_slice_is_ascii", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn is_ascii(&self) -> bool { diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 0a77ecddb84..5b87d6c1fa0 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -1,5 +1,6 @@ -use core::num::NonZeroUsize; use super::*; +use core::ascii::Char as AsciiChar; +use core::num::NonZeroUsize; #[test] fn test_range() { @@ -40,6 +41,21 @@ fn test_char_range() { } #[test] +fn test_ascii_char_range() { + let from = AsciiChar::Null; + let to = AsciiChar::Delete; + assert!((from..=to).eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8))); + assert!((from..=to).rev().eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8).rev())); + + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).count(), 26); + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).count(), 26); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).count(), 10); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).size_hint(), (10, Some(10))); +} + +#[test] fn test_range_exhaustion() { let mut r = 10..10; assert!(r.is_empty()); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7a6def37a55..17011b845cf 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -2,6 +2,8 @@ #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] +#![feature(ascii_char)] +#![feature(ascii_char_variants)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_align_offset)] diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index ee9f6ed087c..97e78d17786 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -132,8 +132,8 @@ //! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of //! UTF-8; see [`OsString`] for more details on its encoding on different platforms. //! -//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_os_str_bytes`] and -//! [`OsStr::from_os_str_bytes_unchecked`]. +//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_encoded_bytes`] and +//! [`OsStr::from_encoded_bytes_unchecked`]. //! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 43cecb19b14..93b9bf0cc20 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -154,36 +154,34 @@ impl OsString { /// # Safety /// /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of - /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version + /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same rust version /// built for the same target platform. For example, reconstructing an `OsString` from bytes sent /// over the network or stored in a file will likely violate these safety rules. /// - /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be /// split either immediately before or immediately after any valid non-empty UTF-8 substring. /// /// # Example /// /// ``` - /// #![feature(os_str_bytes)] - /// /// use std::ffi::OsStr; /// /// let os_str = OsStr::new("Mary had a little lamb"); - /// let bytes = os_str.as_os_str_bytes(); + /// let bytes = os_str.as_encoded_bytes(); /// let words = bytes.split(|b| *b == b' '); /// let words: Vec<&OsStr> = words.map(|word| { /// // SAFETY: - /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes` + /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes` /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring - /// unsafe { OsStr::from_os_str_bytes_unchecked(word) } + /// unsafe { OsStr::from_encoded_bytes_unchecked(word) } /// }).collect(); /// ``` /// /// [conversions]: super#conversions #[inline] - #[unstable(feature = "os_str_bytes", issue = "111544")] - pub unsafe fn from_os_str_bytes_unchecked(bytes: Vec<u8>) -> Self { - OsString { inner: Buf::from_os_str_bytes_unchecked(bytes) } + #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec<u8>) -> Self { + OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) } } /// Converts to an [`OsStr`] slice. @@ -205,7 +203,7 @@ impl OsString { } /// Converts the `OsString` into a byte slice. To convert the byte slice back into an - /// `OsString`, use the [`OsStr::from_os_str_bytes_unchecked`] function. + /// `OsString`, use the [`OsStr::from_encoded_bytes_unchecked`] function. /// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit @@ -219,9 +217,9 @@ impl OsString { /// /// [`std::ffi`]: crate::ffi #[inline] - #[unstable(feature = "os_str_bytes", issue = "111544")] - pub fn into_os_str_bytes(self) -> Vec<u8> { - self.inner.into_os_str_bytes() + #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + pub fn into_encoded_bytes(self) -> Vec<u8> { + self.inner.into_encoded_bytes() } /// Converts the `OsString` into a [`String`] if it contains valid Unicode data. @@ -745,36 +743,34 @@ impl OsStr { /// # Safety /// /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of - /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version + /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same rust version /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent /// over the network or stored in a file will likely violate these safety rules. /// - /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be /// split either immediately before or immediately after any valid non-empty UTF-8 substring. /// /// # Example /// /// ``` - /// #![feature(os_str_bytes)] - /// /// use std::ffi::OsStr; /// /// let os_str = OsStr::new("Mary had a little lamb"); - /// let bytes = os_str.as_os_str_bytes(); + /// let bytes = os_str.as_encoded_bytes(); /// let words = bytes.split(|b| *b == b' '); /// let words: Vec<&OsStr> = words.map(|word| { /// // SAFETY: - /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes` + /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes` /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring - /// unsafe { OsStr::from_os_str_bytes_unchecked(word) } + /// unsafe { OsStr::from_encoded_bytes_unchecked(word) } /// }).collect(); /// ``` /// /// [conversions]: super#conversions #[inline] - #[unstable(feature = "os_str_bytes", issue = "111544")] - pub unsafe fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self { - Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes)) + #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self { + Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes)) } #[inline] @@ -948,7 +944,7 @@ impl OsStr { } /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS - /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function. + /// string slice, use the [`OsStr::from_encoded_bytes_unchecked`] function. /// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit @@ -962,9 +958,9 @@ impl OsStr { /// /// [`std::ffi`]: crate::ffi #[inline] - #[unstable(feature = "os_str_bytes", issue = "111544")] - pub fn as_os_str_bytes(&self) -> &[u8] { - self.inner.as_os_str_bytes() + #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + pub fn as_encoded_bytes(&self) -> &[u8] { + self.inner.as_encoded_bytes() } /// Converts this string to its ASCII lower case equivalent in-place. @@ -1270,7 +1266,7 @@ impl Default for &OsStr { impl PartialEq for OsStr { #[inline] fn eq(&self, other: &OsStr) -> bool { - self.as_os_str_bytes().eq(other.as_os_str_bytes()) + self.as_encoded_bytes().eq(other.as_encoded_bytes()) } } @@ -1297,23 +1293,23 @@ impl Eq for OsStr {} impl PartialOrd for OsStr { #[inline] fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> { - self.as_os_str_bytes().partial_cmp(other.as_os_str_bytes()) + self.as_encoded_bytes().partial_cmp(other.as_encoded_bytes()) } #[inline] fn lt(&self, other: &OsStr) -> bool { - self.as_os_str_bytes().lt(other.as_os_str_bytes()) + self.as_encoded_bytes().lt(other.as_encoded_bytes()) } #[inline] fn le(&self, other: &OsStr) -> bool { - self.as_os_str_bytes().le(other.as_os_str_bytes()) + self.as_encoded_bytes().le(other.as_encoded_bytes()) } #[inline] fn gt(&self, other: &OsStr) -> bool { - self.as_os_str_bytes().gt(other.as_os_str_bytes()) + self.as_encoded_bytes().gt(other.as_encoded_bytes()) } #[inline] fn ge(&self, other: &OsStr) -> bool { - self.as_os_str_bytes().ge(other.as_os_str_bytes()) + self.as_encoded_bytes().ge(other.as_encoded_bytes()) } } @@ -1332,7 +1328,7 @@ impl PartialOrd<str> for OsStr { impl Ord for OsStr { #[inline] fn cmp(&self, other: &OsStr) -> cmp::Ordering { - self.as_os_str_bytes().cmp(other.as_os_str_bytes()) + self.as_encoded_bytes().cmp(other.as_encoded_bytes()) } } @@ -1382,7 +1378,7 @@ impl_cmp!(Cow<'a, OsStr>, OsString); impl Hash for OsStr { #[inline] fn hash<H: Hasher>(&self, state: &mut H) { - self.as_os_str_bytes().hash(state) + self.as_encoded_bytes().hash(state) } } diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 0f04f291117..95ba82e1e07 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -237,7 +237,7 @@ impl<W: ?Sized + Write> BufWriter<W> { )); } Ok(n) => guard.consume(n), - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 3322940d245..57d226a3771 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,4 +1,4 @@ -use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; +use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE}; use crate::alloc::Allocator; use crate::cmp; use crate::collections::VecDeque; @@ -30,6 +30,7 @@ mod tests; /// /// [`read`]: Read::read /// [`write`]: Write::write +/// [`ErrorKind::Interrupted`]: crate::io::ErrorKind::Interrupted /// /// # Examples /// @@ -163,7 +164,7 @@ where // from adding I: Read match self.read(&mut []) { Ok(_) => {} - Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) if e.is_interrupted() => continue, Err(e) => return Err(e), } let buf = self.buffer(); @@ -243,7 +244,7 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> { // Read again if the buffer still has enough capacity, as BufWriter itself would do // This will occur if the reader returns short reads } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } else { @@ -275,7 +276,7 @@ impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> { let mut buf: BorrowedBuf<'_> = self.spare_capacity_mut().into(); match reader.read_buf(buf.unfilled()) { Ok(()) => {} - Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) if e.is_interrupted() => continue, Err(e) => return Err(e), }; @@ -307,7 +308,7 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>( loop { match reader.read_buf(buf.unfilled()) { Ok(()) => {} - Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) if e.is_interrupted() => continue, Err(e) => return Err(e), }; diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index d6fce4ee78f..4eb0d92b38b 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -102,7 +102,7 @@ enum ErrorData<C> { /// /// [`into`]: Into::into #[unstable(feature = "raw_os_error_ty", issue = "107792")] -pub type RawOsError = i32; +pub type RawOsError = sys::RawOsError; // `#[repr(align(4))]` is probably redundant, it should have that value or // higher already. We include it just because repr_bitpacked.rs's encoding @@ -527,8 +527,6 @@ impl Error { /// # Examples /// /// ``` - /// #![feature(io_error_other)] - /// /// use std::io::Error; /// /// // errors can be created from strings @@ -537,7 +535,7 @@ impl Error { /// // errors can also be created from other errors /// let custom_error2 = Error::other(custom_error); /// ``` - #[unstable(feature = "io_error_other", issue = "91946")] + #[stable(feature = "io_error_other", since = "CURRENT_RUSTC_VERSION")] pub fn other<E>(error: E) -> Error where E: Into<Box<dyn error::Error + Send + Sync>>, diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index f94f88bac41..6e7366b3635 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -374,9 +374,6 @@ static_assert!((TAG_MASK + 1).is_power_of_two()); static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1); static_assert!(align_of::<Custom>() >= TAG_MASK + 1); -// `RawOsError` must be an alias for `i32`. -const _: fn(RawOsError) -> i32 = |os| os; - static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE); static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM); static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e89843b5703..eca64fb6063 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1647,7 +1647,7 @@ pub trait Write { )); } Ok(n) => IoSlice::advance_slices(&mut bufs, n), - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 029de8fbf76..b6dc1a062ed 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -123,7 +123,7 @@ pub trait FileExt { buf = &mut tmp[n..]; offset += n as u64; } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } @@ -258,7 +258,7 @@ pub trait FileExt { buf = &buf[n..]; offset += n as u64 } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 160c8f1eca2..3da8c835511 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -82,7 +82,7 @@ pub trait FileExt { buf = &mut tmp[n..]; offset += n as u64; } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } @@ -162,7 +162,7 @@ pub trait FileExt { buf = &buf[n..]; offset += n as u64 } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 5842c096f1a..60562f64c90 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -193,7 +193,7 @@ impl<'a> Prefix<'a> { fn len(&self) -> usize { use self::Prefix::*; fn os_str_len(s: &OsStr) -> usize { - s.as_os_str_bytes().len() + s.as_encoded_bytes().len() } match *self { Verbatim(x) => 4 + os_str_len(x), @@ -316,7 +316,7 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool { // basic workhorse for splitting stem and extension fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - if file.as_os_str_bytes() == b".." { + if file.as_encoded_bytes() == b".." { return (Some(file), None); } @@ -324,7 +324,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { // and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = file.as_os_str_bytes().rsplitn(2, |b| *b == b'.'); + let mut iter = file.as_encoded_bytes().rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") { @@ -332,15 +332,15 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { } else { unsafe { ( - before.map(|s| OsStr::from_os_str_bytes_unchecked(s)), - after.map(|s| OsStr::from_os_str_bytes_unchecked(s)), + before.map(|s| OsStr::from_encoded_bytes_unchecked(s)), + after.map(|s| OsStr::from_encoded_bytes_unchecked(s)), ) } } } fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { - let slice = file.as_os_str_bytes(); + let slice = file.as_encoded_bytes(); if slice == b".." { return (file, None); } @@ -357,8 +357,8 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { let after = &slice[i + 1..]; unsafe { ( - OsStr::from_os_str_bytes_unchecked(before), - Some(OsStr::from_os_str_bytes_unchecked(after)), + OsStr::from_encoded_bytes_unchecked(before), + Some(OsStr::from_encoded_bytes_unchecked(after)), ) } } @@ -739,7 +739,7 @@ impl<'a> Components<'a> { // separately via `include_cur_dir` b".." => Some(Component::ParentDir), b"" => None, - _ => Some(Component::Normal(unsafe { OsStr::from_os_str_bytes_unchecked(comp) })), + _ => Some(Component::Normal(unsafe { OsStr::from_encoded_bytes_unchecked(comp) })), } } @@ -896,7 +896,7 @@ impl<'a> Iterator for Components<'a> { let raw = &self.path[..self.prefix_len()]; self.path = &self.path[self.prefix_len()..]; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { OsStr::from_os_str_bytes_unchecked(raw) }, + raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) }, parsed: self.prefix.unwrap(), })); } @@ -968,7 +968,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { - raw: unsafe { OsStr::from_os_str_bytes_unchecked(self.path) }, + raw: unsafe { OsStr::from_encoded_bytes_unchecked(self.path) }, parsed: self.prefix.unwrap(), })); } @@ -1477,17 +1477,17 @@ impl PathBuf { fn _set_extension(&mut self, extension: &OsStr) -> bool { let file_stem = match self.file_stem() { None => return false, - Some(f) => f.as_os_str_bytes(), + Some(f) => f.as_encoded_bytes(), }; // truncate until right after the file stem let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr(); - let start = self.inner.as_os_str_bytes().as_ptr().addr(); + let start = self.inner.as_encoded_bytes().as_ptr().addr(); let v = self.as_mut_vec(); v.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension.as_os_str_bytes(); + let new = extension.as_encoded_bytes(); if !new.is_empty() { v.reserve_exact(new.len() + 1); v.push(b'.'); @@ -2007,11 +2007,11 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - unsafe { Path::new(OsStr::from_os_str_bytes_unchecked(s)) } + unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { - self.inner.as_os_str_bytes() + self.inner.as_encoded_bytes() } /// Directly wraps a string slice as a `Path` slice. @@ -2609,7 +2609,7 @@ impl Path { fn _with_extension(&self, extension: &OsStr) -> PathBuf { let self_len = self.as_os_str().len(); - let self_bytes = self.as_os_str().as_os_str_bytes(); + let self_bytes = self.as_os_str().as_encoded_bytes(); let (new_capacity, slice_to_copy) = match self.extension() { None => { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 7380b45b00f..762a1e9b408 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1501,6 +1501,66 @@ impl From<fs::File> for Stdio { } } +#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")] +impl From<io::Stdout> for Stdio { + /// Redirect command stdout/stderr to our stdout + /// + /// # Examples + /// + /// ```rust + /// #![feature(exit_status_error)] + /// use std::io; + /// use std::process::Command; + /// + /// # fn test() -> Result<(), Box<dyn std::error::Error>> { + /// let output = Command::new("whoami") + // "whoami" is a command which exists on both Unix and Windows, + // and which succeeds, producing some stdout output but no stderr. + /// .stdout(io::stdout()) + /// .output()?; + /// output.status.exit_ok()?; + /// assert!(output.stdout.is_empty()); + /// # Ok(()) + /// # } + /// # + /// # if cfg!(unix) { + /// # test().unwrap(); + /// # } + /// ``` + fn from(inherit: io::Stdout) -> Stdio { + Stdio::from_inner(inherit.into()) + } +} + +#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")] +impl From<io::Stderr> for Stdio { + /// Redirect command stdout/stderr to our stderr + /// + /// # Examples + /// + /// ```rust + /// #![feature(exit_status_error)] + /// use std::io; + /// use std::process::Command; + /// + /// # fn test() -> Result<(), Box<dyn std::error::Error>> { + /// let output = Command::new("whoami") + /// .stdout(io::stderr()) + /// .output()?; + /// output.status.exit_ok()?; + /// assert!(output.stdout.is_empty()); + /// # Ok(()) + /// # } + /// # + /// # if cfg!(unix) { + /// # test().unwrap(); + /// # } + /// ``` + fn from(inherit: io::Stderr) -> Stdio { + Stdio::from_inner(inherit.into()) + } +} + /// Describes the result of a process after it has terminated. /// /// This `struct` is used to represent the exit status or other termination of a child process. diff --git a/library/std/src/sys/common/small_c_string.rs b/library/std/src/sys/common/small_c_string.rs index 963d17a47e4..af9b18e372d 100644 --- a/library/std/src/sys/common/small_c_string.rs +++ b/library/std/src/sys/common/small_c_string.rs @@ -19,7 +19,7 @@ pub fn run_path_with_cstr<T, F>(path: &Path, f: F) -> io::Result<T> where F: FnOnce(&CStr) -> io::Result<T>, { - run_with_cstr(path.as_os_str().as_os_str_bytes(), f) + run_with_cstr(path.as_os_str().as_encoded_bytes(), f) } #[inline] diff --git a/library/std/src/sys/common/tests.rs b/library/std/src/sys/common/tests.rs index 0a1cbcbe8ef..32dc18ee1cf 100644 --- a/library/std/src/sys/common/tests.rs +++ b/library/std/src/sys/common/tests.rs @@ -8,7 +8,7 @@ use core::iter::repeat; fn stack_allocation_works() { let path = Path::new("abc"); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); @@ -25,7 +25,7 @@ fn heap_allocation_works() { let path = repeat("a").take(384).collect::<String>(); let path = Path::new(&path); let result = run_path_with_cstr(path, |p| { - assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap()); + assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap()); Ok(42) }); assert_eq!(result.unwrap(), 42); diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 744cb0c911b..abd7eb353f8 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -200,7 +200,7 @@ where { loop { match cvt(f()) { - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} other => return other, } } diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index bffda7a8139..a564f1698ba 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -102,7 +102,7 @@ impl Socket { match unsafe { netc::poll(&mut pollfd, 1, timeout) } { -1 => { let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { + if !err.is_interrupted() { return Err(err); } } diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index beea3f23c2d..63bd783746b 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -110,3 +110,5 @@ pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 { pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 { log_fn(n) } + +pub type RawOsError = i32; diff --git a/library/std/src/sys/solid/error.rs b/library/std/src/sys/solid/error.rs index d1877a8bcd2..547b4f3a984 100644 --- a/library/std/src/sys/solid/error.rs +++ b/library/std/src/sys/solid/error.rs @@ -31,11 +31,6 @@ pub fn error_name(er: abi::ER) -> Option<&'static str> { } } -#[inline] -fn is_interrupted(er: abi::ER) -> bool { - false -} - pub fn decode_error_kind(er: abi::ER) -> ErrorKind { match er { // Success diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index e7029174511..5af83653cf8 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -74,7 +74,7 @@ pub fn unsupported_err() -> crate::io::Error { #[inline] pub fn is_interrupted(code: i32) -> bool { - error::is_interrupted(code) + net::is_interrupted(code) } pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs index bdd64ab02b7..6adced787f3 100644 --- a/library/std/src/sys/solid/net.rs +++ b/library/std/src/sys/solid/net.rs @@ -183,8 +183,7 @@ pub(super) fn error_name(er: abi::ER) -> Option<&'static str> { #[inline] pub fn is_interrupted(er: abi::ER) -> bool { - let errno = netc::SOLID_NET_ERR_BASE - er; - errno as libc::c_int == libc::EINTR + er == netc::SOLID_NET_ERR_BASE - libc::EINTR } pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index a5604c92a80..61ea87a5b0c 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -792,7 +792,7 @@ impl Drop for Dir { fn drop(&mut self) { let r = unsafe { libc::closedir(self.0) }; assert!( - r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted, + r == 0 || crate::io::Error::last_os_error().is_interrupted(), "unexpected error during closedir: {:?}", crate::io::Error::last_os_error() ); diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 6d743903314..692d3ab7cc9 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -320,7 +320,7 @@ where { loop { match cvt(f()) { - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} other => return other, } } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 7258c222a6c..ade8c75a657 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -184,7 +184,7 @@ impl Socket { match unsafe { libc::poll(&mut pollfd, 1, timeout) } { -1 => { let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { + if !err.is_interrupted() { return Err(err); } } diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index 463b0a27515..7bd2f656a24 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -97,12 +97,12 @@ impl AsInner<[u8]> for Buf { impl Buf { #[inline] - pub fn into_os_str_bytes(self) -> Vec<u8> { + pub fn into_encoded_bytes(self) -> Vec<u8> { self.inner } #[inline] - pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self { + pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self { Self { inner: s } } @@ -203,18 +203,18 @@ impl Buf { impl Slice { #[inline] - pub fn as_os_str_bytes(&self) -> &[u8] { + pub fn as_encoded_bytes(&self) -> &[u8] { &self.inner } #[inline] - pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { + pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice { unsafe { mem::transmute(s) } } #[inline] pub fn from_str(s: &str) -> &Slice { - unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) } + unsafe { Slice::from_encoded_bytes_unchecked(s.as_bytes()) } } pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs index 91bc0e61a4a..e2a99045e41 100644 --- a/library/std/src/sys/unix/os_str/tests.rs +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn slice_debug_output() { - let input = unsafe { Slice::from_os_str_bytes_unchecked(b"\xF0hello,\tworld") }; + let input = unsafe { Slice::from_encoded_bytes_unchecked(b"\xF0hello,\tworld") }; let expected = r#""\xF0hello,\tworld""#; let output = format!("{input:?}"); @@ -12,6 +12,6 @@ fn slice_debug_output() { #[test] fn display() { assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe { - Slice::from_os_str_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + Slice::from_encoded_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() },); } diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs index 935245f637b..837f68d3eaf 100644 --- a/library/std/src/sys/unix/path.rs +++ b/library/std/src/sys/unix/path.rs @@ -30,7 +30,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { // Get the components, skipping the redundant leading "." component if it exists. let mut components = path.strip_prefix(".").unwrap_or(path).components(); - let path_os = path.as_os_str().as_os_str_bytes(); + let path_os = path.as_os_str().as_encoded_bytes(); let mut normalized = if path.is_absolute() { // "If a pathname begins with two successive <slash> characters, the diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 640648e8707..f729da44774 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -13,7 +13,7 @@ use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; use crate::sys_common::process::{CommandEnv, CommandEnvs}; -use crate::sys_common::IntoInner; +use crate::sys_common::{FromInner, IntoInner}; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -150,6 +150,7 @@ pub enum Stdio { Null, MakePipe, Fd(FileDesc), + StaticFd(BorrowedFd<'static>), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -164,9 +165,9 @@ pub enum ProgramKind { impl ProgramKind { fn new(program: &OsStr) -> Self { - if program.as_os_str_bytes().starts_with(b"/") { + if program.as_encoded_bytes().starts_with(b"/") { Self::Absolute - } else if program.as_os_str_bytes().contains(&b'/') { + } else if program.as_encoded_bytes().contains(&b'/') { // If the program has more than one component in it, it is a relative path. Self::Relative } else { @@ -463,6 +464,11 @@ impl Stdio { } } + Stdio::StaticFd(fd) => { + let fd = FileDesc::from_inner(fd.try_clone_to_owned()?); + Ok((ChildStdio::Owned(fd), None)) + } + Stdio::MakePipe => { let (reader, writer) = pipe::anon_pipe()?; let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; @@ -497,6 +503,28 @@ impl From<File> for Stdio { } } +impl From<io::Stdout> for Stdio { + fn from(_: io::Stdout) -> Stdio { + // This ought really to be is Stdio::StaticFd(input_argument.as_fd()). + // But AsFd::as_fd takes its argument by reference, and yields + // a bounded lifetime, so it's no use here. There is no AsStaticFd. + // + // Additionally AsFd is only implemented for the *locked* versions. + // We don't want to lock them here. (The implications of not locking + // are the same as those for process::Stdio::inherit().) + // + // Arguably the hypothetical AsStaticFd and AsFd<'static> + // should be implemented for io::Stdout, not just for StdoutLocked. + Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }) + } +} + +impl From<io::Stderr> for Stdio { + fn from(_: io::Stderr) -> Stdio { + Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) }) + } +} + impl ChildStdio { pub fn fd(&self) -> Option<c_int> { match *self { diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 3963e7f52d5..75b54064501 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -165,7 +165,7 @@ impl Command { assert!(p.wait().is_ok(), "wait() should either return Ok or panic"); return Err(Error::from_raw_os_error(errno)); } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.is_interrupted() => {} Err(e) => { assert!(p.wait().is_ok(), "wait() should either return Ok or panic"); panic!("the CLOEXEC pipe failed: {e:?}") diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 4f2d9cf3655..7c242d4d334 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -182,6 +182,9 @@ impl Thread { } if let Some(f) = pthread_setname_np.get() { + #[cfg(target_os = "nto")] + let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name); + let res = unsafe { f(libc::pthread_self(), name.as_ptr()) }; debug_assert_eq!(res, 0); } @@ -290,6 +293,7 @@ impl Drop for Thread { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "nto", ))] fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { let mut result = [0; MAX_WITH_NUL]; diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 77b675aaa4e..a639afcc674 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -27,6 +27,8 @@ pub struct StdioPipes { pub stderr: Option<AnonPipe>, } +// FIXME: This should be a unit struct, so we can always construct it +// The value here should be never used, since we cannot spawn processes. pub enum Stdio { Inherit, Null, @@ -87,8 +89,26 @@ impl From<AnonPipe> for Stdio { } } +impl From<io::Stdout> for Stdio { + fn from(_: io::Stdout) -> Stdio { + // FIXME: This is wrong. + // Instead, the Stdio we have here should be a unit struct. + panic!("unsupported") + } +} + +impl From<io::Stderr> for Stdio { + fn from(_: io::Stderr) -> Stdio { + // FIXME: This is wrong. + // Instead, the Stdio we have here should be a unit struct. + panic!("unsupported") + } +} + impl From<File> for Stdio { fn from(_file: File) -> Stdio { + // FIXME: This is wrong. + // Instead, the Stdio we have here should be a unit struct. panic!("unsupported") } } diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 6b597f499bc..ee7dba6e5b3 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -226,7 +226,7 @@ pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> i // that it actually gets passed through on the command line or otherwise // it will be dropped entirely when parsed on the other end. ensure_no_nuls(arg)?; - let arg_bytes = arg.as_os_str_bytes(); + let arg_bytes = arg.as_encoded_bytes(); let (quote, escape) = match quote { Quote::Always => (true, true), Quote::Auto => { @@ -298,7 +298,7 @@ pub(crate) fn make_bat_command_line( const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>"; let force_quotes = match arg { Arg::Regular(arg) if !force_quotes => { - arg.as_os_str_bytes().iter().any(|c| SPECIAL.contains(c)) + arg.as_encoded_bytes().iter().any(|c| SPECIAL.contains(c)) } _ => force_quotes, }; diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 4708657a907..237854fac4e 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -64,12 +64,12 @@ impl fmt::Display for Slice { impl Buf { #[inline] - pub fn into_os_str_bytes(self) -> Vec<u8> { + pub fn into_encoded_bytes(self) -> Vec<u8> { self.inner.into_bytes() } #[inline] - pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self { + pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self { Self { inner: Wtf8Buf::from_bytes_unchecked(s) } } @@ -162,12 +162,12 @@ impl Buf { impl Slice { #[inline] - pub fn as_os_str_bytes(&self) -> &[u8] { + pub fn as_encoded_bytes(&self) -> &[u8] { self.inner.as_bytes() } #[inline] - pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice { + pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice { mem::transmute(Wtf8::from_bytes_unchecked(s)) } diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index c9c2d10e6c4..8c0e07b3566 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -22,12 +22,12 @@ pub fn is_verbatim_sep(b: u8) -> bool { /// Returns true if `path` looks like a lone filename. pub(crate) fn is_file_name(path: &OsStr) -> bool { - !path.as_os_str_bytes().iter().copied().any(is_sep_byte) + !path.as_encoded_bytes().iter().copied().any(is_sep_byte) } pub(crate) fn has_trailing_slash(path: &OsStr) -> bool { - let is_verbatim = path.as_os_str_bytes().starts_with(br"\\?\"); + let is_verbatim = path.as_encoded_bytes().starts_with(br"\\?\"); let is_separator = if is_verbatim { is_verbatim_sep } else { is_sep_byte }; - if let Some(&c) = path.as_os_str_bytes().last() { is_separator(c) } else { false } + if let Some(&c) = path.as_encoded_bytes().last() { is_separator(c) } else { false } } /// Appends a suffix to a path. @@ -49,7 +49,7 @@ impl<'a, const LEN: usize> PrefixParser<'a, LEN> { fn get_prefix(path: &OsStr) -> [u8; LEN] { let mut prefix = [0; LEN]; // SAFETY: Only ASCII characters are modified. - for (i, &ch) in path.as_os_str_bytes().iter().take(LEN).enumerate() { + for (i, &ch) in path.as_encoded_bytes().iter().take(LEN).enumerate() { prefix[i] = if ch == b'/' { b'\\' } else { ch }; } prefix @@ -82,7 +82,7 @@ impl<'a> PrefixParserSlice<'a, '_> { } fn prefix_bytes(&self) -> &'a [u8] { - &self.path.as_os_str_bytes()[..self.index] + &self.path.as_encoded_bytes()[..self.index] } fn finish(self) -> &'a OsStr { @@ -90,7 +90,7 @@ impl<'a> PrefixParserSlice<'a, '_> { // &[u8] and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced only // from ASCII-bounded slices of existing &OsStr values. - unsafe { OsStr::from_os_str_bytes_unchecked(&self.path.as_os_str_bytes()[self.index..]) } + unsafe { OsStr::from_encoded_bytes_unchecked(&self.path.as_encoded_bytes()[self.index..]) } } } @@ -162,7 +162,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> { drive.is_ascii_alphabetic() } - match path.as_os_str_bytes() { + match path.as_encoded_bytes() { [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), _ => None, } @@ -171,7 +171,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> { // Parses a drive prefix exactly, e.g. "C:" fn parse_drive_exact(path: &OsStr) -> Option<u8> { // only parse two bytes: the drive letter and the drive separator - if path.as_os_str_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { + if path.as_encoded_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { parse_drive(path) } else { None @@ -185,15 +185,15 @@ fn parse_drive_exact(path: &OsStr) -> Option<u8> { fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; - match path.as_os_str_bytes().iter().position(|&x| separator(x)) { + match path.as_encoded_bytes().iter().position(|&x| separator(x)) { Some(separator_start) => { let separator_end = separator_start + 1; - let component = &path.as_os_str_bytes()[..separator_start]; + let component = &path.as_encoded_bytes()[..separator_start]; // Panic safe // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. - let path = &path.as_os_str_bytes()[separator_end..]; + let path = &path.as_encoded_bytes()[separator_end..]; // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') // is encoded in a single byte, therefore `bytes[separator_start]` and @@ -201,8 +201,8 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. unsafe { ( - OsStr::from_os_str_bytes_unchecked(component), - OsStr::from_os_str_bytes_unchecked(path), + OsStr::from_encoded_bytes_unchecked(component), + OsStr::from_encoded_bytes_unchecked(path), ) } } @@ -323,7 +323,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { // Verbatim paths should not be modified. if prefix.map(|x| x.is_verbatim()).unwrap_or(false) { // NULs in verbatim paths are rejected for consistency. - if path.as_os_str_bytes().contains(&0) { + if path.as_encoded_bytes().contains(&0) { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 92edd2f6112..cd5bf7f1538 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -172,6 +172,7 @@ pub struct Command { pub enum Stdio { Inherit, + InheritSpecific { from_stdio_id: c::DWORD }, Null, MakePipe, Pipe(AnonPipe), @@ -352,7 +353,7 @@ impl Command { }; si_ptr = &mut si_ex as *mut _ as _; } else { - si.cb = mem::size_of::<c::STARTUPINFOW> as c::DWORD; + si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD; si_ptr = &mut si as *mut _ as _; } @@ -429,7 +430,7 @@ fn resolve_exe<'a>( // Test if the file name has the `exe` extension. // This does a case-insensitive `ends_with`. let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() { - exe_path.as_os_str_bytes()[exe_path.len() - EXE_SUFFIX.len()..] + exe_path.as_encoded_bytes()[exe_path.len() - EXE_SUFFIX.len()..] .eq_ignore_ascii_case(EXE_SUFFIX.as_bytes()) } else { false @@ -459,7 +460,7 @@ fn resolve_exe<'a>( // From the `CreateProcessW` docs: // > If the file name does not contain an extension, .exe is appended. // Note that this rule only applies when searching paths. - let has_extension = exe_path.as_os_str_bytes().contains(&b'.'); + let has_extension = exe_path.as_encoded_bytes().contains(&b'.'); // Search the directories given by `search_paths`. let result = search_paths(parent_paths, child_paths, |mut path| { @@ -555,17 +556,19 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> { impl Stdio { fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> { - match *self { - Stdio::Inherit => match stdio::get_handle(stdio_id) { - Ok(io) => unsafe { - let io = Handle::from_raw_handle(io); - let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); - io.into_raw_handle(); - ret - }, - // If no stdio handle is available, then propagate the null value. - Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) }, + let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) { + Ok(io) => unsafe { + let io = Handle::from_raw_handle(io); + let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); + io.into_raw_handle(); + ret }, + // If no stdio handle is available, then propagate the null value. + Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) }, + }; + match *self { + Stdio::Inherit => use_stdio_id(stdio_id), + Stdio::InheritSpecific { from_stdio_id } => use_stdio_id(from_stdio_id), Stdio::MakePipe => { let ours_readable = stdio_id != c::STD_INPUT_HANDLE; @@ -613,6 +616,18 @@ impl From<File> for Stdio { } } +impl From<io::Stdout> for Stdio { + fn from(_: io::Stdout) -> Stdio { + Stdio::InheritSpecific { from_stdio_id: c::STD_OUTPUT_HANDLE } + } +} + +impl From<io::Stderr> for Stdio { + fn from(_: io::Stderr) -> Stdio { + Stdio::InheritSpecific { from_stdio_id: c::STD_ERROR_HANDLE } + } +} + //////////////////////////////////////////////////////////////////////////////// // Processes //////////////////////////////////////////////////////////////////////////////// diff --git a/library/stdarch b/library/stdarch -Subproject d77878b7299dd7e286799a6e8447048b65d2a86 +Subproject 6100854c4b360f84da5ab25e7c75cb2080667dd diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index ecb58a0e9a5..f5220e361b3 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -142,7 +142,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.8", + "syn", ] [[package]] @@ -229,16 +229,6 @@ dependencies = [ ] [[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn 1.0.102", -] - -[[package]] name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -350,9 +340,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -384,7 +374,7 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", "windows-sys", ] @@ -503,15 +493,6 @@ dependencies = [ ] [[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] name = "pkg-config" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -519,13 +500,11 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "pretty_assertions" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ - "ctor", "diff", - "output_vt100", "yansi", ] @@ -657,7 +636,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.8", + "syn", ] [[package]] @@ -684,17 +663,6 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 74b9a23fa4e..9bf26948af3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -78,7 +78,7 @@ features = [ ] [dev-dependencies] -pretty_assertions = "1.2" +pretty_assertions = "1.4" [features] build-metrics = ["sysinfo"] diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b3666192853..91fa5ec6633 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -302,8 +302,10 @@ impl StepDescription { } } - fn maybe_run(&self, builder: &Builder<'_>, pathsets: Vec<PathSet>) { - if pathsets.iter().any(|set| self.is_excluded(builder, set)) { + fn maybe_run(&self, builder: &Builder<'_>, mut pathsets: Vec<PathSet>) { + pathsets.retain(|set| !self.is_excluded(builder, set)); + + if pathsets.is_empty() { return; } @@ -703,7 +705,8 @@ impl<'a> Builder<'a> { llvm::Lld, llvm::CrtBeginEnd, tool::RustdocGUITest, - tool::OptimizedDist + tool::OptimizedDist, + tool::CoverageDump, ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, @@ -725,6 +728,7 @@ impl<'a> Builder<'a> { test::Tidy, test::Ui, test::RunPassValgrind, + test::CoverageMap, test::RunCoverage, test::MirOpt, test::Codegen, @@ -733,6 +737,7 @@ impl<'a> Builder<'a> { test::Incremental, test::Debuginfo, test::UiFullDeps, + test::CodegenCranelift, test::Rustdoc, test::RunCoverageRustdoc, test::Pretty, diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 43b4a34fe5b..80e66622e8b 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -136,9 +136,9 @@ fn test_exclude_kind() { let mut config = configure("test", &["A"], &["A"]); // Ensure our test is valid, and `test::Rustc` would be run without the exclude. assert!(run_build(&[], config.clone()).contains::<test::CrateLibrustc>()); - // Ensure tests for rustc are skipped. + // Ensure tests for rustc are not skipped. config.skip = vec![path.clone()]; - assert!(!run_build(&[], config.clone()).contains::<test::CrateLibrustc>()); + assert!(run_build(&[], config.clone()).contains::<test::CrateLibrustc>()); // Ensure builds for rustc are not skipped. assert!(run_build(&[], config).contains::<compile::Rustc>()); } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 15e8c1eb9f8..f469dbea6db 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -58,6 +58,7 @@ o("clang", "llvm.clang", "build clang") o("missing-tools", "dist.missing-tools", "allow failures when building tools") o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++") o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard") +o("patch-binaries-for-nix", "build.patch-binaries-for-nix", "whether patch binaries for usage with Nix toolchains") v("llvm-cflags", "llvm.cflags", "build LLVM with these extra compiler flags") v("llvm-cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4396bbc51a3..671d25484d0 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1019,7 +1019,7 @@ impl Build { fn info(&self, msg: &str) { match self.config.dry_run { - DryRun::SelfCheck => return, + DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { println!("{msg}"); } diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index c841cb34036..aefed501513 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -24,6 +24,7 @@ use crate::util::{self, exe, output, t, up_to_date}; use crate::{CLang, GitRepo, Kind}; use build_helper::ci::CiEnv; +use build_helper::git::get_git_merge_base; #[derive(Clone)] pub struct LlvmResult { @@ -128,13 +129,19 @@ pub fn prebuilt_llvm_config( /// This retrieves the LLVM sha we *want* to use, according to git history. pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { let llvm_sha = if is_git { + // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we + // walk back further to the last bors merge commit that actually changed LLVM. The first + // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD` + // in that case. + let closest_upstream = + get_git_merge_base(Some(&config.src)).unwrap_or_else(|_| "HEAD".into()); let mut rev_list = config.git(); rev_list.args(&[ PathBuf::from("rev-list"), format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(), "-n1".into(), "--first-parent".into(), - "HEAD".into(), + closest_upstream.into(), "--".into(), config.src.join("src/llvm-project"), config.src.join("src/bootstrap/download-ci-llvm-stamp"), @@ -591,9 +598,9 @@ fn configure_cmake( } else if target.contains("linux") { cfg.define("CMAKE_SYSTEM_NAME", "Linux"); } else { - builder.info( + builder.info(&format!( "could not determine CMAKE_SYSTEM_NAME from the target `{target}`, build may fail", - ); + )); } // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 7e83b508e94..144e2acd09e 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -62,6 +62,9 @@ impl Finder { } pub fn check(build: &mut Build) { + let skip_target_sanity = + env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some_and(|s| s == "1" || s == "true"); + let path = env::var_os("PATH").unwrap_or_default(); // On Windows, quotes are invalid characters for filename paths, and if // one is present as part of the PATH then that can lead to the system @@ -166,7 +169,7 @@ than building it. // FIXME: it would be better to refactor this code to split necessary setup from pure sanity // checks, and have a regular flag for skipping the latter. Also see // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>. - if env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some() { + if skip_target_sanity { continue; } @@ -205,7 +208,15 @@ than building it. } } - // Make sure musl-root is valid + // Some environments don't want or need these tools, such as when testing Miri. + // FIXME: it would be better to refactor this code to split necessary setup from pure sanity + // checks, and have a regular flag for skipping the latter. Also see + // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>. + if skip_target_sanity { + continue; + } + + // Make sure musl-root is valid. if target.contains("musl") && !target.contains("unikraft") { // If this is a native target (host is also musl) and no musl-root is given, // fall back to the system toolchain in /usr before giving up @@ -227,14 +238,6 @@ than building it. } } - // Some environments don't want or need these tools, such as when testing Miri. - // FIXME: it would be better to refactor this code to split necessary setup from pure sanity - // checks, and have a regular flag for skipping the latter. Also see - // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>. - if env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some() { - continue; - } - if need_cmake && target.contains("msvc") { // There are three builds of cmake on windows: MSVC, MinGW, and // Cygwin. The Cygwin build does not have generators for Visual diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index d1018978f78..35e2e98e08e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1340,6 +1340,12 @@ host_test!(RunMakeFullDeps { default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly" }); +default_test!(CoverageMap { + path: "tests/coverage-map", + mode: "coverage-map", + suite: "coverage-map" +}); + host_test!(RunCoverage { path: "tests/run-coverage", mode: "run-coverage", suite: "run-coverage" }); host_test!(RunCoverageRustdoc { path: "tests/run-coverage-rustdoc", @@ -1545,6 +1551,14 @@ note: if you're sure you want to do this, please open an issue as to why. In the .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target })); } + if mode == "coverage-map" { + let coverage_dump = builder.ensure(tool::CoverageDump { + compiler: compiler.with_stage(0), + target: compiler.host, + }); + cmd.arg("--coverage-dump-path").arg(coverage_dump); + } + if mode == "run-make" || mode == "run-coverage" { let rust_demangler = builder .ensure(tool::RustDemangler { @@ -2953,3 +2967,129 @@ impl Step for TestHelpers { .compile("rust_test_helpers"); } } + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CodegenCranelift { + compiler: Compiler, + target: TargetSelection, +} + +impl Step for CodegenCranelift { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.paths(&["compiler/rustc_codegen_cranelift"]) + } + + fn make_run(run: RunConfig<'_>) { + let builder = run.builder; + let host = run.build_triple(); + let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + + if builder.doc_tests == DocTests::Only { + return; + } + + let triple = run.target.triple; + let target_supported = if triple.contains("linux") { + triple.contains("x86_64") || triple.contains("aarch64") || triple.contains("s390x") + } else if triple.contains("darwin") || triple.contains("windows") { + triple.contains("x86_64") + } else { + false + }; + if !target_supported { + builder.info("target not supported by rustc_codegen_cranelift. skipping"); + return; + } + + if builder.remote_tested(run.target) { + builder.info("remote testing is not supported by rustc_codegen_cranelift. skipping"); + return; + } + + if !builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("cranelift")) { + builder.info("cranelift not in rust.codegen-backends. skipping"); + return; + } + + builder.ensure(CodegenCranelift { compiler, target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let compiler = self.compiler; + let target = self.target; + + builder.ensure(compile::Std::new(compiler, target)); + + // If we're not doing a full bootstrap but we're testing a stage2 + // version of libstd, then what we're actually testing is the libstd + // produced in stage1. Reflect that here by updating the compiler that + // we're working with automatically. + let compiler = builder.compiler_for(compiler.stage, compiler.host, target); + + let build_cargo = || { + let mut cargo = builder.cargo( + compiler, + Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works + SourceType::InTree, + target, + "run", + ); + cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift")); + cargo + .arg("--manifest-path") + .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml")); + compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + + // Avoid incremental cache issues when changing rustc + cargo.env("CARGO_BUILD_INCREMENTAL", "false"); + + cargo + }; + + builder.info(&format!( + "{} cranelift stage{} ({} -> {})", + Kind::Test.description(), + compiler.stage, + &compiler.host, + target + )); + let _time = util::timeit(&builder); + + // FIXME handle vendoring for source tarballs before removing the --skip-test below + let download_dir = builder.out.join("cg_clif_download"); + + /* + let mut prepare_cargo = build_cargo(); + prepare_cargo.arg("--").arg("prepare").arg("--download-dir").arg(&download_dir); + #[allow(deprecated)] + builder.config.try_run(&mut prepare_cargo.into()).unwrap(); + */ + + let mut cargo = build_cargo(); + cargo + .arg("--") + .arg("test") + .arg("--download-dir") + .arg(&download_dir) + .arg("--out-dir") + .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_clif")) + .arg("--no-unstable-features") + .arg("--use-backend") + .arg("cranelift") + // Avoid having to vendor the standard library dependencies + .arg("--sysroot") + .arg("llvm") + // These tests depend on crates that are not yet vendored + // FIXME remove once vendoring is handled + .arg("--skip-test") + .arg("testsuite.extended_sysroot"); + cargo.args(builder.config.test_args()); + + #[allow(deprecated)] + builder.config.try_run(&mut cargo.into()).unwrap(); + } +} diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 07ff3da6b4a..f094dd9d7c9 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -306,6 +306,7 @@ bootstrap_tool!( GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; OptimizedDist, "src/tools/opt-dist", "opt-dist"; + CoverageDump, "src/tools/coverage-dump", "coverage-dump"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh index 7dae90f4403..689fe52863e 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 7018e24d8fe248596819d2e884761676f3542a04 +git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index 45174e708dc..4b0d360686f 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 7018e24d8fe248596819d2e884761676f3542a04 +git reset --hard ec4566beae84e54952637f0bf61bee4b4cacc087 make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 319989df334..f6954275ad4 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -60,7 +60,7 @@ ENV CC=clang CXX=clang++ # rustc-perf version from 2023-05-30 # Should also be changed in the opt-dist tool for other environments. ENV PERF_COMMIT 8b2ac3042e1ff2c0074455a0a3618adef97156b1 -RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \ +RUN curl -LS -o perf.zip https://ci-mirrors.rust-lang.org/rustc/rustc-perf-$PERF_COMMIT.zip && \ unzip perf.zip && \ mv rustc-perf-$PERF_COMMIT rustc-perf && \ rm perf.zip diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile index 02b4664eb55..0d0f1edd003 100644 --- a/src/ci/docker/host-x86_64/wasm32/Dockerfile +++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile @@ -58,5 +58,6 @@ ENV NO_CHANGE_USER=1 RUN chown 10719 -R /emsdk-portable/ # Exclude library/alloc due to OOM in benches. +# FIXME: Fix std tests ENV SCRIPT python3 ../x.py test --stage 2 --host='' --target $TARGETS \ - --skip library/alloc + --skip library/alloc --skip library/std diff --git a/src/ci/run.sh b/src/ci/run.sh index b8cb758bf40..98f2cdac5dc 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -123,6 +123,9 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir" + # Test the Cranelift backend in on CI, but don't ship it. + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.codegen-backends=llvm,cranelift" + # We enable this for non-dist builders, since those aren't trying to produce # fresh binaries. We currently don't entirely support distributing a fresh # copy of the compiler (including llvm tools, etc.) if we haven't actually diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 2c7c05c0c4b..4d32897cc14 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -260,6 +260,10 @@ The valid types of print values are: This returns rustc's minimum supported deployment target if no `*_DEPLOYMENT_TARGET` variable is present in the environment, or otherwise returns the variable's parsed value. +A filepath may optionally be specified for each requested information kind, in +the format `--print KIND=PATH`, just like for `--emit`. When a path is +specified, information will be written there instead of to stdout. + [conditional compilation]: ../reference/conditional-compilation.html [deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c1614d02f34..269fe928754 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -63,8 +63,9 @@ Tools](#tier-1-with-host-tools). ## Tier 2 with Host Tools Tier 2 targets can be thought of as "guaranteed to build". The Rust project -builds official binary releases for each tier 2 target, and automated builds -ensure that each tier 2 target builds after each change. Automated tests are +builds official binary releases of the standard library (or, in some cases, +only the `core` library) for each tier 2 target, and automated builds +ensure that each tier 2 target can be used as build target after each change. Automated tests are not always run so it's not guaranteed to produce a working build, but tier 2 targets often work to quite a good degree and patches are always welcome! @@ -103,11 +104,12 @@ target | notes `x86_64-unknown-linux-musl` | 64-bit Linux with MUSL [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 -## Tier 2 +## Tier 2 without Host Tools Tier 2 targets can be thought of as "guaranteed to build". The Rust project -builds official binary releases for each tier 2 target, and automated builds -ensure that each tier 2 target builds after each change. Automated tests are +builds official binary releases of the standard library (or, in some cases, +only the `core` library) for each tier 2 target, and automated builds +ensure that each tier 2 target can be used as build target after each change. Automated tests are not always run so it's not guaranteed to produce a working build, but tier 2 targets often work to quite a good degree and patches are always welcome! For the full requirements, see [Tier 2 target @@ -179,6 +181,7 @@ target | std | notes `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI +[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads `x86_64-apple-ios` | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` @@ -321,7 +324,6 @@ target | std | host | notes `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL -[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS diff --git a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md index b3eb34de638..23b99924899 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1-threads.md @@ -1,6 +1,6 @@ # `wasm32-wasi-preview1-threads` -**Tier: 3** +**Tier: 2** The `wasm32-wasi-preview1-threads` target is a new and still (as of July 2023) an experimental target. This target is an extension to `wasm32-wasi-preview1` target, @@ -70,12 +70,6 @@ compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can reliably interoperate with C code in this mode (yet). -This target is not a stable target. This means that there are not many engines -which implement the `wasi-threads` feature and if they do they're likely behind a -flag, for example: - -* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` - Also note that at this time the `wasm32-wasi-preview1-threads` target assumes the presence of other merged wasm proposals such as (with their LLVM feature flags): @@ -94,6 +88,17 @@ The target intends to match the corresponding Clang target for its `"C"` ABI. > found it's recommended to open an issue either with rust-lang/rust or ideally > with LLVM itself. +## Platform requirements + +The runtime should support the same set of APIs as any other supported wasi target for interacting with the host environment through the WASI standard. The runtime also should have implemetation of [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads). + +This target is not a stable target. This means that there are a few engines +which implement the `wasi-threads` feature and if they do they're likely behind a +flag, for example: + +* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` +* [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) - needs to be built with WAMR_BUILD_LIB_WASI_THREADS=1 + ## Building the target Users need to install or built wasi-sdk since release 20.0 @@ -110,12 +115,16 @@ After that users can build this by adding it to the `target` list in ## Building Rust programs -Since it is Tier 3, rust doesn't ship pre-compiled artifacts for this target. +From Rust Nightly 1.71.1 (2023-08-03) on the artifacts are shipped pre-compiled: + +```text +rustup target add wasm32-wasi-preview1-threads --toolchain nightly +``` + +Rust programs can be built for that target: -Specify `wasi-root` as explained in the previous section and then use the `build-std` -nightly cargo feature to build the standard library: -```shell -cargo +nightly build --target=wasm32-wasi-preview1-threads -Zbuild-std +```text +rustc --target wasm32-wasi-preview1-threads your-code.rs ``` ## Cross-compilation diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 9deb7009cfe..cd6e29ffd66 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -38,6 +38,22 @@ followed by a list of fields or variants for Rust types. Finally, the page lists associated functions and trait implementations, including automatic and blanket implementations that `rustdoc` knows about. +### Sections + +<!-- FIXME: Implementations --> +<!-- FIXME: Trait Implementations --> +<!-- FIXME: Implementors --> +<!-- FIXME: Auto Trait Implementations --> + +#### Aliased Type + +A type alias is expanded at compile time to its +[aliased type](https://doc.rust-lang.org/reference/items/type-aliases.html). +That may involve substituting some or all of the type parameters in the target +type with types provided by the type alias definition. The Aliased Type section +shows the result of this expansion, including the types of public fields or +variants, which may depend on those substitutions. + ### Navigation Subheadings, variants, fields, and many other things in this documentation diff --git a/src/doc/rustdoc/src/write-documentation/re-exports.md b/src/doc/rustdoc/src/write-documentation/re-exports.md index 593428b8a70..8ce059cc29c 100644 --- a/src/doc/rustdoc/src/write-documentation/re-exports.md +++ b/src/doc/rustdoc/src/write-documentation/re-exports.md @@ -86,7 +86,7 @@ pub use self::Hidden as InlinedHidden; ``` The same applies on re-exports themselves: if you have multiple re-exports and some of them have -`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation: +`#[doc(hidden)]`, then these ones (and only these) won't appear in the documentation: ```rust,ignore (inline) mod private_mod { diff --git a/src/doc/unstable-book/src/compiler-flags/path-options.md b/src/doc/unstable-book/src/compiler-flags/path-options.md deleted file mode 100644 index 0786ef1f166..00000000000 --- a/src/doc/unstable-book/src/compiler-flags/path-options.md +++ /dev/null @@ -1,11 +0,0 @@ -# `--print` Options - -The behavior of the `--print` flag can be modified by optionally be specifying a filepath -for each requested information kind, in the format `--print KIND=PATH`, just like for -`--emit`. When a path is specified, information will be written there instead of to stdout. - -This is unstable feature, so you have to provide `-Zunstable-options` to enable it. - -## Examples - -`rustc main.rs -Z unstable-options --print cfg=cfgs.txt` diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc86a3d7475..dd43ee03383 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -20,7 +20,8 @@ use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty, - clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type, + clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes, + AttributesExt, ImplKind, ItemId, Type, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -289,16 +290,14 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::TypeAlias> { let predicates = cx.tcx.explicit_predicates_of(did); - let type_ = clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), - cx, - Some(did), - None, - ); + let ty = cx.tcx.type_of(did).instantiate_identity(); + let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); + let inner_type = clean_ty_alias_inner_type(ty, cx); Box::new(clean::TypeAlias { type_, generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + inner_type, item_type: None, }) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1e85284371d..1f6e832c7cb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -24,6 +24,7 @@ use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::fold::TypeFolder; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -955,6 +956,43 @@ fn clean_ty_generics<'tcx>( } } +fn clean_ty_alias_inner_type<'tcx>( + ty: Ty<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option<TypeAliasInnerType> { + let ty::Adt(adt_def, args) = ty.kind() else { + return None; + }; + + Some(if adt_def.is_enum() { + let variants: rustc_index::IndexVec<_, _> = adt_def + .variants() + .iter() + .map(|variant| clean_variant_def_with_args(variant, args, cx)) + .collect(); + + TypeAliasInnerType::Enum { + variants, + is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), + } + } else { + let variant = adt_def + .variants() + .iter() + .next() + .unwrap_or_else(|| bug!("a struct or union should always have one variant def")); + + let fields: Vec<_> = + clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); + + if adt_def.is_struct() { + TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields } + } else { + TypeAliasInnerType::Union { fields } + } + }) +} + fn clean_proc_macro<'tcx>( item: &hir::Item<'tcx>, name: &mut Symbol, @@ -1222,6 +1260,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext Box::new(TypeAlias { type_: clean_ty(default, cx), generics, + inner_type: None, item_type: Some(item_type), }), bounds, @@ -1264,7 +1303,12 @@ pub(crate) fn clean_impl_item<'tcx>( None, ); AssocTypeItem( - Box::new(TypeAlias { type_, generics, item_type: Some(item_type) }), + Box::new(TypeAlias { + type_, + generics, + inner_type: None, + item_type: Some(item_type), + }), Vec::new(), ) } @@ -1471,6 +1515,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), bounds, @@ -1490,6 +1535,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), // Associated types inside trait or inherent impls are not allowed to have @@ -1959,31 +2005,44 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( #[derive(Debug)] pub(crate) enum ContainerTy<'tcx> { Ref(ty::Region<'tcx>), - Regular { ty: DefId, args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, arg: usize }, + Regular { + ty: DefId, + args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, + has_self: bool, + arg: usize, + }, } impl<'tcx> ContainerTy<'tcx> { fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> { match self { Self::Ref(region) => ObjectLifetimeDefault::Arg(region), - Self::Regular { ty: container, args, arg: index } => { + Self::Regular { ty: container, args, has_self, arg: index } => { let (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias { .. } - | DefKind::Trait - | DefKind::AssocTy - | DefKind::Variant) = tcx.def_kind(container) + | DefKind::Trait) = tcx.def_kind(container) else { return ObjectLifetimeDefault::Empty; }; let generics = tcx.generics_of(container); - let param = generics.params[index].def_id; - let default = tcx.object_lifetime_default(param); + debug_assert_eq!(generics.parent_count, 0); + // If the container is a trait object type, the arguments won't contain the self type but the + // generics of the corresponding trait will. In such a case, offset the index by one. + // For comparison, if the container is a trait inside a bound, the arguments do contain the + // self type. + let offset = + if !has_self && generics.parent.is_none() && generics.has_self { 1 } else { 0 }; + let param = generics.params[index + offset].def_id; + + let default = tcx.object_lifetime_default(param); match default { rbv::ObjectLifetimeDefault::Param(lifetime) => { + // The index is relative to the parent generics but since we don't have any, + // we don't need to translate it. let index = generics.param_def_id_to_index[&lifetime]; let arg = args.skip_binder()[index as usize].expect_region(); ObjectLifetimeDefault::Arg(arg) @@ -2350,6 +2409,83 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont ) } +pub(crate) fn clean_variant_def_with_args<'tcx>( + variant: &ty::VariantDef, + args: &GenericArgsRef<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Item { + let discriminant = match variant.discr { + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }), + ty::VariantDiscr::Relative(_) => None, + }; + + use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; + + let infcx = cx.tcx.infer_ctxt().build(); + let kind = match variant.ctor_kind() { + Some(CtorKind::Const) => VariantKind::CLike, + Some(CtorKind::Fn) => VariantKind::Tuple( + variant + .fields + .iter() + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + ), + None => VariantKind::Struct(VariantStruct { + fields: variant + .fields + .iter() + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + }), + }; + + Item::from_def_id_and_parts( + variant.def_id, + Some(variant.name), + VariantItem(Variant { kind, discriminant }), + cx, + ) +} + fn clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, disr_expr: &Option<hir::AnonConst>, @@ -2604,7 +2740,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; let rustdoc_ty = clean_ty(hir_ty, cx); - let ty = clean_middle_ty( + let type_ = clean_middle_ty( ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None, @@ -2617,10 +2753,15 @@ fn clean_maybe_renamed_item<'tcx>( cx.current_type_aliases.remove(&def_id); } } + + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + let inner_type = clean_ty_alias_inner_type(ty, cx); + TypeAliasItem(Box::new(TypeAlias { - type_: rustdoc_ty, generics, - item_type: Some(ty), + inner_type, + type_: rustdoc_ty, + item_type: Some(type_), })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9cf3c068b60..ff158fa8b4c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -22,6 +22,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::IndexVec; +use rustc_metadata::rendered_const; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment}; @@ -35,7 +36,7 @@ use rustc_target::spec::abi::Abi; use crate::clean::cfg::Cfg; use crate::clean::external_path; use crate::clean::inline::{self, print_inlined_const}; -use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const}; +use crate::clean::utils::{is_literal_expr, print_evaluated_const}; use crate::core::DocContext; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -2086,7 +2087,7 @@ impl Discriminant { /// Will be `None` in the case of cross-crate reexports, and may be /// simplified pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> { - self.expr.map(|body| print_const_expr(tcx, body)) + self.expr.map(|body| rendered_const(tcx, body)) } /// Will always be a machine readable number, without underscores or suffixes. pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String { @@ -2230,9 +2231,19 @@ pub(crate) struct PathSegment { } #[derive(Clone, Debug)] +pub(crate) enum TypeAliasInnerType { + Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool }, + Union { fields: Vec<Item> }, + Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> }, +} + +#[derive(Clone, Debug)] pub(crate) struct TypeAlias { pub(crate) type_: Type, pub(crate) generics: Generics, + /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`, + /// to be shown directly on the typedef page. + pub(crate) inner_type: Option<TypeAliasInnerType>, /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type /// alias instead of the final type. This will always have the final type, regardless of whether /// `type_` came from HIR or from metadata. @@ -2326,7 +2337,7 @@ impl ConstantKind { ConstantKind::TyConst { ref expr } => expr.to_string(), ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id), ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { - print_const_expr(tcx, body) + rendered_const(tcx, body) } } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 80a7a33d2bd..7696ea0f449 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -14,6 +14,7 @@ use rustc_ast::tokenstream::TokenTree; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_metadata::rendered_const; use rustc_middle::mir; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt}; @@ -77,9 +78,10 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { pub(crate) fn ty_args_to_args<'tcx>( cx: &mut DocContext<'tcx>, args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, - mut skip_first: bool, + has_self: bool, container: Option<DefId>, ) -> Vec<GenericArg> { + let mut skip_first = has_self; let mut ret_val = Vec::with_capacity(args.skip_binder().len().saturating_sub(if skip_first { 1 } else { 0 })); @@ -99,6 +101,7 @@ pub(crate) fn ty_args_to_args<'tcx>( container.map(|container| crate::clean::ContainerTy::Regular { ty: container, args, + has_self, arg: index, }), ))), @@ -253,7 +256,7 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { match n.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => { let s = if let Some(def) = def.as_local() { - print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def)) + rendered_const(cx.tcx, cx.tcx.hir().body_owned_by(def)) } else { inline::print_inlined_const(cx.tcx, def) }; @@ -365,100 +368,6 @@ pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { false } -/// Build a textual representation of an unevaluated constant expression. -/// -/// If the const expression is too complex, an underscore `_` is returned. -/// For const arguments, it's `{ _ }` to be precise. -/// This means that the output is not necessarily valid Rust code. -/// -/// Currently, only -/// -/// * literals (optionally with a leading `-`) -/// * unit `()` -/// * blocks (`{ … }`) around simple expressions and -/// * paths without arguments -/// -/// are considered simple enough. Simple blocks are included since they are -/// necessary to disambiguate unit from the unit type. -/// This list might get extended in the future. -/// -/// Without this censoring, in a lot of cases the output would get too large -/// and verbose. Consider `match` expressions, blocks and deeply nested ADTs. -/// Further, private and `doc(hidden)` fields of structs would get leaked -/// since HIR datatypes like the `body` parameter do not contain enough -/// semantic information for this function to be able to hide them – -/// at least not without significant performance overhead. -/// -/// Whenever possible, prefer to evaluate the constant first and try to -/// use a different method for pretty-printing. Ideally this function -/// should only ever be used as a fallback. -pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { - let hir = tcx.hir(); - let value = &hir.body(body).value; - - #[derive(PartialEq, Eq)] - enum Classification { - Literal, - Simple, - Complex, - } - - use Classification::*; - - fn classify(expr: &hir::Expr<'_>) -> Classification { - match &expr.kind { - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex } - } - hir::ExprKind::Lit(_) => Literal, - hir::ExprKind::Tup([]) => Simple, - hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => { - if classify(expr) == Complex { Complex } else { Simple } - } - // Paths with a self-type or arguments are too “complex” following our measure since - // they may leak private fields of structs (with feature `adt_const_params`). - // Consider: `<Self as Trait<{ Struct { private: () } }>>::CONSTANT`. - // Paths without arguments are definitely harmless though. - hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) => { - if segments.iter().all(|segment| segment.args.is_none()) { Simple } else { Complex } - } - // FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty - // contains const arguments. Is there a *concise* way to check for this? - hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple, - // FIXME: Can they contain const arguments and thus leak private struct fields? - hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple, - _ => Complex, - } - } - - let classification = classify(value); - - if classification == Literal - && !value.span.from_expansion() - && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) { - // For literals, we avoid invoking the pretty-printer and use the source snippet instead to - // preserve certain stylistic choices the user likely made for the sake legibility like - // - // * hexadecimal notation - // * underscores - // * character escapes - // - // FIXME: This passes through `-/*spacer*/0` verbatim. - snippet - } else if classification == Simple { - // Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and - // other formatting artifacts. - rustc_hir_pretty::id_to_string(&hir, body.hir_id) - } else if tcx.def_kind(hir.body_owner_def_id(body).to_def_id()) == DefKind::AnonConst { - // FIXME: Omit the curly braces if the enclosing expression is an array literal - // with a repeated element (an `ExprKind::Repeat`) as in such case it - // would not actually need any disambiguation. - "{ _ }".to_owned() - } else { - "_".to_owned() - } -} - /// Given a type Path, resolve it to a Type using the TyCtxt pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { debug!("resolve_type({path:?})"); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 1ce7efdfc20..974dc1c5135 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -157,6 +157,12 @@ pub(crate) struct Options { /// Note: this field is duplicated in `RenderOptions` because it's useful /// to have it in both places. pub(crate) unstable_features: rustc_feature::UnstableFeatures, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub(crate) expanded_args: Vec<String>, } impl fmt::Debug for Options { @@ -744,6 +750,7 @@ impl Options { json_unused_externs, scrape_examples_options, unstable_features, + expanded_args: args, }; let render_options = RenderOptions { output, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index eadff37b592..7cd25ef444b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -194,6 +194,7 @@ pub(crate) fn create_config( describe_lints, lint_cap, scrape_examples_options, + expanded_args, .. }: RustdocOptions, RenderOptions { document_private, .. }: &RenderOptions, @@ -291,6 +292,7 @@ pub(crate) fn create_config( make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + expanded_args, } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 36d5adb6304..bb7d26c541b 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -109,6 +109,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + expanded_args: options.expanded_args.clone(), }; let test_args = options.test_args.clone(); diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ceba643ed5f..cf11e2d7899 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -52,10 +52,31 @@ pub(crate) trait DocFolder: Sized { VariantItem(Variant { kind, discriminant }) } + TypeAliasItem(mut typealias) => { + typealias.inner_type = typealias.inner_type.map(|inner_type| match inner_type { + TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants = variants + .into_iter_enumerated() + .filter_map(|(_, x)| self.fold_item(x)) + .collect(); + + TypeAliasInnerType::Enum { variants, is_non_exhaustive } + } + TypeAliasInnerType::Union { fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Union { fields } + } + TypeAliasInnerType::Struct { ctor_kind, fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Struct { ctor_kind, fields } + } + }); + + TypeAliasItem(typealias) + } ExternCrateItem { src: _ } | ImportItem(_) | FunctionItem(_) - | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9a34e7cce8a..4c6e7dfb987 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -457,6 +457,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::StructItem(..) | clean::UnionItem(..) | clean::VariantItem(..) + | clean::TypeAliasItem(..) | clean::ImplItem(..) => { self.cache.parent_stack.push(ParentStackItem::new(&item)); (self.fold_item_recur(item), true) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 98cc38a10d4..a8d85fb6fb4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1574,7 +1574,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { map.insert("crate-search-div".into(), 1); // This is the list of IDs used in HTML generated in Rust (including the ones // used in tera template files). - map.insert("mainThemeStyle".into(), 1); map.insert("themeStyle".into(), 1); map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index bb1c186668c..0bc10c5e10f 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -7,8 +7,10 @@ use std::sync::mpsc::{channel, Receiver}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::source_map::FileName; use rustc_span::{sym, Symbol}; @@ -22,13 +24,13 @@ use super::{ sidebar::{sidebar_module_like, Sidebar}, AllTypes, LinkFromSrc, StylePath, }; -use crate::clean::{self, types::ExternalLocation, ExternalCrate}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem}; use crate::config::{ModuleSorting, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::FormatRenderer; +use crate::formats::{self, FormatRenderer}; use crate::html::escape::Escape; use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; @@ -147,6 +149,53 @@ impl SharedContext<'_> { pub(crate) fn edition(&self) -> Edition { self.tcx.sess.edition() } + + /// Returns a list of impls on the given type, and, if it's a type alias, + /// other types that it aliases. + pub(crate) fn all_impls_for_item<'a>( + &'a self, + it: &clean::Item, + did: DefId, + ) -> Vec<&'a formats::Impl> { + let tcx = self.tcx; + let cache = &self.cache; + let mut saw_impls = FxHashSet::default(); + let mut v: Vec<&formats::Impl> = cache + .impls + .get(&did) + .map(Vec::as_slice) + .unwrap_or(&[]) + .iter() + .filter(|i| saw_impls.insert(i.def_id())) + .collect(); + if let TypeAliasItem(ait) = &*it.kind && + let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) && + let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) && + let Some(av) = cache.impls.get(&aliased_type_defid) && + let Some(alias_def_id) = it.item_id.as_def_id() + { + // This branch of the compiler compares types structually, but does + // not check trait bounds. That's probably fine, since type aliases + // don't normally constrain on them anyway. + // https://github.com/rust-lang/rust/issues/21903 + // + // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification. + // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress. + let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); + let reject_cx = DeepRejectCtxt { + treat_obligation_params: TreatParams::AsCandidateKey, + }; + v.extend(av.iter().filter(|impl_| { + if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() { + reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder()) + && saw_impls.insert(impl_def_id) + } else { + false + } + })); + } + v + } } impl<'tcx> Context<'tcx> { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index aef8f1a74fb..5adbecd6d04 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1117,13 +1117,13 @@ pub(crate) fn render_all_impls( fn render_assoc_items<'a, 'cx: 'a>( cx: &'a mut Context<'cx>, containing_item: &'a clean::Item, - it: DefId, + did: DefId, what: AssocItemRender<'a>, ) -> impl fmt::Display + 'a + Captures<'cx> { let mut derefs = DefIdSet::default(); - derefs.insert(it); + derefs.insert(did); display_fn(move |f| { - render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); + render_assoc_items_inner(f, cx, containing_item, did, what, &mut derefs); Ok(()) }) } @@ -1132,15 +1132,17 @@ fn render_assoc_items_inner( mut w: &mut dyn fmt::Write, cx: &mut Context<'_>, containing_item: &clean::Item, - it: DefId, + did: DefId, what: AssocItemRender<'_>, derefs: &mut DefIdSet, ) { info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); - let cache = &shared.cache; - let Some(v) = cache.impls.get(&it) else { return }; - let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let v = shared.all_impls_for_item(containing_item, did); + let v = v.as_slice(); + let (non_trait, traits): (Vec<&Impl>, _) = + v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let mut saw_impls = FxHashSet::default(); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { @@ -1169,6 +1171,9 @@ fn render_assoc_items_inner( }; let mut impls_buf = Buffer::html(); for i in &non_trait { + if !saw_impls.insert(i.def_id()) { + continue; + } render_impl( &mut impls_buf, cx, @@ -1214,8 +1219,10 @@ fn render_assoc_items_inner( let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, _) = - concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); + let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete + .into_iter() + .filter(|t| saw_impls.insert(t.def_id())) + .partition(|t| t.inner_impl().kind.is_blanket()); render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cb78f903462..c6751c9585e 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,6 +1237,75 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + if let Some(inner_type) = &t.inner_type { + write!( + w, + "<h2 id=\"aliased-type\" class=\"small-section-header\">\ + Aliased Type<a href=\"#aliased-type\" class=\"anchor\">§</a></h2>" + ); + + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); + wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; + + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + render_enum_fields( + w, + cx, + Some(&t.generics), + variants_iter(), + variants_count, + has_stripped_entries, + *is_non_exhaustive, + ) + }); + item_variants(w, cx, it, variants_iter()); + } + clean::TypeAliasInnerType::Union { fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + Some(&t.generics), + None, + fields, + "", + true, + has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + } + clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + Some(&t.generics), + *ctor_kind, + fields, + "", + true, + has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + } + } + } + let def_id = it.item_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -1315,6 +1384,12 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( s: &'a [clean::Item], ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(|f| { + if s.iter() + .all(|field| matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))) + { + return f.write_str("/* private fields */"); + } + for (i, ty) in s.iter().enumerate() { if i > 0 { f.write_str(", ")?; @@ -1332,7 +1407,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let tcx = cx.tcx(); let count_variants = e.variants().count(); - wrap_item(w, |mut w| { + wrap_item(w, |w| { render_attributes_in_code(w, it, tcx); write!( w, @@ -1341,148 +1416,179 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: it.name.unwrap(), e.generics.print(cx), ); - if !print_where_clause_and_check(w, &e.generics, cx) { - // If there wasn't a `where` clause, we add a whitespace. - w.write_str(" "); - } + render_enum_fields( + w, + cx, + Some(&e.generics), + e.variants(), + count_variants, + e.has_stripped_entries(), + it.is_non_exhaustive(), + ); + }); - let variants_stripped = e.has_stripped_entries(); - if count_variants == 0 && !variants_stripped { - w.write_str("{}"); - } else { - w.write_str("{\n"); - let toggle = should_hide_fields(count_variants); - if toggle { - toggle_open(&mut w, format_args!("{count_variants} variants")); - } - for v in e.variants() { - w.write_str(" "); - let name = v.name.unwrap(); - match *v.kind { - // FIXME(#101337): Show discriminant - clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => w.write_str(name.as_str()), - clean::VariantKind::Tuple(ref s) => { - write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); - } - clean::VariantKind::Struct(ref s) => { - render_struct(w, v, None, None, &s.fields, " ", false, cx); - } - }, - _ => unreachable!(), - } - w.write_str(",\n"); - } + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - if variants_stripped && !it.is_non_exhaustive() { - w.write_str(" // some variants omitted\n"); - } - if toggle { - toggle_close(&mut w); + if count_variants != 0 { + item_variants(w, cx, it, e.variants()); + } + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn render_enum_fields<'a>( + mut w: &mut Buffer, + cx: &mut Context<'_>, + g: Option<&clean::Generics>, + variants: impl Iterator<Item = &'a clean::Item>, + count_variants: usize, + has_stripped_entries: bool, + is_non_exhaustive: bool, +) { + if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { + // If there wasn't a `where` clause, we add a whitespace. + w.write_str(" "); + } + + let variants_stripped = has_stripped_entries; + if count_variants == 0 && !variants_stripped { + w.write_str("{}"); + } else { + w.write_str("{\n"); + let toggle = should_hide_fields(count_variants); + if toggle { + toggle_open(&mut w, format_args!("{count_variants} variants")); + } + const TAB: &str = " "; + for v in variants { + w.write_str(TAB); + let name = v.name.unwrap(); + match *v.kind { + // FIXME(#101337): Show discriminant + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => w.write_str(name.as_str()), + clean::VariantKind::Tuple(ref s) => { + write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); + } + clean::VariantKind::Struct(ref s) => { + render_struct(w, v, None, None, &s.fields, TAB, false, cx); + } + }, + _ => unreachable!(), } - w.write_str("}"); + w.write_str(",\n"); } - }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + if variants_stripped && !is_non_exhaustive { + w.write_str(" // some variants omitted\n"); + } + if toggle { + toggle_close(&mut w); + } + w.write_str("}"); + } +} - if count_variants != 0 { +fn item_variants<'a>( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + variants: impl Iterator<Item = &'a clean::Item>, +) { + let tcx = cx.tcx(); + write!( + w, + "<h2 id=\"variants\" class=\"variants small-section-header\">\ + Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\ + </h2>\ + {}\ + <div class=\"variants\">", + document_non_exhaustive_header(it), + document_non_exhaustive(it) + ); + for variant in variants { + let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); write!( w, - "<h2 id=\"variants\" class=\"variants small-section-header\">\ - Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\ - </h2>\ - {}\ - <div class=\"variants\">", - document_non_exhaustive_header(it), - document_non_exhaustive(it) + "<section id=\"{id}\" class=\"variant\">\ + <a href=\"#{id}\" class=\"anchor\">§</a>", ); - for variant in e.variants() { - let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "<section id=\"{id}\" class=\"variant\">\ - <a href=\"#{id}\" class=\"anchor\">§</a>", - ); - render_stability_since_raw_with_extra( - w, - variant.stable_since(tcx), - variant.const_stability(tcx), - it.stable_since(tcx), - it.const_stable_since(tcx), - " rightside", - ); - write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap()); + render_stability_since_raw_with_extra( + w, + variant.stable_since(tcx), + variant.const_stability(tcx), + it.stable_since(tcx), + it.const_stable_since(tcx), + " rightside", + ); + write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap()); - let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; + let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; - if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - write!(w, "({})", print_tuple_struct_fields(cx, s)); - } - w.write_str("</h3></section>"); - - let heading_and_fields = match &variant_data.kind { - clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), - clean::VariantKind::Tuple(fields) => { - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - if fields.iter().any(|f| !f.doc_value().is_empty()) { - Some(("Tuple Fields", fields)) - } else { - None - } + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { + write!(w, "({})", print_tuple_struct_fields(cx, s)); + } + w.write_str("</h3></section>"); + + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| !f.doc_value().is_empty()) { + Some(("Tuple Fields", fields)) + } else { + None } - clean::VariantKind::CLike => None, - }; + } + clean::VariantKind::CLike => None, + }; - if let Some((heading, fields)) = heading_and_fields { - let variant_id = - cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "<div class=\"sub-variant\" id=\"{variant_id}\">\ - <h4>{heading}</h4>\ - {}", - document_non_exhaustive(variant) - ); - for field in fields { - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(_)) => {} - clean::StructFieldItem(ref ty) => { - let id = cx.derive_id(format!( - "variant.{}.field.{}", - variant.name.unwrap(), - field.name.unwrap() - )); - write!( - w, - "<div class=\"sub-variant-field\">\ + if let Some((heading, fields)) = heading_and_fields { + let variant_id = + cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); + write!( + w, + "<div class=\"sub-variant\" id=\"{variant_id}\">\ + <h4>{heading}</h4>\ + {}", + document_non_exhaustive(variant) + ); + for field in fields { + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => {} + clean::StructFieldItem(ref ty) => { + let id = cx.derive_id(format!( + "variant.{}.field.{}", + variant.name.unwrap(), + field.name.unwrap() + )); + write!( + w, + "<div class=\"sub-variant-field\">\ <span id=\"{id}\" class=\"small-section-header\">\ <a href=\"#{id}\" class=\"anchor field\">§</a>\ <code>{f}: {t}</code>\ </span>", - f = field.name.unwrap(), - t = ty.print(cx), - ); - write!( - w, - "{}</div>", - document(cx, field, Some(variant), HeadingOffset::H5) - ); - } - _ => unreachable!(), + f = field.name.unwrap(), + t = ty.print(cx), + ); + write!( + w, + "{}</div>", + document(cx, field, Some(variant), HeadingOffset::H5) + ); } + _ => unreachable!(), } - w.write_str("</div>"); } - - write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); + w.write_str("</div>"); } - write!(w, "</div>"); + + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); + write!(w, "</div>"); } fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { @@ -1593,15 +1699,28 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - let mut fields = s - .fields + item_fields(w, cx, it, &s.fields, s.ctor_kind); + + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn item_fields( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + fields: &Vec<clean::Item>, + ctor_kind: Option<CtorKind>, +) { + let mut fields = fields .iter() .filter_map(|f| match *f.kind { clean::StructFieldItem(ref ty) => Some((f, ty)), _ => None, }) .peekable(); - if let None | Some(CtorKind::Fn) = s.ctor_kind { + if let None | Some(CtorKind::Fn) = ctor_kind { if fields.peek().is_some() { write!( w, @@ -1609,7 +1728,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean {}{}<a href=\"#fields\" class=\"anchor\">§</a>\ </h2>\ {}", - if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, + if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it), document_non_exhaustive(it) ); @@ -1630,9 +1749,6 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } } } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); } fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { @@ -1871,7 +1987,7 @@ fn render_union<'a, 'cx: 'a>( } fn render_struct( - mut w: &mut Buffer, + w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, ty: Option<CtorKind>, @@ -1891,6 +2007,29 @@ fn render_struct( if let Some(g) = g { write!(w, "{}", g.print(cx)) } + render_struct_fields( + w, + g, + ty, + fields, + tab, + structhead, + it.has_stripped_entries().unwrap_or(false), + cx, + ) +} + +fn render_struct_fields( + mut w: &mut Buffer, + g: Option<&clean::Generics>, + ty: Option<CtorKind>, + fields: &[clean::Item], + tab: &str, + structhead: bool, + has_stripped_entries: bool, + cx: &Context<'_>, +) { + let tcx = cx.tcx(); match ty { None => { let where_displayed = @@ -1922,11 +2061,11 @@ fn render_struct( } if has_visible_fields { - if it.has_stripped_entries().unwrap() { + if has_stripped_entries { write!(w, "\n{tab} /* private fields */"); } write!(w, "\n{tab}"); - } else if it.has_stripped_entries().unwrap() { + } else if has_stripped_entries { write!(w, " /* private fields */ "); } if toggle { @@ -1936,21 +2075,31 @@ fn render_struct( } Some(CtorKind::Fn) => { w.write_str("("); - for (i, field) in fields.iter().enumerate() { - if i > 0 { - w.write_str(", "); - } - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), - clean::StructFieldItem(ref ty) => { - write!( - w, - "{}{}", - visibility_print_with_space(field.visibility(tcx), field.item_id, cx), - ty.print(cx), - ) + if fields.iter().all(|field| { + matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) + }) { + write!(w, "/* private fields */"); + } else { + for (i, field) in fields.iter().enumerate() { + if i > 0 { + w.write_str(", "); + } + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), + clean::StructFieldItem(ref ty) => { + write!( + w, + "{}{}", + visibility_print_with_space( + field.visibility(tcx), + field.item_id, + cx + ), + ty.print(cx), + ) + } + _ => unreachable!(), } - _ => unreachable!(), } } w.write_str(")"); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index f34be120d29..145c7d18dd0 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1,10 +1,10 @@ use std::collections::hash_map::Entry; use std::collections::BTreeMap; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; -use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer}; use crate::clean; use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; @@ -78,9 +78,9 @@ pub(crate) fn build_index<'tcx>( map: &mut FxHashMap<F, usize>, itemid: F, lastpathid: &mut usize, - crate_paths: &mut Vec<(ItemType, Symbol)>, + crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>, item_type: ItemType, - path: Symbol, + path: &[Symbol], ) { match map.entry(itemid) { Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())), @@ -88,7 +88,7 @@ pub(crate) fn build_index<'tcx>( let pathid = *lastpathid; entry.insert(pathid); *lastpathid += 1; - crate_paths.push((item_type, path)); + crate_paths.push((item_type, path.to_vec())); ty.id = Some(RenderTypeId::Index(pathid)); } } @@ -100,7 +100,7 @@ pub(crate) fn build_index<'tcx>( itemid_to_pathid: &mut FxHashMap<ItemId, usize>, primitives: &mut FxHashMap<Symbol, usize>, lastpathid: &mut usize, - crate_paths: &mut Vec<(ItemType, Symbol)>, + crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>, ) { if let Some(generics) = &mut ty.generics { for item in generics { @@ -131,7 +131,7 @@ pub(crate) fn build_index<'tcx>( lastpathid, crate_paths, item_type, - *fqp.last().unwrap(), + fqp, ); } else { ty.id = None; @@ -146,7 +146,7 @@ pub(crate) fn build_index<'tcx>( lastpathid, crate_paths, ItemType::Primitive, - sym, + &[sym], ); } RenderTypeId::Index(_) => {} @@ -191,7 +191,7 @@ pub(crate) fn build_index<'tcx>( lastpathid += 1; if let Some(&(ref fqp, short)) = paths.get(&defid) { - crate_paths.push((short, *fqp.last().unwrap())); + crate_paths.push((short, fqp.clone())); Some(pathid) } else { None @@ -213,118 +213,163 @@ pub(crate) fn build_index<'tcx>( struct CrateData<'a> { doc: String, items: Vec<&'a IndexItem>, - paths: Vec<(ItemType, Symbol)>, + paths: Vec<(ItemType, Vec<Symbol>)>, // The String is alias name and the vec is the list of the elements with this alias. // // To be noted: the `usize` elements are indexes to `items`. aliases: &'a BTreeMap<String, Vec<usize>>, } + struct Paths { + ty: ItemType, + name: Symbol, + path: Option<usize>, + } + + impl Serialize for Paths { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.ty)?; + seq.serialize_element(self.name.as_str())?; + if let Some(ref path) = self.path { + seq.serialize_element(path)?; + } + seq.end() + } + } + impl<'a> Serialize for CrateData<'a> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { + let mut extra_paths = FxHashMap::default(); + // We need to keep the order of insertion, hence why we use an `IndexMap`. Then we will + // insert these "extra paths" (which are paths of items from external crates) into the + // `full_paths` list at the end. + let mut revert_extra_paths = FxIndexMap::default(); + let mut mod_paths = FxHashMap::default(); + for (index, item) in self.items.iter().enumerate() { + if item.path.is_empty() { + continue; + } + mod_paths.insert(&item.path, index); + } + let mut paths = Vec::with_capacity(self.paths.len()); + for (ty, path) in &self.paths { + if path.len() < 2 { + paths.push(Paths { ty: *ty, name: path[0], path: None }); + continue; + } + let full_path = join_with_double_colon(&path[..path.len() - 1]); + if let Some(index) = mod_paths.get(&full_path) { + paths.push(Paths { ty: *ty, name: *path.last().unwrap(), path: Some(*index) }); + continue; + } + // It means it comes from an external crate so the item and its path will be + // stored into another array. + // + // `index` is put after the last `mod_paths` + let index = extra_paths.len() + self.items.len(); + if !revert_extra_paths.contains_key(&index) { + revert_extra_paths.insert(index, full_path.clone()); + } + match extra_paths.entry(full_path) { + Entry::Occupied(entry) => { + paths.push(Paths { + ty: *ty, + name: *path.last().unwrap(), + path: Some(*entry.get()), + }); + } + Entry::Vacant(entry) => { + entry.insert(index); + paths.push(Paths { + ty: *ty, + name: *path.last().unwrap(), + path: Some(index), + }); + } + } + } + + let mut names = Vec::with_capacity(self.items.len()); + let mut types = String::with_capacity(self.items.len()); + let mut full_paths = Vec::with_capacity(self.items.len()); + let mut descriptions = Vec::with_capacity(self.items.len()); + let mut parents = Vec::with_capacity(self.items.len()); + let mut functions = Vec::with_capacity(self.items.len()); + let mut deprecated = Vec::with_capacity(self.items.len()); + + for (index, item) in self.items.iter().enumerate() { + let n = item.ty as u8; + let c = char::try_from(n + b'A').expect("item types must fit in ASCII"); + assert!(c <= 'z', "item types must fit within ASCII printables"); + types.push(c); + + assert_eq!( + item.parent.is_some(), + item.parent_idx.is_some(), + "`{}` is missing idx", + item.name + ); + // 0 is a sentinel, everything else is one-indexed + parents.push(item.parent_idx.map(|x| x + 1).unwrap_or(0)); + + names.push(item.name.as_str()); + descriptions.push(&item.desc); + + if !item.path.is_empty() { + full_paths.push((index, &item.path)); + } + + // Fake option to get `0` out as a sentinel instead of `null`. + // We want to use `0` because it's three less bytes. + enum FunctionOption<'a> { + Function(&'a IndexItemFunctionType), + None, + } + impl<'a> Serialize for FunctionOption<'a> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self { + FunctionOption::None => 0.serialize(serializer), + FunctionOption::Function(ty) => ty.serialize(serializer), + } + } + } + functions.push(match &item.search_type { + Some(ty) => FunctionOption::Function(ty), + None => FunctionOption::None, + }); + + if item.deprecation.is_some() { + deprecated.push(index); + } + } + + for (index, path) in &revert_extra_paths { + full_paths.push((*index, path)); + } + let has_aliases = !self.aliases.is_empty(); let mut crate_data = serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?; crate_data.serialize_field("doc", &self.doc)?; - crate_data.serialize_field( - "t", - &self - .items - .iter() - .map(|item| { - let n = item.ty as u8; - let c = char::try_from(n + b'A').expect("item types must fit in ASCII"); - assert!(c <= 'z', "item types must fit within ASCII printables"); - c - }) - .collect::<String>(), - )?; - crate_data.serialize_field( - "n", - &self.items.iter().map(|item| item.name.as_str()).collect::<Vec<_>>(), - )?; - crate_data.serialize_field( - "q", - &self - .items - .iter() - .enumerate() - // Serialize as an array of item indices and full paths - .filter_map( - |(index, item)| { - if item.path.is_empty() { None } else { Some((index, &item.path)) } - }, - ) - .collect::<Vec<_>>(), - )?; - crate_data.serialize_field( - "d", - &self.items.iter().map(|item| &item.desc).collect::<Vec<_>>(), - )?; - crate_data.serialize_field( - "i", - &self - .items - .iter() - .map(|item| { - assert_eq!( - item.parent.is_some(), - item.parent_idx.is_some(), - "`{}` is missing idx", - item.name - ); - // 0 is a sentinel, everything else is one-indexed - item.parent_idx.map(|x| x + 1).unwrap_or(0) - }) - .collect::<Vec<_>>(), - )?; - crate_data.serialize_field( - "f", - &self - .items - .iter() - .map(|item| { - // Fake option to get `0` out as a sentinel instead of `null`. - // We want to use `0` because it's three less bytes. - enum FunctionOption<'a> { - Function(&'a IndexItemFunctionType), - None, - } - impl<'a> Serialize for FunctionOption<'a> { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - match self { - FunctionOption::None => 0.serialize(serializer), - FunctionOption::Function(ty) => ty.serialize(serializer), - } - } - } - match &item.search_type { - Some(ty) => FunctionOption::Function(ty), - None => FunctionOption::None, - } - }) - .collect::<Vec<_>>(), - )?; - crate_data.serialize_field( - "c", - &self - .items - .iter() - .enumerate() - // Serialize as an array of deprecated item indices - .filter_map(|(index, item)| item.deprecation.map(|_| index)) - .collect::<Vec<_>>(), - )?; - crate_data.serialize_field( - "p", - &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(), - )?; + crate_data.serialize_field("t", &types)?; + crate_data.serialize_field("n", &names)?; + // Serialize as an array of item indices and full paths + crate_data.serialize_field("q", &full_paths)?; + crate_data.serialize_field("d", &descriptions)?; + crate_data.serialize_field("i", &parents)?; + crate_data.serialize_field("f", &functions)?; + crate_data.serialize_field("c", &deprecated)?; + crate_data.serialize_field("p", &paths)?; if has_aliases { crate_data.serialize_field("a", &self.aliases)?; } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index b96b1536156..6466ae825d7 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -82,7 +82,7 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf clean::PrimitiveItem(_) => sidebar_primitive(cx, it), clean::UnionItem(ref u) => sidebar_union(cx, it, u), clean::EnumItem(ref e) => sidebar_enum(cx, it, e), - clean::TypeAliasItem(_) => sidebar_type_alias(cx, it), + clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t), clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)], clean::ForeignTypeItem => sidebar_foreign_type(cx, it), _ => vec![], @@ -230,8 +230,32 @@ fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBl } } -fn sidebar_type_alias<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> { +fn sidebar_type_alias<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + t: &'a clean::TypeAlias, +) -> Vec<LinkBlock<'a>> { let mut items = vec![]; + if let Some(inner_type) = &t.inner_type { + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { + let mut variants = variants + .iter() + .filter(|i| !i.is_stripped()) + .filter_map(|v| v.name) + .map(|name| Link::new(format!("variant.{name}"), name.to_string())) + .collect::<Vec<_>>(); + variants.sort_unstable(); + + items.push(LinkBlock::new(Link::new("variants", "Variants"), variants)); + } + clean::TypeAliasInnerType::Union { fields } + | clean::TypeAliasInnerType::Struct { ctor_kind: _, fields } => { + let fields = get_struct_fields_name(fields); + items.push(LinkBlock::new(Link::new("fields", "Fields"), fields)); + } + } + } sidebar_assoc_items(cx, it, &mut items); items } @@ -254,11 +278,12 @@ fn sidebar_assoc_items<'a>( links: &mut Vec<LinkBlock<'a>>, ) { let did = it.item_id.expect_def_id(); - let cache = cx.cache(); + let v = cx.shared.all_impls_for_item(it, it.item_id.expect_def_id()); + let v = v.as_slice(); let mut assoc_consts = Vec::new(); let mut methods = Vec::new(); - if let Some(v) = cache.impls.get(&did) { + if !v.is_empty() { let mut used_links = FxHashSet::default(); let mut id_map = IdMap::new(); @@ -294,7 +319,7 @@ fn sidebar_assoc_items<'a>( cx, &mut deref_methods, impl_, - v, + v.iter().copied(), &mut derefs, &mut used_links, ); @@ -324,7 +349,7 @@ fn sidebar_deref_methods<'a>( cx: &'a Context<'_>, out: &mut Vec<LinkBlock<'a>>, impl_: &Impl, - v: &[Impl], + v: impl Iterator<Item = &'a Impl>, derefs: &mut DefIdSet, used_links: &mut FxHashSet<String>, ) { @@ -349,7 +374,7 @@ fn sidebar_deref_methods<'a>( // Avoid infinite cycles return; } - let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); + let deref_mut = { v }.any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); let inner_impl = target .def_id(c) .or_else(|| { @@ -400,7 +425,7 @@ fn sidebar_deref_methods<'a>( cx, out, target_deref_impl, - target_impls, + target_impls.iter(), derefs, used_links, ); diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index c4a1ebbec02..1d6eafe51b9 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -134,7 +134,7 @@ impl DocVisitor for SourceCollector<'_, '_> { let filename = span.filename(sess); let span = span.inner(); let pos = sess.source_map().lookup_source_file(span.lo()); - let file_span = span.with_lo(pos.start_pos).with_hi(pos.end_pos); + let file_span = span.with_lo(pos.start_pos).with_hi(pos.end_position()); // If it turns out that we couldn't read this file, then we probably // can't read any of the files (generating html output from json or // something like that), so just don't include sources for the diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index cb653d6b8df..a5ae988f348 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -852,14 +852,14 @@ function preLoadCss(cssUrl) { window.CURRENT_TOOLTIP_ELEMENT = wrapper; window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e; clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); - wrapper.onpointerenter = function(ev) { + wrapper.onpointerenter = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } clearTooltipHoverTimeout(e); }; - wrapper.onpointerleave = function(ev) { + wrapper.onpointerleave = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; @@ -963,38 +963,38 @@ function preLoadCss(cssUrl) { } onEachLazy(document.getElementsByClassName("tooltip"), e => { - e.onclick = function() { - this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true; - if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) { + e.onclick = () => { + e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true; + if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) { hideTooltip(true); } else { - showTooltip(this); + showTooltip(e); window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0"); window.CURRENT_TOOLTIP_ELEMENT.focus(); window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler; } return false; }; - e.onpointerenter = function(ev) { + e.onpointerenter = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - setTooltipHoverTimeout(this, true); + setTooltipHoverTimeout(e, true); }; - e.onpointermove = function(ev) { + e.onpointermove = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - setTooltipHoverTimeout(this, true); + setTooltipHoverTimeout(e, true); }; - e.onpointerleave = function(ev) { + e.onpointerleave = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - if (!this.TOOLTIP_FORCE_VISIBLE && + if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) { // Tooltip pointer leave gesture: // @@ -1139,7 +1139,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ * * Pass "true" to reset focus for tooltip popovers. */ - window.hideAllModals = function(switchFocus) { + window.hideAllModals = switchFocus => { hideSidebar(); window.hidePopoverMenus(); hideTooltip(switchFocus); @@ -1148,7 +1148,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ /** * Hide all the popover menus. */ - window.hidePopoverMenus = function() { + window.hidePopoverMenus = () => { onEachLazy(document.querySelectorAll(".search-form .popover"), elem => { elem.style.display = "none"; }); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 42088e73554..0e270bbcc40 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -263,7 +263,6 @@ function initSearch(rawSearchIndex) { * @returns {integer} */ function buildTypeMapIndex(name) { - if (name === "" || name === null) { return -1; } @@ -1380,7 +1379,7 @@ function initSearch(rawSearchIndex) { * @type Map<integer, QueryElement[]> */ const queryElemSet = new Map(); - const addQueryElemToQueryElemSet = function addQueryElemToQueryElemSet(queryElem) { + const addQueryElemToQueryElemSet = queryElem => { let currentQueryElemList; if (queryElemSet.has(queryElem.id)) { currentQueryElemList = queryElemSet.get(queryElem.id); @@ -1397,7 +1396,7 @@ function initSearch(rawSearchIndex) { * @type Map<integer, FunctionType[]> */ const fnTypeSet = new Map(); - const addFnTypeToFnTypeSet = function addFnTypeToFnTypeSet(fnType) { + const addFnTypeToFnTypeSet = fnType => { // Pure generic, or an item that's not matched by any query elems. // Try [unboxing] it. // @@ -1463,6 +1462,32 @@ function initSearch(rawSearchIndex) { if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) { continue; } + const queryElemPathLength = queryElem.pathWithoutLast.length; + // If the query element is a path (it contains `::`), we need to check if this + // path is compatible with the target type. + if (queryElemPathLength > 0) { + const fnTypePath = fnType.path !== undefined && fnType.path !== null ? + fnType.path.split("::") : []; + // If the path provided in the query element is longer than this type, + // no need to check it since it won't match in any case. + if (queryElemPathLength > fnTypePath.length) { + continue; + } + let i = 0; + for (const path of fnTypePath) { + if (path === queryElem.pathWithoutLast[i]) { + i += 1; + if (i >= queryElemPathLength) { + break; + } + } + } + if (i < queryElemPathLength) { + // If we didn't find all parts of the path of the query element inside + // the fn type, then it's not the right one. + continue; + } + } if (queryElem.generics.length === 0 || checkGenerics(fnType, queryElem)) { currentFnTypeList.splice(i, 1); const result = doHandleQueryElemList(currentFnTypeList, queryElemList); @@ -1863,14 +1888,14 @@ function initSearch(rawSearchIndex) { * @param {QueryElement} elem */ function convertNameToId(elem) { - if (typeNameIdMap.has(elem.name)) { - elem.id = typeNameIdMap.get(elem.name); + if (typeNameIdMap.has(elem.pathLast)) { + elem.id = typeNameIdMap.get(elem.pathLast); } else if (!parsedQuery.literalSearch) { let match = -1; let matchDist = maxEditDistance + 1; let matchName = ""; for (const [name, id] of typeNameIdMap) { - const dist = editDistance(name, elem.name, maxEditDistance); + const dist = editDistance(name, elem.pathLast, maxEditDistance); if (dist <= matchDist && dist <= maxEditDistance) { if (dist === matchDist && matchName > name) { continue; @@ -2385,12 +2410,20 @@ ${item.displayPath}<span class="${type}">${name}</span>\ lowercasePaths ); } + // `0` is used as a sentinel because it's fewer bytes than `null` + if (pathIndex === 0) { + return { + id: -1, + ty: null, + path: null, + generics: generics, + }; + } + const item = lowercasePaths[pathIndex - 1]; return { - // `0` is used as a sentinel because it's fewer bytes than `null` - id: pathIndex === 0 - ? -1 - : buildTypeMapIndex(lowercasePaths[pathIndex - 1].name), - ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + id: buildTypeMapIndex(item.name), + ty: item.ty, + path: item.path, generics: generics, }; }); @@ -2422,13 +2455,22 @@ ${item.displayPath}<span class="${type}">${name}</span>\ let inputs, output; if (typeof functionSearchType[INPUTS_DATA] === "number") { const pathIndex = functionSearchType[INPUTS_DATA]; - inputs = [{ - id: pathIndex === 0 - ? -1 - : buildTypeMapIndex(lowercasePaths[pathIndex - 1].name), - ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, - generics: [], - }]; + if (pathIndex === 0) { + inputs = [{ + id: -1, + ty: null, + path: null, + generics: [], + }]; + } else { + const item = lowercasePaths[pathIndex - 1]; + inputs = [{ + id: buildTypeMapIndex(item.name), + ty: item.ty, + path: item.path, + generics: [], + }]; + } } else { inputs = buildItemSearchTypeAll( functionSearchType[INPUTS_DATA], @@ -2438,13 +2480,22 @@ ${item.displayPath}<span class="${type}">${name}</span>\ if (functionSearchType.length > 1) { if (typeof functionSearchType[OUTPUT_DATA] === "number") { const pathIndex = functionSearchType[OUTPUT_DATA]; - output = [{ - id: pathIndex === 0 - ? -1 - : buildTypeMapIndex(lowercasePaths[pathIndex - 1].name), - ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, - generics: [], - }]; + if (pathIndex === 0) { + output = [{ + id: -1, + ty: null, + path: null, + generics: [], + }]; + } else { + const item = lowercasePaths[pathIndex - 1]; + output = [{ + id: buildTypeMapIndex(item.name), + ty: item.ty, + path: item.path, + generics: [], + }]; + } } else { output = buildItemSearchTypeAll( functionSearchType[OUTPUT_DATA], @@ -2486,18 +2537,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\ let crateSize = 0; /** - * The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f` - * are arrays with the same length. n[i] contains the name of an item. - * t[i] contains the type of that item (as a string of characters that represent an - * offset in `itemTypes`). d[i] contains the description of that item. + * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f` + * are arrays with the same length. `q`, `a`, and `c` use a sparse + * representation for compactness. * - * q[i] contains the full path of the item, or an empty string indicating - * "same as q[i-1]". + * `n[i]` contains the name of an item. * - * i[i] contains an item's parent, usually a module. For compactness, + * `t[i]` contains the type of that item + * (as a string of characters that represent an offset in `itemTypes`). + * + * `d[i]` contains the description of that item. + * + * `q` contains the full paths of the items. For compactness, it is a set of + * (index, path) pairs used to create a map. If a given index `i` is + * not present, this indicates "same as the last index present". + * + * `i[i]` contains an item's parent, usually a module. For compactness, * it is a set of indexes into the `p` array. * - * f[i] contains function signatures, or `0` if the item isn't a function. + * `f[i]` contains function signatures, or `0` if the item isn't a function. * Functions are themselves encoded as arrays. The first item is a list of * types representing the function's inputs, and the second list item is a list * of types representing the function's output. Tuples are flattened. @@ -2511,6 +2569,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * * `p` is a list of path/type pairs. It is used for parents and function parameters. * + * `c` is an array of item indices that are deprecated. + * * @type {{ * doc: string, * a: Object, @@ -2577,9 +2637,19 @@ ${item.displayPath}<span class="${type}">${name}</span>\ // convert `rawPaths` entries into object form // generate normalizedPaths for function search mode let len = paths.length; + let lastPath = itemPaths.get(0); for (let i = 0; i < len; ++i) { - lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()}); - paths[i] = {ty: paths[i][0], name: paths[i][1]}; + const elem = paths[i]; + const ty = elem[0]; + const name = elem[1]; + let path = null; + if (elem.length > 2) { + path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath; + lastPath = path; + } + + lowercasePaths.push({ty: ty, name: name.toLowerCase(), path: path}); + paths[i] = {ty: ty, name: name, path: path}; } // convert `item*` into an object form, and construct word indices. @@ -2589,8 +2659,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ // operation that is cached for the life of the page state so that // all other search operations have access to this cached data for // faster analysis operations + lastPath = ""; len = itemTypes.length; - let lastPath = ""; for (let i = 0; i < len; ++i) { let word = ""; // This object should have exactly the same set of fields as the "crateRow" @@ -2599,11 +2669,12 @@ ${item.displayPath}<span class="${type}">${name}</span>\ word = itemNames[i].toLowerCase(); } searchWords.push(word); + const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath; const row = { crate: crate, ty: itemTypes.charCodeAt(i) - charA, name: itemNames[i], - path: itemPaths.has(i) ? itemPaths.get(i) : lastPath, + path: path, desc: itemDescs[i], parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, type: buildFunctionSearchType( diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 2cba32c1b50..63947789c54 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -59,8 +59,8 @@ if (settingValue !== null) { toggle.checked = settingValue === "true"; } - toggle.onchange = function() { - changeSetting(this.id, this.checked); + toggle.onchange = () => { + changeSetting(toggle.id, toggle.checked); }; }); onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => { @@ -224,14 +224,14 @@ if (isSettingsPage) { // We replace the existing "onclick" callback to do nothing if clicked. - getSettingsButton().onclick = function(event) { + getSettingsButton().onclick = event => { event.preventDefault(); }; } else { // We replace the existing "onclick" callback. const settingsButton = getSettingsButton(); const settingsMenu = document.getElementById("settings"); - settingsButton.onclick = function(event) { + settingsButton.onclick = event => { if (elemIsInParent(event.target, settingsMenu)) { return; } diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 60ccfe4da44..8cb43634377 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -15,8 +15,7 @@ <link rel="stylesheet" {#+ #} href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #} <link rel="stylesheet" {#+ #} - href="{{static_root_path|safe}}{{files.rustdoc_css}}" {#+ #} - id="mainThemeStyle"> {# #} + href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {# #} {% if !layout.default_settings.is_empty() %} <script id="default-settings" {#+ #} {%~ for (k, v) in layout.default_settings ~%} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 66b5798797f..08865015960 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -8,6 +8,7 @@ use std::fmt; use rustc_ast::ast; use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId}; +use rustc_metadata::rendered_const; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::{Pos, Symbol}; @@ -15,7 +16,6 @@ use rustc_target::spec::abi::Abi as RustcAbi; use rustdoc_json_types::*; -use crate::clean::utils::print_const_expr; use crate::clean::{self, ItemId}; use crate::formats::item_type::ItemType; use crate::json::JsonRenderer; @@ -789,7 +789,7 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind impl FromWithTcx<Box<clean::TypeAlias>> for TypeAlias { fn from_tcx(type_alias: Box<clean::TypeAlias>, tcx: TyCtxt<'_>) -> Self { - let clean::TypeAlias { type_, generics, item_type: _ } = *type_alias; + let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias; TypeAlias { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) } } } @@ -805,7 +805,7 @@ impl FromWithTcx<clean::Static> for Static { Static { type_: stat.type_.into_tcx(tcx), mutable: stat.mutability == ast::Mutability::Mut, - expr: stat.expr.map(|e| print_const_expr(tcx, e)).unwrap_or_default(), + expr: stat.expr.map(|e| rendered_const(tcx, e)).unwrap_or_default(), } } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 534c6eebbdd..dd52deef672 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -73,7 +73,7 @@ pub(crate) struct SyntaxRange { impl SyntaxRange { fn new(span: rustc_span::Span, file: &SourceFile) -> Option<Self> { let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0; - let get_line = |bytepos: BytePos| file.lookup_line(bytepos); + let get_line = |bytepos: BytePos| file.lookup_line(file.relative_position(bytepos)); Some(SyntaxRange { byte_span: (get_pos(span.lo()), get_pos(span.hi())), diff --git a/src/llvm-project b/src/llvm-project -Subproject 50eecd007f6bf135ad60493bc62102739038d59 +Subproject 0537f6354cffe546cbf47f6dc9c7f82e49e86cf diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index 66876e02c19..f20b7a2b4d7 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -78,13 +78,22 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> { /// We will then fall back to origin/master in the hope that at least this exists. pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> { let upstream_remote = get_rust_lang_rust_remote(git_dir)?; - let upstream_master = format!("{upstream_remote}/master"); - if rev_exists(&upstream_master, git_dir)? { - return Ok(upstream_master); + for upstream_master in [format!("{upstream_remote}/master"), format!("origin/master")] { + if rev_exists(&upstream_master, git_dir)? { + return Ok(upstream_master); + } } - // We could implement smarter logic here in the future. - Ok("origin/master".into()) + Err(format!("Cannot find any suitable upstream master branch")) +} + +pub fn get_git_merge_base(git_dir: Option<&Path>) -> Result<String, String> { + let updated_master = updated_master_branch(git_dir)?; + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned()) } /// Returns the files that have been modified in the current branch compared to the master branch. @@ -94,20 +103,13 @@ pub fn get_git_modified_files( git_dir: Option<&Path>, extensions: &Vec<&str>, ) -> Result<Option<Vec<String>>, String> { - let Ok(updated_master) = updated_master_branch(git_dir) else { - return Ok(None); - }; - - let git = || { - let mut git = Command::new("git"); - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - git - }; + let merge_base = get_git_merge_base(git_dir)?; - let merge_base = output_result(git().arg("merge-base").arg(&updated_master).arg("HEAD"))?; - let files = output_result(git().arg("diff-index").arg("--name-only").arg(merge_base.trim()))? + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + let files = output_result(git.args(["diff-index", "--name-only", merge_base.trim()]))? .lines() .map(|s| s.trim().to_owned()) .filter(|f| { diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 96fe1c9e1aecd8f57063e3753969bb6418fd2fd +Subproject 2fc85d15a542bfb610aff7682073412cf635352 diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index f2ef602012f..da8d8ed4c0f 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -12,7 +12,7 @@ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -507,20 +507,18 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - return unsafe_line.sf.lines(|lines| { - if comment_start_line.line >= unsafe_line.line { - HasSafetyComment::No - } else { - match text_has_safety_comment( - src, - &lines[comment_start_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos.to_usize(), - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } + return if comment_start_line.line >= unsafe_line.line { + HasSafetyComment::No + } else { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }); + }; } } HasSafetyComment::Maybe @@ -551,20 +549,18 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - return unsafe_line.sf.lines(|lines| { - if comment_start_line.line >= unsafe_line.line { - HasSafetyComment::No - } else { - match text_has_safety_comment( - src, - &lines[comment_start_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos.to_usize(), - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } + return if comment_start_line.line >= unsafe_line.line { + HasSafetyComment::No + } else { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }); + }; } } HasSafetyComment::Maybe @@ -614,20 +610,18 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span && Lrc::ptr_eq(&unsafe_line.sf, ¯o_line.sf) && let Some(src) = unsafe_line.sf.src.as_deref() { - unsafe_line.sf.lines(|lines| { - if macro_line.line < unsafe_line.line { - match text_has_safety_comment( - src, - &lines[macro_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos.to_usize(), - ) { - Some(b) => HasSafetyComment::Yes(b), - None => HasSafetyComment::No, - } - } else { - HasSafetyComment::No + if macro_line.line < unsafe_line.line { + match text_has_safety_comment( + src, + &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ) { + Some(b) => HasSafetyComment::Yes(b), + None => HasSafetyComment::No, } - }) + } else { + HasSafetyComment::No + } } else { // Problem getting source text. Pretend a comment was found. HasSafetyComment::Maybe @@ -671,13 +665,11 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { // Get the text from the start of function body to the unsafe block. // fn foo() { some_stuff; unsafe { stuff }; other_stuff; } // ^-------------^ - unsafe_line.sf.lines(|lines| { - body_line.line < unsafe_line.line && text_has_safety_comment( - src, - &lines[body_line.line + 1..=unsafe_line.line], - unsafe_line.sf.start_pos.to_usize(), - ).is_some() - }) + body_line.line < unsafe_line.line && text_has_safety_comment( + src, + &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line], + unsafe_line.sf.start_pos, + ).is_some() } else { // Problem getting source text. Pretend a comment was found. true @@ -688,13 +680,13 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { } /// Checks if the given text has a safety comment for the immediately proceeding line. -fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> Option<BytePos> { +fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos: BytePos) -> Option<BytePos> { let mut lines = line_starts .array_windows::<2>() .rev() .map_while(|[start, end]| { - let start = start.to_usize() - offset; - let end = end.to_usize() - offset; + let start = start.to_usize(); + let end = end.to_usize(); let text = src.get(start..end)?; let trimmed = text.trim_start(); Some((start + (text.len() - trimmed.len()), trimmed)) @@ -709,9 +701,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> let (mut line, mut line_start) = (line, line_start); loop { if line.to_ascii_uppercase().contains("SAFETY:") { - return Some(BytePos( - u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(), - )); + return Some(start_pos + BytePos(u32::try_from(line_start).unwrap())); } match lines.next() { Some((s, x)) if x.starts_with("//") => (line, line_start) = (x, s), @@ -724,15 +714,13 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> let (mut line_start, mut line) = (line_start, line); loop { if line.starts_with("/*") { - let src = &src[line_start..line_starts.last().unwrap().to_usize() - offset]; + let src = &src[line_start..line_starts.last().unwrap().to_usize()]; let mut tokens = tokenize(src); return (src[..tokens.next().unwrap().len as usize] .to_ascii_uppercase() .contains("SAFETY:") && tokens.all(|t| t.kind == TokenKind::Whitespace)) - .then_some(BytePos( - u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(), - )); + .then_some(start_pos + BytePos(u32::try_from(line_start).unwrap())); } match lines.next() { Some(x) => (line_start, line) = x, diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index dc4ee725681..600cd084c19 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -8,7 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; use rustc_span::source_map::{original_sp, SourceMap}; -use rustc_span::{hygiene, BytePos, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; use std::ops::Range; @@ -117,9 +117,9 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo /// ``` fn line_span<T: LintContext>(cx: &T, span: Span) -> Span { let span = original_sp(span, DUMMY_SP); - let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap(); - let line_no = source_map_and_line.line; - let line_start = source_map_and_line.sf.lines(|lines| lines[line_no]); + let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap(); + let line_start = sf.lines()[line]; + let line_start = sf.absolute_position(line_start); span.with_lo(line_start) } diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr index a8900da4e6e..99f08d94727 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr @@ -5,6 +5,7 @@ LL | std::f32::MAX; | ^^^^^^^^^^^^^ | = note: `-D clippy::absolute-paths` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::absolute_paths)]` error: consider bringing this path into scope with the `use` keyword --> $DIR/absolute_paths.rs:41:5 diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr index 41b70644be8..017ba4cc24f 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr @@ -5,6 +5,7 @@ LL | std::f32::MAX; | ^^^^^^^^^^^^^ | = note: `-D clippy::absolute-paths` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::absolute_paths)]` error: consider bringing this path into scope with the `use` keyword --> $DIR/absolute_paths.rs:41:5 diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr index c5912b7af9e..b754f67edfb 100644 --- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr +++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr @@ -5,6 +5,7 @@ LL | println!("val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::uninlined-format-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::uninlined_format_args)]` help: change this to | LL - println!("val='{}'", local_i32); @@ -30,6 +31,7 @@ LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^ | = note: `-D clippy::print-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_literal)]` help: try | LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr index 4f98ca19231..5e8d26e0741 100644 --- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr +++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr @@ -5,6 +5,7 @@ LL | let _ = Baz + Baz; | ^^^^^^^^^ | = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects --> $DIR/arithmetic_side_effects_allowed.rs:80:13 diff --git a/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr b/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr index ac017b20916..cf70b3c5cfc 100644 --- a/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr +++ b/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr @@ -7,6 +7,7 @@ LL | const ABOVE: [u8; 11] = [0; 11]; | help: make this a static item: `static` | = note: `-D clippy::large-const-arrays` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_const_arrays)]` error: allocating a local array larger than 10 bytes --> $DIR/array_size_threshold.rs:4:25 @@ -16,6 +17,7 @@ LL | const ABOVE: [u8; 11] = [0; 11]; | = help: consider allocating on the heap with `vec![0; 11].into_boxed_slice()` = note: `-D clippy::large-stack-arrays` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_stack_arrays)]` error: allocating a local array larger than 10 bytes --> $DIR/array_size_threshold.rs:8:17 diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index 825aa1487e7..6f8b04fd12b 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -6,6 +6,7 @@ LL | let _x = String::from("hello"); | = note: strings are bad (from clippy.toml) = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml` --> $DIR/await_holding_invalid_type.rs:10:9 diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 89d84eb2455..a21952c0e7a 100644 --- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -18,6 +18,7 @@ LL | fn cognitive_complexity() { | = help: you could split it up into multiple smaller functions = note: `-D clippy::cognitive-complexity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]` error: aborting due to previous error; 2 warnings emitted diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr index 859383a7119..3a66f701e4d 100644 --- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr @@ -5,6 +5,7 @@ LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::dbg-macro` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]` help: remove the invocation before committing it to a version control system | LL | if let Some(n) = n.checked_sub(4) { n } else { n } diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr index aed9feb6f79..0eebd587a5f 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr +++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr @@ -5,6 +5,7 @@ LL | println!("one"); | ^^^^^^^^^^^^^^^ | = note: `-D clippy::disallowed-macros` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]` error: use of a disallowed macro `std::println` --> $DIR/disallowed_macros.rs:11:5 diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr index 23c3e96a8d0..51cbe1abf59 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr @@ -5,6 +5,7 @@ LL | let foo = "bar"; | ^^^ | = note: `-D clippy::disallowed-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `ducks` --> $DIR/disallowed_names.rs:7:9 diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr index d961fa34074..d9f25a3eee5 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr @@ -5,6 +5,7 @@ LL | let ducks = ["quack", "quack"]; | ^^^^^ | = note: `-D clippy::disallowed-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.stderr b/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.stderr index 0f767c9b855..92b0350581d 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.stderr +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.stderr @@ -5,6 +5,7 @@ LL | /// TestItemThingyOfCoolness might sound cool but is not on the list and sh | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` help: try | LL | /// `TestItemThingyOfCoolness` might sound cool but is not on the list and should be linted. diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr index e0613eb863b..6567b5f1275 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr @@ -5,6 +5,7 @@ LL | /// OAuth and LaTeX are inside Clippy's default list. | ^^^^^ | = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` help: try | LL | /// `OAuth` and LaTeX are inside Clippy's default list. diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr index 1a7311b33e8..74be5b2e2b9 100644 --- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr +++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr @@ -6,6 +6,7 @@ LL | let w = { 3 }; | = help: try refactoring your code to minimize nesting = note: `-D clippy::excessive-nesting` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::excessive_nesting)]` error: this block is too nested --> $DIR/excessive_nesting.rs:67:17 diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr index 815d009350f..13b6d7ff9cd 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr @@ -6,6 +6,7 @@ LL | let _ = opt.expect(""); | = note: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::expect_used)]` error: used `expect()` on a `Result` value --> $DIR/expect_used.rs:12:13 diff --git a/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr b/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr index 87bdb61c6a5..717a4bbfbfe 100644 --- a/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr +++ b/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr @@ -6,6 +6,7 @@ LL | fn g(_: bool, _: bool) {} | = help: consider refactoring bools into two-variant enums = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::fn_params_excessive_bools)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr index dc255bdcaba..a2ca623e966 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr @@ -8,6 +8,7 @@ LL | | } | |_^ | = note: `-D clippy::too-many-lines` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` error: this function has too many lines (4/1) --> $DIR/test.rs:25:1 diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr index 2841f62bc94..305e00af27e 100644 --- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr +++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr @@ -10,6 +10,7 @@ note: same as this LL | if x.get() { | ^^^^^^^ = note: `-D clippy::ifs-same-cond` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/large_futures/large_futures.stderr b/src/tools/clippy/tests/ui-toml/large_futures/large_futures.stderr index b92734de2f0..7a02fcdbdd2 100644 --- a/src/tools/clippy/tests/ui-toml/large_futures/large_futures.stderr +++ b/src/tools/clippy/tests/ui-toml/large_futures/large_futures.stderr @@ -5,6 +5,7 @@ LL | should_warn().await; | ^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(should_warn())` | = note: `-D clippy::large-futures` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr index 7b5fb9e8765..7508cd6c46e 100644 --- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr +++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr @@ -6,6 +6,7 @@ LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); | = note: the configuration allows a maximum size of 600 bytes = note: `-D clippy::large-include-file` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]` = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) error: attempted to include a large file diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr index ac9d89d0cbe..ef97e5d3f31 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr @@ -5,6 +5,7 @@ LL | let _fail1 = 100_200_300.123456789; | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789` | = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]` error: long literal lacking separators --> $DIR/test.rs:22:18 @@ -13,6 +14,7 @@ LL | let _fail2 = 100200300.300200100; | ^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.300_200_100` | = note: `-D clippy::unreadable-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unreadable_literal)]` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr b/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr index d9a27628ddb..7f00fac4924 100644 --- a/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr @@ -5,6 +5,7 @@ LL | use extern_types::Aaa; | ^^^ | = note: `-D clippy::min-ident-chars` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]` error: this ident is too short (3 <= 3) --> $DIR/min_ident_chars.rs:10:5 diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr index 5dae5af7eb5..5b1f8dbd3ea 100644 --- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr @@ -5,6 +5,7 @@ LL | let _: Option<u64> = Some(&16).map(|b| *b); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `Some(&16).cloned()` | = note: `-D clippy::map-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_clone)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index 45de8fdffef..0aea330d40b 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -5,6 +5,7 @@ LL | use std::process::{exit as wrong_exit, Child as Kid}; | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` | = note: `-D clippy::missing-enforced-import-renames` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_enforced_import_renames)]` error: this import should be renamed --> $DIR/conf_missing_enforced_import_rename.rs:6:1 diff --git a/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr b/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr index a5a09c322e1..0eb25453b25 100644 --- a/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr +++ b/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr @@ -7,6 +7,7 @@ LL | | } | |_________^ | = note: `-D clippy::module-inception` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_inception)]` error: module has the same name as its containing module --> $DIR/module_inception.rs:11:5 diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index cfff1fffe80..483941d3c31 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -5,6 +5,7 @@ LL | let _ = vec! {1, 2, 3}; | ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]` | = note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::nonstandard_macro_braces)]` error: use of irregular braces for `format!` macro --> $DIR/conf_nonstandard_macro_braces.rs:44:13 diff --git a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr index d4b1ae84fd7..fe2d5afc6ca 100644 --- a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr +++ b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr @@ -5,6 +5,7 @@ LL | print!("{n}"); | ^^^^^^^^^^^^^ | = note: `-D clippy::print-stdout` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_stdout)]` error: use of `eprint!` --> $DIR/print_macro.rs:7:5 @@ -13,6 +14,7 @@ LL | eprint!("{n}"); | ^^^^^^^^^^^^^^ | = note: `-D clippy::print-stderr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_stderr)]` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr index a474187050c..1ecdabbc03e 100644 --- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr @@ -5,6 +5,7 @@ LL | pub(crate) fn crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a function --> $DIR/pub_crate_missing_doc.rs:15:5 diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr index 49b58067467..ca6a7475cf3 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr @@ -5,6 +5,7 @@ LL | { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_outside_block)]` help: put the `;` here | LL - { unit_fn_block(); } @@ -33,6 +34,7 @@ LL | | }; | |______^ | = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_inside_block)]` help: put the `;` here | LL ~ unit_fn_block(); diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr index 13ba9750f4b..ce03d7d75a2 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr @@ -8,6 +8,7 @@ LL | | }; | |______^ | = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_inside_block)]` help: put the `;` here | LL ~ unit_fn_block(); diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr index 3c619ebe73d..fcc409796e2 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr @@ -5,6 +5,7 @@ LL | { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_outside_block)]` help: put the `;` here | LL - { unit_fn_block(); } diff --git a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr index c72f8c6488d..6df11cc1fb7 100644 --- a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr +++ b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr @@ -11,6 +11,7 @@ LL | rc_is_not_send: Rc<String>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_send_fields_in_send_ty)]` error: some fields in `MultiField<T>` are not safe to be sent to another thread --> $DIR/test.rs:19:1 diff --git a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr index 4e7c70d1838..9237c9c9d29 100644 --- a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr +++ b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr @@ -8,6 +8,7 @@ LL | | } | = help: consider using a state machine or refactoring bools into two-variant enums = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::struct_excessive_bools)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr index 14e13194427..d14974faffa 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -18,6 +18,7 @@ LL | x[index]; | = help: consider using `.get(n)` or `.get_mut(n)` instead = note: `-D clippy::indexing-slicing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic --> $DIR/test.rs:46:5 diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr index 9082c1c54c3..62132829223 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr @@ -5,6 +5,7 @@ LL | fn test(toto: ()) {} | ^^^^ | = note: `-D clippy::disallowed-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `toto` --> $DIR/conf_french_disallowed_name.rs:9:9 diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index fc137c225d8..d9b70e3b77c 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -5,6 +5,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap(); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::disallowed-methods` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` --> $DIR/conf_disallowed_methods.rs:36:5 diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr index e3ece799c7c..4ac96deb44f 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr @@ -5,6 +5,7 @@ LL | use std::sync::atomic::AtomicU32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::disallowed-types` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` error: `std::time::Instant` is not allowed according to config --> $DIR/conf_disallowed_types.rs:8:1 diff --git a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr index db5d6805362..262d302e72d 100644 --- a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr @@ -5,6 +5,7 @@ LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `u16` | = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::trivially_copy_pass_by_ref)]` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) --> $DIR/test.rs:15:20 diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr index 9a0fd059389..183c07fe786 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr @@ -6,6 +6,7 @@ LL | /* Safety: */ unsafe {} | = help: consider adding a safety comment on the preceding line = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment --> $DIR/undocumented_unsafe_blocks.rs:267:5 @@ -251,6 +252,7 @@ help: consider removing the safety comment LL | // SAFETY: | ^^^^^^^^^^ = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment --> $DIR/undocumented_unsafe_blocks.rs:473:5 diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr index 10219beaf97..cc22ea273d4 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -5,6 +5,7 @@ LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]` | = note: `-D clippy::get-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::get_unwrap)]` error: used `unwrap()` on an `Option` value --> $DIR/unwrap_used.rs:38:17 @@ -15,6 +16,7 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: if this value is `None`, it will panic = help: consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/unwrap_used.rs:39:17 diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr index 02f29bbefe1..3fad561b17c 100644 --- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr +++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr @@ -5,6 +5,7 @@ LL | struct HTTPResponse; // not linted by default, but with cfg option | ^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `HttpResponse` | = note: `-D clippy::upper-case-acronyms` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::upper_case_acronyms)]` error: name `NS` contains a capitalized acronym --> $DIR/upper_case_acronyms.rs:8:5 diff --git a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr index 55de68f8ecf..c88860ea8f6 100644 --- a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr +++ b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr @@ -5,6 +5,7 @@ LL | struct Foo(Vec<Box<u8>>); | ^^^^^^^^^^^^ help: try: `Vec<u8>` | = note: `-D clippy::vec-box` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::vec_box)]` error: `Vec<T>` is already on the heap, the boxing is unnecessary --> $DIR/test.rs:10:12 diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr index a7843e2b349..64d38e60dc6 100644 --- a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr +++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr @@ -6,6 +6,7 @@ LL | u <= 0; | = help: because `0` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 0` instead = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::absurd_extreme_comparisons)]` error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false --> $DIR/absurd-extreme-comparisons.rs:16:5 diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr index 30a947b0648..7ac0bd45684 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes.stderr @@ -5,6 +5,7 @@ LL | #[allow(dead_code)] | ^^^^^ help: replace it with: `expect` | = note: `-D clippy::allow-attributes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::allow_attributes)]` error: #[allow] attribute found --> $DIR/allow_attributes.rs:22:30 diff --git a/src/tools/clippy/tests/ui/almost_complete_range.stderr b/src/tools/clippy/tests/ui/almost_complete_range.stderr index 9a6d91b7d8b..054a02c9c90 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.stderr +++ b/src/tools/clippy/tests/ui/almost_complete_range.stderr @@ -7,6 +7,7 @@ LL | let _ = ('a') ..'z'; | help: use an inclusive range: `..=` | = note: `-D clippy::almost-complete-range` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::almost_complete_range)]` error: almost complete ascii range --> $DIR/almost_complete_range.rs:19:17 diff --git a/src/tools/clippy/tests/ui/approx_const.stderr b/src/tools/clippy/tests/ui/approx_const.stderr index 28d2d317155..4b5cd2a7a62 100644 --- a/src/tools/clippy/tests/ui/approx_const.stderr +++ b/src/tools/clippy/tests/ui/approx_const.stderr @@ -6,6 +6,7 @@ LL | let my_e = 2.7182; | = help: consider using the constant directly = note: `-D clippy::approx-constant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::approx_constant)]` error: approximate value of `f{32, 64}::consts::E` found --> $DIR/approx_const.rs:6:20 diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr index de3f2fb9e16..fd239580d28 100644 --- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr +++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr @@ -8,6 +8,7 @@ LL | let _ = Arc::new(RefCell::new(42)); = note: required for `Arc<RefCell<i32>>` to implement `Send` and `Sync` = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex` = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]` error: usage of an `Arc` that is not `Send` or `Sync` --> $DIR/arc_with_non_send_sync.rs:40:13 diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 7f490748160..13729a6c5a3 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -5,6 +5,7 @@ LL | _n += 1; | ^^^^^^^ | = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects --> $DIR/arithmetic_side_effects.rs:305:5 diff --git a/src/tools/clippy/tests/ui/as_conversions.stderr b/src/tools/clippy/tests/ui/as_conversions.stderr index 54037a64997..4bb964399e2 100644 --- a/src/tools/clippy/tests/ui/as_conversions.stderr +++ b/src/tools/clippy/tests/ui/as_conversions.stderr @@ -6,6 +6,7 @@ LL | let i = 0u32 as u64; | = help: consider using a safe wrapper for this conversion = note: `-D clippy::as-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::as_conversions)]` error: using a potentially dangerous silent `as` conversion --> $DIR/as_conversions.rs:12:13 diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr index 1cd57dd6d16..92cdf911538 100644 --- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr @@ -5,6 +5,7 @@ LL | let _ = string.as_ptr() as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` | = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]` error: casting the result of `as_ptr` to *mut i8 --> $DIR/as_ptr_cast_mut.rs:25:22 diff --git a/src/tools/clippy/tests/ui/as_underscore.stderr b/src/tools/clippy/tests/ui/as_underscore.stderr index 21d7884445d..1842eeeacec 100644 --- a/src/tools/clippy/tests/ui/as_underscore.stderr +++ b/src/tools/clippy/tests/ui/as_underscore.stderr @@ -7,6 +7,7 @@ LL | foo(n as _); | help: consider giving the type explicitly: `usize` | = note: `-D clippy::as-underscore` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::as_underscore)]` error: using `as _` conversion --> $DIR/as_underscore.rs:10:18 diff --git a/src/tools/clippy/tests/ui/asm_syntax.stderr b/src/tools/clippy/tests/ui/asm_syntax.stderr index 8ee3c97ae2c..537ea8c57e9 100644 --- a/src/tools/clippy/tests/ui/asm_syntax.stderr +++ b/src/tools/clippy/tests/ui/asm_syntax.stderr @@ -6,6 +6,7 @@ LL | asm!(""); | = help: use AT&T x86 assembly syntax = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]` error: Intel x86 assembly syntax used --> $DIR/asm_syntax.rs:10:9 @@ -31,6 +32,7 @@ LL | asm!("", options(att_syntax)); | = help: use Intel x86 assembly syntax = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]` error: AT&T x86 assembly syntax used --> $DIR/asm_syntax.rs:28:9 diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr index fc1c7671ffc..780d1fe1c8a 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr @@ -6,6 +6,7 @@ LL | assert!(true); | = help: remove it = note: `-D clippy::assertions-on-constants` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assertions_on_constants)]` error: `assert!(false)` should probably be replaced --> $DIR/assertions_on_constants.rs:12:5 diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr index 298d63c9c34..23af51cfe6f 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr @@ -5,6 +5,7 @@ LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` | = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assertions_on_result_states)]` error: called `assert!` with `Result::is_ok` --> $DIR/assertions_on_result_states.rs:42:5 diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr index 525ce592b49..e021e1bab4c 100644 --- a/src/tools/clippy/tests/ui/assign_ops.stderr +++ b/src/tools/clippy/tests/ui/assign_ops.stderr @@ -5,6 +5,7 @@ LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` | = note: `-D clippy::assign-op-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation --> $DIR/assign_ops.rs:8:5 diff --git a/src/tools/clippy/tests/ui/assign_ops2.stderr b/src/tools/clippy/tests/ui/assign_ops2.stderr index b392d1c690b..6e9b96c0a64 100644 --- a/src/tools/clippy/tests/ui/assign_ops2.stderr +++ b/src/tools/clippy/tests/ui/assign_ops2.stderr @@ -5,6 +5,7 @@ LL | a += a + 1; | ^^^^^^^^^^ | = note: `-D clippy::misrefactored-assign-op` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::misrefactored_assign_op)]` help: did you mean `a = a + 1` or `a = a + a + 1`? Consider replacing it with | LL | a += 1; @@ -141,6 +142,7 @@ LL | buf = buf + cows.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` | = note: `-D clippy::assign-op-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr index 22ce1c6f647..c29e3c734b7 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.stderr +++ b/src/tools/clippy/tests/ui/async_yields_async.stderr @@ -11,6 +11,7 @@ LL | | }; | |______- outer async construct | = note: `-D clippy::async-yields-async` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::async_yields_async)]` help: consider awaiting this value | LL ~ async { diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr index 0139717f548..16402a4ddfe 100644 --- a/src/tools/clippy/tests/ui/attrs.stderr +++ b/src/tools/clippy/tests/ui/attrs.stderr @@ -5,6 +5,7 @@ LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::inline-always` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_always)]` error: the since field must contain a semver-compliant version --> $DIR/attrs.rs:27:14 @@ -13,6 +14,7 @@ LL | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::deprecated-semver` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::deprecated_semver)]` error: the since field must contain a semver-compliant version --> $DIR/attrs.rs:32:14 diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr index d360c757158..56b111c4d9e 100644 --- a/src/tools/clippy/tests/ui/await_holding_lock.stderr +++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr @@ -14,6 +14,7 @@ LL | | baz().await LL | | } | |_____^ = note: `-D clippy::await-holding-lock` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]` error: this `MutexGuard` is held across an `await` point --> $DIR/await_holding_lock.rs:25:13 diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr index 266f8f39028..6b7e1d1afdd 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr @@ -14,6 +14,7 @@ LL | | baz().await LL | | } | |_^ = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:12:9 diff --git a/src/tools/clippy/tests/ui/bit_masks.stderr b/src/tools/clippy/tests/ui/bit_masks.stderr index d0cb3a263fc..4423d15d79d 100644 --- a/src/tools/clippy/tests/ui/bit_masks.stderr +++ b/src/tools/clippy/tests/ui/bit_masks.stderr @@ -5,6 +5,7 @@ LL | x & 0 == 0; | ^^^^^^^^^^ | = note: `-D clippy::bad-bit-mask` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bad_bit_mask)]` error: this operation will always return zero. This is likely not the intended outcome --> $DIR/bit_masks.rs:14:5 @@ -87,6 +88,7 @@ LL | x | 1 > 3; | ^^^^^^^^^ | = note: `-D clippy::ineffective-bit-mask` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ineffective_bit_mask)]` error: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared directly --> $DIR/bit_masks.rs:72:5 diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr index 0f92fbebae9..d04ea7151c2 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr @@ -3,6 +3,7 @@ error: `clippy::restriction` is not meant to be enabled as a group = note: because of the command line `--warn clippy::restriction` = help: enable the restriction lints you need individually = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]` error: `clippy::restriction` is not meant to be enabled as a group --> $DIR/blanket_clippy_restriction_lints.rs:6:9 diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_if_conditions.stderr index 2af7f3128c1..d80ef9c0fd8 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_if_conditions.stderr @@ -8,6 +8,7 @@ LL | | } { | |_____^ | = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]` help: try | LL ~ let res = { @@ -29,6 +30,7 @@ LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.stderr b/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.stderr index 34ebe5b6d14..ab68997d477 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.stderr @@ -11,6 +11,7 @@ LL | | }, | |_____________^ | = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` --> $DIR/blocks_in_if_conditions_closure.rs:34:13 diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr index e0d718c4ed8..5969e4faa1a 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr @@ -5,6 +5,7 @@ LL | assert_eq!("a".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::bool-assert-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bool_assert_comparison)]` help: replace it with `assert!(..)` | LL - assert_eq!("a".is_empty(), false); diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr index 31522d4a525..4560df6d4cd 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_comparison.stderr @@ -5,6 +5,7 @@ LL | if x == true { | ^^^^^^^^^ help: try simplifying it as shown: `x` | = note: `-D clippy::bool-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation --> $DIR/bool_comparison.rs:12:8 diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr index b0581e96834..837ed05d3a6 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr @@ -10,6 +10,7 @@ LL | | }; | = note: `a as i32` or `a.into()` can also be valid options = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bool_to_int_with_if)]` error: boolean to int conversion using if --> $DIR/bool_to_int_with_if.rs:19:5 diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr index b0e4e9363f1..43a7a6bf5b5 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr @@ -5,6 +5,7 @@ LL | let _p = &val as *const i32; | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)` | = note: `-D clippy::borrow-as-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer --> $DIR/borrow_as_ptr.rs:17:18 diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr index 4a0467cdbfe..2f258bcf966 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr @@ -5,6 +5,7 @@ LL | let _p = &val as *const i32; | ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)` | = note: `-D clippy::borrow-as-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer --> $DIR/borrow_as_ptr_no_std.rs:11:18 diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr index 524cf597c7f..c389d679738 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr @@ -5,6 +5,7 @@ LL | let b = &*a; | ^^^ help: if you would like to reborrow, try removing `&*`: `a` | = note: `-D clippy::borrow-deref-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::borrow_deref_ref)]` error: deref on an immutable reference --> $DIR/borrow_deref_ref.rs:15:22 diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.stderr index 5650f722b54..2a21f5ca236 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.stderr +++ b/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.stderr @@ -5,6 +5,7 @@ LL | let x: &str = &*s; | ^^^ | = note: `-D clippy::borrow-deref-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::borrow_deref_ref)]` help: if you would like to reborrow, try removing `&*` | LL | let x: &str = s; diff --git a/src/tools/clippy/tests/ui/box_collection.stderr b/src/tools/clippy/tests/ui/box_collection.stderr index 77342712675..1ae7c2a05e3 100644 --- a/src/tools/clippy/tests/ui/box_collection.stderr +++ b/src/tools/clippy/tests/ui/box_collection.stderr @@ -6,6 +6,7 @@ LL | fn test1(foo: Box<Vec<bool>>) {} | = help: `Vec<..>` is already on the heap, `Box<Vec<..>>` makes an extra allocation = note: `-D clippy::box-collection` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::box_collection)]` error: you seem to be trying to use `Box<String>`. Consider using just `String` --> $DIR/box_collection.rs:29:15 diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index 8c4778983d3..004550c6c64 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -5,6 +5,7 @@ LL | let _string: Box<String> = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` | = note: `-D clippy::box-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::box_default)]` error: `Box::new(_)` of default value --> $DIR/box_default.rs:23:17 diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr index 11868605d96..187cc8fa18b 100644 --- a/src/tools/clippy/tests/ui/boxed_local.stderr +++ b/src/tools/clippy/tests/ui/boxed_local.stderr @@ -5,6 +5,7 @@ LL | fn warn_arg(x: Box<A>) { | ^ | = note: `-D clippy::boxed-local` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::boxed_local)]` error: local variable doesn't need to be boxed here --> $DIR/boxed_local.rs:123:12 diff --git a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr index 47a8a1e623e..cb8462182b8 100644 --- a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr +++ b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr @@ -5,6 +5,7 @@ LL | fn foo<u32>(a: u32) -> u32 { | ^^^ | = note: `-D clippy::builtin-type-shadow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::builtin_type_shadow)]` error[E0308]: mismatched types --> $DIR/builtin_type_shadow.rs:5:5 diff --git a/src/tools/clippy/tests/ui/bytes_count_to_len.stderr b/src/tools/clippy/tests/ui/bytes_count_to_len.stderr index fe2c8b0627d..db0bb4099de 100644 --- a/src/tools/clippy/tests/ui/bytes_count_to_len.stderr +++ b/src/tools/clippy/tests/ui/bytes_count_to_len.stderr @@ -5,6 +5,7 @@ LL | let _ = String::from("foo").bytes().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.len()` instead: `String::from("foo").len()` | = note: `-D clippy::bytes-count-to-len` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bytes_count_to_len)]` error: using long and hard to read `.bytes().count()` --> $DIR/bytes_count_to_len.rs:10:13 diff --git a/src/tools/clippy/tests/ui/bytes_nth.stderr b/src/tools/clippy/tests/ui/bytes_nth.stderr index d9ede64a381..574bfaac193 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.stderr +++ b/src/tools/clippy/tests/ui/bytes_nth.stderr @@ -5,6 +5,7 @@ LL | let _ = s.bytes().nth(3); | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()` | = note: `-D clippy::bytes-nth` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bytes_nth)]` error: called `.bytes().nth().unwrap()` on a `String` --> $DIR/bytes_nth.rs:7:14 diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr index 9abf8aaca93..49c840bd769 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -6,6 +6,7 @@ LL | filename.ends_with(".rs") | = help: consider using a case-insensitive comparison instead = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::case_sensitive_file_extension_comparisons)]` help: use std::path::Path | LL ~ std::path::Path::new(filename) diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 5442ef5db16..bc74f7b728e 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -5,6 +5,7 @@ LL | x0 as f32; | ^^^^^^^^^ | = note: `-D clippy::cast-precision-loss` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) --> $DIR/cast.rs:20:5 @@ -44,6 +45,7 @@ LL | 1f32 as i32; | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value --> $DIR/cast.rs:35:5 @@ -60,6 +62,7 @@ LL | 1f32 as u32; | ^^^^^^^^^^^ | = note: `-D clippy::cast-sign-loss` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value --> $DIR/cast.rs:39:5 @@ -190,6 +193,7 @@ LL | 1u8 as i8; | ^^^^^^^^^ | = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value --> $DIR/cast.rs:69:5 @@ -360,6 +364,7 @@ LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ | = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value --> $DIR/cast.rs:260:21 diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr index 94b87df0b6e..fbdb559fc42 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr @@ -5,6 +5,7 @@ LL | let y: u32 = x.abs() as u32; | ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()` | = note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_abs_to_unsigned)]` error: casting the result of `i32::abs()` to usize --> $DIR/cast_abs_to_unsigned.rs:10:20 diff --git a/src/tools/clippy/tests/ui/cast_alignment.stderr b/src/tools/clippy/tests/ui/cast_alignment.stderr index 70510eaf634..49bd8dad9c2 100644 --- a/src/tools/clippy/tests/ui/cast_alignment.stderr +++ b/src/tools/clippy/tests/ui/cast_alignment.stderr @@ -5,6 +5,7 @@ LL | (&1u8 as *const u8) as *const u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_ptr_alignment)]` error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes) --> $DIR/cast_alignment.rs:22:5 diff --git a/src/tools/clippy/tests/ui/cast_enum_constructor.stderr b/src/tools/clippy/tests/ui/cast_enum_constructor.stderr index f0489f08f91..b1bf61edeed 100644 --- a/src/tools/clippy/tests/ui/cast_enum_constructor.stderr +++ b/src/tools/clippy/tests/ui/cast_enum_constructor.stderr @@ -5,6 +5,7 @@ LL | let _ = Foo::Y as usize; | ^^^^^^^^^^^^^^^ | = note: `-D clippy::cast-enum-constructor` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_enum_constructor)]` error: cast of an enum tuple constructor to an integer --> $DIR/cast_enum_constructor.rs:16:13 diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr index 891476f304d..e4a5b2e805c 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr @@ -5,6 +5,7 @@ LL | let _ = true as u8; | ^^^^^^^^^^ help: try: `u8::from(true)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)` --> $DIR/cast_lossless_bool.rs:7:13 diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.stderr b/src/tools/clippy/tests/ui/cast_lossless_float.stderr index 70dc4a10264..95e80b4e4a6 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_float.stderr @@ -5,6 +5,7 @@ LL | let _ = x0 as f32; | ^^^^^^^^^ help: try: `f32::from(x0)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `i8` to `f64` may become silently lossy if you later change the type --> $DIR/cast_lossless_float.rs:8:13 diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr index 4891d934c5e..da75cb195eb 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr @@ -5,6 +5,7 @@ LL | let _ = 1i8 as i16; | ^^^^^^^^^^ help: try: `i16::from(1i8)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: casting `i8` to `i32` may become silently lossy if you later change the type --> $DIR/cast_lossless_integer.rs:7:13 diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr index 678db89954e..c0bb29448f2 100644 --- a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr +++ b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr @@ -6,6 +6,7 @@ LL | let _ = (0.0_f32 / -0.0) as usize; | = note: this always evaluates to 0 = note: `-D clippy::cast-nan-to-int` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_nan_to_int)]` error: casting a known NaN to usize --> $DIR/cast_nan_to_int.rs:8:13 diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr index 83164112026..47dc39a30ef 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr @@ -5,6 +5,7 @@ LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *co | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` | = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]` error: casting the result of `from_raw_parts_mut` to *mut [u8] --> $DIR/cast_raw_slice_pointer_cast.rs:9:35 diff --git a/src/tools/clippy/tests/ui/cast_size.stderr b/src/tools/clippy/tests/ui/cast_size.stderr index 6c7459b3aba..bc9224be644 100644 --- a/src/tools/clippy/tests/ui/cast_size.stderr +++ b/src/tools/clippy/tests/ui/cast_size.stderr @@ -6,6 +6,7 @@ LL | 1isize as i8; | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` help: ... or use `try_from` and handle the error accordingly | LL | i8::try_from(1isize); @@ -18,6 +19,7 @@ LL | x0 as f64; | ^^^^^^^^^ | = note: `-D clippy::cast-precision-loss` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> $DIR/cast_size.rs:19:5 @@ -92,6 +94,7 @@ LL | 1usize as i32; | ^^^^^^^^^^^^^ | = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size.rs:36:5 diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr index 524a2bf7248..8816ce2d837 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr @@ -5,6 +5,7 @@ LL | #[cfg_attr(rustfmt, rustfmt::skip)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]` | = note: `-D clippy::deprecated-cfg-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::deprecated_cfg_attr)]` error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes --> $DIR/cfg_attr_rustfmt.rs:22:1 diff --git a/src/tools/clippy/tests/ui/cfg_features.stderr b/src/tools/clippy/tests/ui/cfg_features.stderr index 5f92dfe169c..401c3e92ed9 100644 --- a/src/tools/clippy/tests/ui/cfg_features.stderr +++ b/src/tools/clippy/tests/ui/cfg_features.stderr @@ -5,6 +5,7 @@ LL | #[cfg(features = "not-really-a-feature")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `feature = "not-really-a-feature"` | = note: `-D clippy::maybe-misused-cfg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::maybe_misused_cfg)]` error: feature may misspelled as features --> $DIR/cfg_features.rs:9:34 diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr index da3e5c5e52b..ce1f2f8296e 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr @@ -6,6 +6,7 @@ LL | let _ = '❤' as u8; | = note: `char` is four bytes wide, but `u8` is a single byte = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr index 0542db5501a..359857119d0 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr @@ -6,6 +6,7 @@ LL | let _ = 'a' as u8; | = note: `char` is four bytes wide, but `u8` is a single byte = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` error: casting a character literal to `u8` truncates --> $DIR/char_lit_as_u8_suggestions.rs:5:13 diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr index 08457973a21..3e0169b74da 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.stderr +++ b/src/tools/clippy/tests/ui/checked_conversions.stderr @@ -5,6 +5,7 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` | = note: `-D clippy::checked-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]` error: checked cast can be simplified --> $DIR/checked_conversions.rs:15:13 diff --git a/src/tools/clippy/tests/ui/clear_with_drain.stderr b/src/tools/clippy/tests/ui/clear_with_drain.stderr index db545c5fba4..b1a3812563a 100644 --- a/src/tools/clippy/tests/ui/clear_with_drain.stderr +++ b/src/tools/clippy/tests/ui/clear_with_drain.stderr @@ -5,6 +5,7 @@ LL | v.drain(0..v.len()); | ^^^^^^^^^^^^^^^^^ help: try: `clear()` | = note: `-D clippy::clear-with-drain` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::clear_with_drain)]` error: `drain` used to clear a `Vec` --> $DIR/clear_with_drain.rs:26:7 diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr index 053dee95448..0526c2f5a28 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.stderr +++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr @@ -5,6 +5,7 @@ LL | 42.clone(); | ^^^^^^^^^^ help: try removing the `clone` call: `42` | = note: `-D clippy::clone-on-copy` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::clone_on_copy)]` error: using `clone` on type `i32` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:27:5 diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr index 247d15a015a..69a3738dd05 100644 --- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr +++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr @@ -5,6 +5,7 @@ LL | let _ = [1].iter().cloned(); | ^^^^^^ help: try: `copied` | = note: `-D clippy::cloned-instead-of-copied` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cloned_instead_of_copied)]` error: used `cloned` where `copied` could be used instead --> $DIR/cloned_instead_of_copied.rs:8:31 diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr index cc2ffb21b47..d3b7c85b229 100644 --- a/src/tools/clippy/tests/ui/cmp_null.stderr +++ b/src/tools/clippy/tests/ui/cmp_null.stderr @@ -5,6 +5,7 @@ LL | if p == ptr::null() { | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::cmp-null` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cmp_null)]` error: comparing with null is better expressed by the `.is_null()` method --> $DIR/cmp_null.rs:16:8 diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr index 95c829e795e..6431b3619be 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr @@ -5,6 +5,7 @@ LL | if borrowed.to_owned() == owned {} | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` | = note: `-D clippy::cmp-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison --> $DIR/asymmetric_partial_eq.rs:47:21 diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr index 76983578f41..09a495996f2 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr @@ -5,6 +5,7 @@ LL | if a.to_string() != "bar" { | ^^^^^^^^^^^^^ help: try: `a` | = note: `-D clippy::cmp-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison --> $DIR/comparison_flip.rs:10:17 diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr index 88e6da2f067..0b1127c1a61 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr @@ -5,6 +5,7 @@ LL | x != "foo".to_string(); | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` | = note: `-D clippy::cmp-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison --> $DIR/with_suggestion.rs:7:9 diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr index fa7cb380eba..c4f63bd09cb 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr @@ -5,6 +5,7 @@ LL | y.to_owned() == *x; | ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating | = note: `-D clippy::cmp-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison --> $DIR/without_suggestion.rs:13:5 diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.stderr b/src/tools/clippy/tests/ui/cognitive_complexity.stderr index a712b163b17..58c7455d11a 100644 --- a/src/tools/clippy/tests/ui/cognitive_complexity.stderr +++ b/src/tools/clippy/tests/ui/cognitive_complexity.stderr @@ -6,6 +6,7 @@ LL | fn main() { | = help: you could split it up into multiple smaller functions = note: `-D clippy::cognitive-complexity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]` error: the function has a cognitive complexity of (7/1) --> $DIR/cognitive_complexity.rs:92:4 diff --git a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr index bb48f329748..9cd25f6fda9 100644 --- a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr +++ b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr @@ -6,6 +6,7 @@ LL | fn kaboom() { | = help: you could split it up into multiple smaller functions = note: `-D clippy::cognitive-complexity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.stderr b/src/tools/clippy/tests/ui/collapsible_else_if.stderr index b644205d983..f0f840653f8 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_else_if.stderr @@ -10,6 +10,7 @@ LL | | } | |_____^ | = note: `-D clippy::collapsible-else-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_else_if)]` help: collapse nested if block | LL ~ } else if y == "world" { diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index c687bae1acc..e8a36bf48f1 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::collapsible-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]` help: collapse nested if block | LL ~ if x == "hello" && y == "world" { diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr index 51a5eedd761..ce7da1c16d3 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match.stderr @@ -18,6 +18,7 @@ LL | LL | Some(n) => foo(n), | ^^^^^^^ with this pattern = note: `-D clippy::collapsible-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]` error: this `match` can be collapsed into the outer `match` --> $DIR/collapsible_match.rs:23:20 diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr index f1b7c1417ef..e008355bec8 100644 --- a/src/tools/clippy/tests/ui/collapsible_match2.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr @@ -18,6 +18,7 @@ LL | LL | Some(n) => foo(n), | ^^^^^^^ with this pattern = note: `-D clippy::collapsible-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]` error: this `match` can be collapsed into the outer `match` --> $DIR/collapsible_match2.rs:21:24 diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr index 0751a104300..4b0bd818d2f 100644 --- a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr +++ b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr @@ -5,6 +5,7 @@ LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")` | = note: `-D clippy::collapsible-str-replace` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_str_replace)]` error: used consecutive `str::replace` call --> $DIR/collapsible_str_replace.rs:20:27 diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.stderr b/src/tools/clippy/tests/ui/collection_is_never_read.stderr index 0d3f2fc602f..acb9abff68e 100644 --- a/src/tools/clippy/tests/ui/collection_is_never_read.stderr +++ b/src/tools/clippy/tests/ui/collection_is_never_read.stderr @@ -5,6 +5,7 @@ LL | let mut x = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::collection-is-never-read` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collection_is_never_read)]` error: collection is never read --> $DIR/collection_is_never_read.rs:62:5 diff --git a/src/tools/clippy/tests/ui/comparison_chain.stderr b/src/tools/clippy/tests/ui/comparison_chain.stderr index db20b1fbb3b..3b41dcf55c6 100644 --- a/src/tools/clippy/tests/ui/comparison_chain.stderr +++ b/src/tools/clippy/tests/ui/comparison_chain.stderr @@ -11,6 +11,7 @@ LL | | } | = help: consider rewriting the `if` chain to use `cmp` and `match` = note: `-D clippy::comparison-chain` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]` error: `if` chain can be rewritten with `match` --> $DIR/comparison_chain.rs:28:5 diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr index 0a59caea8a2..b97ab4c3c93 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr +++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr @@ -5,6 +5,7 @@ LL | let _ = s == ""; | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` | = note: `-D clippy::comparison-to-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]` error: comparison to empty slice --> $DIR/comparison_to_empty.rs:9:13 diff --git a/src/tools/clippy/tests/ui/const_comparisons.stderr b/src/tools/clippy/tests/ui/const_comparisons.stderr index 8c920d36896..f773ccbc711 100644 --- a/src/tools/clippy/tests/ui/const_comparisons.stderr +++ b/src/tools/clippy/tests/ui/const_comparisons.stderr @@ -6,6 +6,7 @@ LL | status_code <= 400 && status_code > 500; | = note: since `400` < `500`, the expression evaluates to false for any value of `status_code` = note: `-D clippy::impossible-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::impossible_comparisons)]` error: boolean expression will never evaluate to 'true' --> $DIR/const_comparisons.rs:48:5 @@ -131,6 +132,7 @@ note: `if `status_code < 200` evaluates to true, status_code <= 299` will always LL | status_code < 200 && status_code <= 299; | ^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::redundant-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_comparisons)]` error: left-hand side of `&&` operator has no effect --> $DIR/const_comparisons.rs:114:5 diff --git a/src/tools/clippy/tests/ui/copy_iterator.stderr b/src/tools/clippy/tests/ui/copy_iterator.stderr index 12a329bdc12..48c3385b6c8 100644 --- a/src/tools/clippy/tests/ui/copy_iterator.stderr +++ b/src/tools/clippy/tests/ui/copy_iterator.stderr @@ -12,6 +12,7 @@ LL | | } | = note: consider implementing `IntoIterator` instead = note: `-D clippy::copy-iterator` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::copy_iterator)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-10148.stderr b/src/tools/clippy/tests/ui/crashes/ice-10148.stderr index f23e4433f95..4d436e3aa04 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10148.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-10148.stderr @@ -7,6 +7,7 @@ LL | println!(with_span!(""something "")); | help: remove the empty string | = note: `-D clippy::println-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::println_empty_string)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-10645.stderr b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr index 0055fe061e2..fc5347c86cd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10645.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr @@ -11,6 +11,7 @@ LL | pub async fn bar<'a, T: 'a>(_: T) {} | ^ has type `T` which is not `Send` = note: `T` doesn't implement `std::marker::Send` = note: `-D clippy::future-not-send` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` warning: 1 warning emitted diff --git a/src/tools/clippy/tests/ui/crashes/ice-10912.stderr b/src/tools/clippy/tests/ui/crashes/ice-10912.stderr index 0833769feec..2be297b5625 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10912.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-10912.stderr @@ -11,6 +11,7 @@ LL | fn f2() -> impl Sized { && 3.14159265358979323846E } | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider: `3.141_592_653_589_793_238_46` | = note: `-D clippy::unreadable-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unreadable_literal)]` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr index a166ccb3ee8..ae9610c9acd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr @@ -5,6 +5,7 @@ LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { | ^^ ^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_lifetimes)]` help: elide the lifetimes | LL - pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.stderr b/src/tools/clippy/tests/ui/crashes/ice-360.stderr index 292b27dd934..dd016355b53 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-360.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-360.stderr @@ -11,6 +11,7 @@ LL | | } | |_____^ help: try: `while let Some(ele) = iter.next() { .. }` | = note: `-D clippy::while-let-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::while_let_loop)]` error: empty `loop {}` wastes CPU cycles --> $DIR/ice-360.rs:12:9 @@ -20,6 +21,7 @@ LL | loop {} | = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body = note: `-D clippy::empty-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr index bc10555693c..c6bef3004d3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr @@ -5,6 +5,7 @@ LL | str: Sized; | ^^^^^ | = note: `-D trivial-bounds` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(trivial_bounds)]` error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters --> $DIR/ice-3969.rs:26:30 diff --git a/src/tools/clippy/tests/ui/crashes/ice-5835.stderr b/src/tools/clippy/tests/ui/crashes/ice-5835.stderr index c972bcb60a0..74d99a34847 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5835.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-5835.stderr @@ -5,6 +5,7 @@ LL | /// 位 | ^^^^ help: consider using four spaces per tab | = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-5872.stderr b/src/tools/clippy/tests/ui/crashes/ice-5872.stderr index a60ca345cf7..75a26ee318c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5872.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-5872.stderr @@ -5,6 +5,7 @@ LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` | = note: `-D clippy::needless-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr index 263c27d3d64..6ace7dae8bd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr @@ -9,6 +9,7 @@ LL | FOO_REF_REF => {}, = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details = note: `-D indirect-structural-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(indirect_structural_match)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-7169.stderr b/src/tools/clippy/tests/ui/crashes/ice-7169.stderr index 0cd02851640..47947f89baf 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7169.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-7169.stderr @@ -5,6 +5,7 @@ LL | if let Ok(_) = Ok::<_, ()>(A::<String>::default()) {} | -------^^^^^-------------------------------------- help: try: `if Ok::<_, ()>(A::<String>::default()).is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr index 1d8314e889f..e5f14f2215d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr @@ -6,6 +6,7 @@ LL | unsafe { 0 }; | = help: consider adding a safety comment on the preceding line = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.stderr b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr index 61fc8a4817a..7acace78a7b 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7869.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr @@ -11,6 +11,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports = note: `-D clippy::enum-variant-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-8250.stderr b/src/tools/clippy/tests/ui/crashes/ice-8250.stderr index e6f3644ef34..9c57f334581 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8250.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-8250.stderr @@ -5,6 +5,7 @@ LL | let _ = s[1..].splitn(2, '.').next()?; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s[1..].split('.')` | = note: `-D clippy::needless-splitn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_splitn)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.stderr b/src/tools/clippy/tests/ui/crashes/ice-8821.stderr index 486096e0a06..c8bd01fb1c6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8821.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-8821.stderr @@ -5,6 +5,7 @@ LL | let _: () = FN(); | ^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `FN();` | = note: `-D clippy::let-unit-value` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-8850.stderr b/src/tools/clippy/tests/ui/crashes/ice-8850.stderr index 41da3f715ae..aa140f305e3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8850.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-8850.stderr @@ -7,6 +7,7 @@ LL | res | ^^^ | = note: `-D clippy::let-and-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]` help: return the expression directly | LL ~ diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr index f5038f0a848..49c9bdc300e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr @@ -5,6 +5,7 @@ LL | things.iter().find(|p| is_thing_ready(p)).is_some() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|p| is_thing_ready(&p))` | = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr b/src/tools/clippy/tests/ui/crashes/ice-9445.stderr index a59d098e5ac..9307409ba58 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9445.stderr @@ -7,6 +7,7 @@ LL | const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core: | make this a static item (maybe with lazy_static) | = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr index 7a0a648974f..6d45393996d 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr +++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr @@ -10,6 +10,7 @@ help: consider marking this type as `Copy` LL | struct Foo<'a>(&'a [(); 100]); | ^^^^^^^^^^^^^^ = note: `-D clippy::needless-pass-by-value` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_value)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crate_in_macro_def.stderr b/src/tools/clippy/tests/ui/crate_in_macro_def.stderr index faf2bca1d62..3e624618237 100644 --- a/src/tools/clippy/tests/ui/crate_in_macro_def.stderr +++ b/src/tools/clippy/tests/ui/crate_in_macro_def.stderr @@ -5,6 +5,7 @@ LL | println!("{}", crate::unhygienic::MESSAGE); | ^^^^^ help: to reference the macro definition's crate, use: `$crate` | = note: `-D clippy::crate-in-macro-def` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::crate_in_macro_def)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr index 9258c828aaf..01033246dd9 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr @@ -9,6 +9,7 @@ LL | | b = a; | = note: or maybe you should use `core::mem::replace`? = note: `-D clippy::almost-swapped` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr index 82c68bd1cfe..f3ffd6a10c7 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr +++ b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr @@ -6,6 +6,7 @@ LL | main(); | = help: consider using another function for this recursion = note: `-D clippy::main-recursion` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::main_recursion)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr index 5c005bee761..037e6ff173a 100644 --- a/src/tools/clippy/tests/ui/create_dir.stderr +++ b/src/tools/clippy/tests/ui/create_dir.stderr @@ -5,6 +5,7 @@ LL | std::fs::create_dir("foo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")` | = note: `-D clippy::create-dir` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::create_dir)]` error: calling `std::fs::create_dir` where there may be a better way --> $DIR/create_dir.rs:11:5 diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr index e63d07a5f24..f45a7ba1fae 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro.stderr @@ -5,6 +5,7 @@ LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::dbg-macro` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]` help: remove the invocation before committing it to a version control system | LL | if let Some(n) = n.checked_sub(4) { n } else { n } diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr index 97c47064a33..b993bbf5526 100644 --- a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr +++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr @@ -5,6 +5,7 @@ LL | debug_assert!(bool_mut(&mut 3)); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::debug-assert-with-mut-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::debug_assert_with_mut_call)]` error: do not call a function with mutable arguments inside of `debug_assert!` --> $DIR/debug_assert_with_mut_call.rs:45:20 diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.stderr b/src/tools/clippy/tests/ui/decimal_literal_representation.stderr index 2f126073c33..f1d4d744e73 100644 --- a/src/tools/clippy/tests/ui/decimal_literal_representation.stderr +++ b/src/tools/clippy/tests/ui/decimal_literal_representation.stderr @@ -5,6 +5,7 @@ LL | 32_773, // 0x8005 | ^^^^^^ help: consider: `0x8005` | = note: `-D clippy::decimal-literal-representation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::decimal_literal_representation)]` error: integer literal has a better hexadecimal representation --> $DIR/decimal_literal_representation.rs:17:9 diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr index 6070df749ca..6d34373886d 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr @@ -7,6 +7,7 @@ LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(tru | make this a static item (maybe with lazy_static) | = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should never be interior mutable --> $DIR/enums.rs:23:1 diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr index 0259f6a4a28..cc286b9f7f6 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr @@ -7,6 +7,7 @@ LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); | make this a static item (maybe with lazy_static) | = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should never be interior mutable --> $DIR/others.rs:10:1 diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr index ef62919dfea..7647cd96fec 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr @@ -5,6 +5,7 @@ LL | const ATOMIC: AtomicUsize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should never be interior mutable --> $DIR/traits.rs:9:9 diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr index f8fc17e872b..bfd0de4e13a 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.stderr +++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr @@ -6,6 +6,7 @@ LL | pub fn as_ref(self) -> &'static str { | = help: consider choosing a less ambiguous name = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr index 25128b89f2e..434c72aa9b1 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr @@ -5,6 +5,7 @@ LL | Self::default() | ^^^^^^^^^^^ help: remove this call to `default` | = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_constructed_unit_structs)]` error: use of `default` to create a unit struct --> $DIR/default_constructed_unit_structs.rs:53:31 diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr index 2763ad6120e..48d6c02d150 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr @@ -5,6 +5,7 @@ LL | let _ = std::iter::Empty::<usize>::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty::<usize>()` | = note: `-D clippy::default-instead-of-iter-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_instead_of_iter_empty)]` error: `std::iter::empty()` is the more idiomatic way --> $DIR/default_instead_of_iter_empty.rs:13:13 diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr index 7aa2ad25228..7ea2e3e6819 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr @@ -5,6 +5,7 @@ LL | let x = 0.12; | ^^^^ help: consider adding suffix: `0.12_f64` | = note: `-D clippy::default-numeric-fallback` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_numeric_fallback)]` error: default numeric fallback might occur --> $DIR/default_numeric_fallback_f64.rs:22:18 diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr index 586f4fc0c03..b03b8b84c33 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr @@ -5,6 +5,7 @@ LL | let x = 22; | ^^ help: consider adding suffix: `22_i32` | = note: `-D clippy::default-numeric-fallback` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_numeric_fallback)]` error: default numeric fallback might occur --> $DIR/default_numeric_fallback_i32.rs:22:18 diff --git a/src/tools/clippy/tests/ui/default_union_representation.stderr b/src/tools/clippy/tests/ui/default_union_representation.stderr index 256eebc4420..82f69ffeec3 100644 --- a/src/tools/clippy/tests/ui/default_union_representation.stderr +++ b/src/tools/clippy/tests/ui/default_union_representation.stderr @@ -10,6 +10,7 @@ LL | | } | = help: consider annotating `NoAttribute` with `#[repr(C)]` to explicitly specify memory layout = note: `-D clippy::default-union-representation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::default_union_representation)]` error: this union has the default representation --> $DIR/default_union_representation.rs:17:1 diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index 0e142ac8f20..388fcc23846 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -5,6 +5,7 @@ LL | #![warn(clippy::should_assert_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D renamed-and-removed-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice --> $DIR/deprecated.rs:6:9 diff --git a/src/tools/clippy/tests/ui/deprecated_old.stderr b/src/tools/clippy/tests/ui/deprecated_old.stderr index 5a6c4be80b2..d27ad852f97 100644 --- a/src/tools/clippy/tests/ui/deprecated_old.stderr +++ b/src/tools/clippy/tests/ui/deprecated_old.stderr @@ -5,6 +5,7 @@ LL | #[warn(unstable_as_slice)] | ^^^^^^^^^^^^^^^^^ | = note: `-D renamed-and-removed-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 --> $DIR/deprecated_old.rs:4:8 diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index 5918a33f38b..b01fa4df6b1 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -5,6 +5,7 @@ LL | let b = *&a; | ^^^ help: try: `a` | = note: `-D clippy::deref-addrof` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::deref_addrof)]` error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:25:13 diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr index 3463f0a1ab7..78ec7340016 100644 --- a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr @@ -5,6 +5,7 @@ LL | let b = **&&a; | ^^^^ help: try: `&a` | = note: `-D clippy::deref-addrof` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::deref_addrof)]` error: immediately dereferencing a reference --> $DIR/deref_addrof_double_trigger.rs:16:17 diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.stderr b/src/tools/clippy/tests/ui/deref_by_slicing.stderr index b22c18c492d..7b8144a9a6e 100644 --- a/src/tools/clippy/tests/ui/deref_by_slicing.stderr +++ b/src/tools/clippy/tests/ui/deref_by_slicing.stderr @@ -5,6 +5,7 @@ LL | let _ = &vec[..]; | ^^^^^^^^ help: dereference the original value instead: `&*vec` | = note: `-D clippy::deref-by-slicing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::deref_by_slicing)]` error: slicing when dereferencing would work --> $DIR/deref_by_slicing.rs:9:13 diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr index b05af79e3fd..98e2f361290 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.stderr +++ b/src/tools/clippy/tests/ui/derivable_impls.stderr @@ -11,6 +11,7 @@ LL | | } | |_^ | = note: `-D clippy::derivable-impls` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::derivable_impls)]` = help: remove the manual implementation... help: ...and instead derive it | diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr index 2986296bcaf..e9b2ee34760 100644 --- a/src/tools/clippy/tests/ui/derive.stderr +++ b/src/tools/clippy/tests/ui/derive.stderr @@ -20,6 +20,7 @@ LL | | } LL | | } | |_^ = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]` error: you are implementing `Clone` explicitly on a `Copy` type --> $DIR/derive.rs:37:1 diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr index ee900c5ea27..7555c12b196 100644 --- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr @@ -10,6 +10,7 @@ note: `PartialOrd` implemented here LL | impl PartialOrd for DeriveOrd { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::derive_ord_xor_partial_ord)]` = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr index 91729abc2bb..abfd70e8c3d 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr @@ -5,6 +5,7 @@ LL | #[derive(Debug, PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` | = note: `-D clippy::derive-partial-eq-without-eq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::derive_partial_eq_without_eq)]` error: you are deriving `PartialEq` and can implement `Eq` --> $DIR/derive_partial_eq_without_eq.rs:53:10 diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr index 259501a94e7..3387906a0e5 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui/disallowed_names.stderr @@ -5,6 +5,7 @@ LL | fn test(foo: ()) {} | ^^^ | = note: `-D clippy::disallowed-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `foo` --> $DIR/disallowed_names.rs:17:9 diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr index 042e2690ec4..d8021c5d7ba 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr @@ -5,6 +5,7 @@ LL | b || diverge(); | ^^^^^^^^^ | = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::diverging_sub_expression)]` error: sub-expression diverges --> $DIR/diverging_sub_expression.rs:23:10 diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr index dda764f8493..a30ded81385 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr @@ -5,6 +5,7 @@ LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot t | ^^^^^^^ | = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` help: try | LL | /// The `foo_bar` function does _nothing_. See also foo::bar. (note the dot there) diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr index 7a3544288be..92b6f8536c8 100644 --- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr +++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr @@ -10,6 +10,7 @@ LL | | /// very `confusing_and_misleading`. | = help: a backtick may be missing a pair = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` error: backticks are unbalanced --> $DIR/unbalanced_ticks.rs:14:1 diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr index a0356623003..9cea864f1d8 100644 --- a/src/tools/clippy/tests/ui/doc_errors.stderr +++ b/src/tools/clippy/tests/ui/doc_errors.stderr @@ -5,6 +5,7 @@ LL | pub fn pub_fn_missing_errors_header() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-errors-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_errors_doc)]` error: docs for function returning `Result` missing `# Errors` section --> $DIR/doc_errors.rs:13:1 diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr index ea730e667d6..2db1bc09289 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr @@ -5,6 +5,7 @@ LL | /// Calls ['bar'] uselessly | ^^^^^ | = note: `-D clippy::doc-link-with-quotes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_link_with_quotes)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/doc_unsafe.stderr b/src/tools/clippy/tests/ui/doc_unsafe.stderr index a86e191370e..ab3fb3c029d 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.stderr +++ b/src/tools/clippy/tests/ui/doc_unsafe.stderr @@ -5,6 +5,7 @@ LL | pub unsafe fn destroy_the_planet() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-safety-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` error: unsafe function's docs miss `# Safety` section --> $DIR/doc_unsafe.rs:32:5 diff --git a/src/tools/clippy/tests/ui/double_comparison.stderr b/src/tools/clippy/tests/ui/double_comparison.stderr index 05ef4e25f7f..02f0a960974 100644 --- a/src/tools/clippy/tests/ui/double_comparison.stderr +++ b/src/tools/clippy/tests/ui/double_comparison.stderr @@ -5,6 +5,7 @@ LL | if x == y || x < y { | ^^^^^^^^^^^^^^^ help: try: `x <= y` | = note: `-D clippy::double-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_comparisons)]` error: this binary expression can be simplified --> $DIR/double_comparison.rs:9:8 diff --git a/src/tools/clippy/tests/ui/double_must_use.stderr b/src/tools/clippy/tests/ui/double_must_use.stderr index 46d56006ebf..a2d87c59ecf 100644 --- a/src/tools/clippy/tests/ui/double_must_use.stderr +++ b/src/tools/clippy/tests/ui/double_must_use.stderr @@ -6,6 +6,7 @@ LL | pub fn must_use_result() -> Result<(), ()> { | = help: either add some descriptive text or remove the attribute = note: `-D clippy::double-must-use` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]` error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` --> $DIR/double_must_use.rs:11:1 diff --git a/src/tools/clippy/tests/ui/double_neg.stderr b/src/tools/clippy/tests/ui/double_neg.stderr index 7cdb040b687..a6241c78610 100644 --- a/src/tools/clippy/tests/ui/double_neg.stderr +++ b/src/tools/clippy/tests/ui/double_neg.stderr @@ -5,6 +5,7 @@ LL | --x; | ^^^ | = note: `-D clippy::double-neg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_neg)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/double_parens.stderr b/src/tools/clippy/tests/ui/double_parens.stderr index 303ddce0248..8a010d8ccc0 100644 --- a/src/tools/clippy/tests/ui/double_parens.stderr +++ b/src/tools/clippy/tests/ui/double_parens.stderr @@ -5,6 +5,7 @@ LL | ((0)) | ^^^^^ | = note: `-D clippy::double-parens` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_parens)]` error: consider removing unnecessary double parentheses --> $DIR/double_parens.rs:21:14 diff --git a/src/tools/clippy/tests/ui/drop_non_drop.stderr b/src/tools/clippy/tests/ui/drop_non_drop.stderr index 15e7c6eeca2..a571076f68c 100644 --- a/src/tools/clippy/tests/ui/drop_non_drop.stderr +++ b/src/tools/clippy/tests/ui/drop_non_drop.stderr @@ -10,6 +10,7 @@ note: argument has type `main::Foo` LL | drop(Foo); | ^^^ = note: `-D clippy::drop-non-drop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::drop_non_drop)]` error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes --> $DIR/drop_non_drop.rs:38:5 diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr b/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr index f71614a5fd1..f47f6c89622 100644 --- a/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr +++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr @@ -5,6 +5,7 @@ LL | fn join_the_dark_side(darth: i32, _darth: i32) {} | ^^^^^ | = note: `-D clippy::duplicate-underscore-argument` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duplicate_underscore_argument)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/duration_subsec.stderr b/src/tools/clippy/tests/ui/duration_subsec.stderr index 6c1fd433e7c..70568383712 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.stderr +++ b/src/tools/clippy/tests/ui/duration_subsec.stderr @@ -5,6 +5,7 @@ LL | let bad_millis_1 = dur.subsec_micros() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` | = note: `-D clippy::duration-subsec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::duration_subsec)]` error: calling `subsec_millis()` is more concise than this calculation --> $DIR/duration_subsec.rs:10:24 diff --git a/src/tools/clippy/tests/ui/else_if_without_else.stderr b/src/tools/clippy/tests/ui/else_if_without_else.stderr index 11baf75441a..b2bf4ac4d1b 100644 --- a/src/tools/clippy/tests/ui/else_if_without_else.stderr +++ b/src/tools/clippy/tests/ui/else_if_without_else.stderr @@ -10,6 +10,7 @@ LL | | } | = help: add an `else` block here = note: `-D clippy::else-if-without-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::else_if_without_else)]` error: `if` expression with an `else if`, but without a final `else` --> $DIR/else_if_without_else.rs:54:12 diff --git a/src/tools/clippy/tests/ui/empty_drop.stderr b/src/tools/clippy/tests/ui/empty_drop.stderr index e9521693726..5848eab7447 100644 --- a/src/tools/clippy/tests/ui/empty_drop.stderr +++ b/src/tools/clippy/tests/ui/empty_drop.stderr @@ -7,6 +7,7 @@ LL | | } | |_^ help: try removing this impl | = note: `-D clippy::empty-drop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_drop)]` error: empty drop implementation --> $DIR/empty_drop.rs:23:1 diff --git a/src/tools/clippy/tests/ui/empty_enum.stderr b/src/tools/clippy/tests/ui/empty_enum.stderr index 0d9aa5818e2..92d81c7269a 100644 --- a/src/tools/clippy/tests/ui/empty_enum.stderr +++ b/src/tools/clippy/tests/ui/empty_enum.stderr @@ -6,6 +6,7 @@ LL | enum Empty {} | = help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated = note: `-D clippy::empty-enum` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_enum)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr index 2ca1b51679e..2cf5b5b0f54 100644 --- a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr @@ -7,6 +7,7 @@ LL | | fn with_doc_and_newline() { assert!(true)} | |_ | = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? --> $DIR/empty_line_after_doc_comments.rs:68:1 diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr index 594fca44a32..0cb848c20dd 100644 --- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr +++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr @@ -8,6 +8,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) } | |_ | = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? --> $DIR/empty_line_after_outer_attribute.rs:23:1 diff --git a/src/tools/clippy/tests/ui/empty_loop.stderr b/src/tools/clippy/tests/ui/empty_loop.stderr index 7602412334b..84d7d61c7da 100644 --- a/src/tools/clippy/tests/ui/empty_loop.stderr +++ b/src/tools/clippy/tests/ui/empty_loop.stderr @@ -6,6 +6,7 @@ LL | loop {} | = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body = note: `-D clippy::empty-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]` error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:11:9 diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr index 417b7f01c78..90200826472 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr @@ -6,6 +6,7 @@ LL | loop {} | = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body = note: `-D clippy::empty-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]` error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop_no_std.rs:26:5 diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr b/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr index ba3013750d5..4b8572d5c9e 100644 --- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr +++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr @@ -5,6 +5,7 @@ LL | pub struct MyEmptyStruct {} // should trigger lint | ^^^ | = note: `-D clippy::empty-structs-with-brackets` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_structs_with_brackets)]` = help: remove the brackets error: found empty brackets on struct declaration diff --git a/src/tools/clippy/tests/ui/endian_bytes.stderr b/src/tools/clippy/tests/ui/endian_bytes.stderr index 5e64ea5b5ab..a458c46fa69 100644 --- a/src/tools/clippy/tests/ui/endian_bytes.stderr +++ b/src/tools/clippy/tests/ui/endian_bytes.stderr @@ -9,6 +9,7 @@ LL | fn host() { fn_body!(); } | = help: specify the desired endianness explicitly = note: `-D clippy::host-endian-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::host_endian_bytes)]` = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i8::to_ne_bytes` method @@ -346,6 +347,7 @@ LL | fn little() { fn_body!(); } | = help: use the native endianness instead = note: `-D clippy::little-endian-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::little_endian_bytes)]` = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i8::to_le_bytes` method @@ -707,6 +709,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } | = help: use `u8::to_le_bytes` instead = note: `-D clippy::big-endian-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::big_endian_bytes)]` = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr index e89d15cc1af..b01f0a9a0e5 100644 --- a/src/tools/clippy/tests/ui/entry.stderr +++ b/src/tools/clippy/tests/ui/entry.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: try: `m.entry(k).or_insert(v);` | = note: `-D clippy::map-entry` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:29:5 diff --git a/src/tools/clippy/tests/ui/entry_btree.stderr b/src/tools/clippy/tests/ui/entry_btree.stderr index e5a1365eae9..cc0e951d9b4 100644 --- a/src/tools/clippy/tests/ui/entry_btree.stderr +++ b/src/tools/clippy/tests/ui/entry_btree.stderr @@ -8,6 +8,7 @@ LL | | } | |_____^ | = note: `-D clippy::map-entry` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` help: try | LL ~ if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { diff --git a/src/tools/clippy/tests/ui/entry_with_else.stderr b/src/tools/clippy/tests/ui/entry_with_else.stderr index a0f39568708..425e87122d5 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.stderr +++ b/src/tools/clippy/tests/ui/entry_with_else.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::map-entry` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` help: try | LL ~ match m.entry(k) { diff --git a/src/tools/clippy/tests/ui/enum_glob_use.stderr b/src/tools/clippy/tests/ui/enum_glob_use.stderr index c1851f92765..8b94e67f87e 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.stderr +++ b/src/tools/clippy/tests/ui/enum_glob_use.stderr @@ -5,6 +5,7 @@ LL | use std::cmp::Ordering::*; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::cmp::Ordering::Less` | = note: `-D clippy::enum-glob-use` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::enum_glob_use)]` error: usage of wildcard import for enum variants --> $DIR/enum_glob_use.rs:11:5 diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index 1cfe48cd797..9ea80b635f4 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -5,6 +5,7 @@ LL | cFoo, | ^^^^ | = note: `-D clippy::enum-variant-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]` error: all variants have the same prefix: `c` --> $DIR/enum_variants.rs:14:1 diff --git a/src/tools/clippy/tests/ui/eprint_with_newline.stderr b/src/tools/clippy/tests/ui/eprint_with_newline.stderr index 934c4c83173..674b4fdaed5 100644 --- a/src/tools/clippy/tests/ui/eprint_with_newline.stderr +++ b/src/tools/clippy/tests/ui/eprint_with_newline.stderr @@ -5,6 +5,7 @@ LL | eprint!("Hello\n"); | ^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::print-with-newline` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_with_newline)]` help: use `eprintln!` instead | LL - eprint!("Hello\n"); diff --git a/src/tools/clippy/tests/ui/eq_op.stderr b/src/tools/clippy/tests/ui/eq_op.stderr index 315d94cc90e..2427ac0dda5 100644 --- a/src/tools/clippy/tests/ui/eq_op.stderr +++ b/src/tools/clippy/tests/ui/eq_op.stderr @@ -5,6 +5,7 @@ LL | let _ = 1 == 1; | ^^^^^^ | = note: `-D clippy::eq-op` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::eq_op)]` error: equal expressions as operands to `==` --> $DIR/eq_op.rs:10:13 diff --git a/src/tools/clippy/tests/ui/eq_op_macros.stderr b/src/tools/clippy/tests/ui/eq_op_macros.stderr index 3c60cdbc5ca..0df26607aa6 100644 --- a/src/tools/clippy/tests/ui/eq_op_macros.stderr +++ b/src/tools/clippy/tests/ui/eq_op_macros.stderr @@ -8,6 +8,7 @@ LL | assert_in_macro_def!(); | ---------------------- in this macro invocation | = note: `-D clippy::eq-op` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::eq_op)]` = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `assert_ne!` macro call diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr index 3b6cbbabbe2..6cc19d829ed 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.stderr +++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr @@ -5,6 +5,7 @@ LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` | = note: `-D clippy::equatable-if-let` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` error: this pattern matching can be expressed using equality --> $DIR/equatable_if_let.rs:65:8 diff --git a/src/tools/clippy/tests/ui/erasing_op.stderr b/src/tools/clippy/tests/ui/erasing_op.stderr index 7b9608fe452..1b50a05cd22 100644 --- a/src/tools/clippy/tests/ui/erasing_op.stderr +++ b/src/tools/clippy/tests/ui/erasing_op.stderr @@ -5,6 +5,7 @@ LL | x * 0; | ^^^^^ | = note: `-D clippy::erasing-op` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::erasing_op)]` error: this operation will always return zero. This is likely not the intended outcome --> $DIR/erasing_op.rs:38:5 diff --git a/src/tools/clippy/tests/ui/err_expect.stderr b/src/tools/clippy/tests/ui/err_expect.stderr index e3046a5a13a..da7cd47f0bb 100644 --- a/src/tools/clippy/tests/ui/err_expect.stderr +++ b/src/tools/clippy/tests/ui/err_expect.stderr @@ -5,6 +5,7 @@ LL | test_debug.err().expect("Testing debug type"); | ^^^^^^^^^^^^ help: try: `expect_err` | = note: `-D clippy::err-expect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::err_expect)]` error: called `.err().expect()` on a `Result` value --> $DIR/err_expect.rs:25:7 diff --git a/src/tools/clippy/tests/ui/error_impl_error.stderr b/src/tools/clippy/tests/ui/error_impl_error.stderr index 54a55d5dcf4..d7a1aa82989 100644 --- a/src/tools/clippy/tests/ui/error_impl_error.stderr +++ b/src/tools/clippy/tests/ui/error_impl_error.stderr @@ -10,6 +10,7 @@ note: `Error` was implemented here LL | impl std::error::Error for Error {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::error-impl-error` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::error_impl_error)]` error: exported type named `Error` that implements `Error` --> $DIR/error_impl_error.rs:21:21 diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index db6184e36a4..7c7f1797462 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -5,6 +5,7 @@ LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` | = note: `-D clippy::redundant-closure` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: redundant closure --> $DIR/eta.rs:32:40 @@ -37,6 +38,7 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` | = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]` error: redundant closure --> $DIR/eta.rs:94:51 diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr index a1f874e93d4..5e7672e185a 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.stderr +++ b/src/tools/clippy/tests/ui/excessive_precision.stderr @@ -5,6 +5,7 @@ LL | const BAD32_1: f32 = 0.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32` | = note: `-D clippy::excessive-precision` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::excessive_precision)]` error: float has excessive precision --> $DIR/excessive_precision.rs:21:26 diff --git a/src/tools/clippy/tests/ui/exit1.stderr b/src/tools/clippy/tests/ui/exit1.stderr index a8d3956aa27..94d8f1e32ee 100644 --- a/src/tools/clippy/tests/ui/exit1.stderr +++ b/src/tools/clippy/tests/ui/exit1.stderr @@ -5,6 +5,7 @@ LL | std::process::exit(4); | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::exit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::exit)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/exit2.stderr b/src/tools/clippy/tests/ui/exit2.stderr index 7263e156a9d..cd324f18220 100644 --- a/src/tools/clippy/tests/ui/exit2.stderr +++ b/src/tools/clippy/tests/ui/exit2.stderr @@ -5,6 +5,7 @@ LL | std::process::exit(3); | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::exit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::exit)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr index c9a29624d53..35a258a85e4 100644 --- a/src/tools/clippy/tests/ui/expect.stderr +++ b/src/tools/clippy/tests/ui/expect.stderr @@ -6,6 +6,7 @@ LL | let _ = opt.expect(""); | = note: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::expect_used)]` error: used `expect()` on a `Result` value --> $DIR/expect.rs:12:13 diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr index b5ab580ad00..dd3976f3624 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.stderr +++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr @@ -5,6 +5,7 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` | = note: `-D clippy::expect-fun-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::expect_fun_call)]` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:40:26 diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr index 1a08d77113a..3f8d0b72436 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -5,6 +5,7 @@ LL | #[expect(dead_code)] | ^^^^^^^^^ | = note: `-D unfulfilled-lint-expectations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]` error: this lint expectation is unfulfilled --> $DIR/expect_tool_lint_rfc_2383.rs:41:18 diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr index 34ce188530c..bea014d8ad5 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr @@ -5,6 +5,7 @@ LL | let _: &str = &*s; | ^^^ help: try: `&s` | = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::explicit_auto_deref)]` error: deref which would be done by auto-deref --> $DIR/explicit_auto_deref.rs:69:19 diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr index 3b36f28617b..aef97907252 100644 --- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr @@ -5,6 +5,7 @@ LL | for _v in &vec { | ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()` | = note: `-D clippy::explicit-counter-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::explicit_counter_loop)]` error: the variable `_index` is used as a loop counter --> $DIR/explicit_counter_loop.rs:15:5 diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr index 362e559b21a..eb7059367a2 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr @@ -5,6 +5,7 @@ LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try: `&*a` | = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]` error: explicit `deref_mut` method call --> $DIR/explicit_deref_methods.rs:56:23 diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr index 744be093b7b..c03647ab433 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr @@ -5,6 +5,7 @@ LL | for _ in iterator.into_iter() {} | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` | = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::explicit_into_iter_loop)]` error: it is more concise to loop over containers instead of using explicit iteration methods --> $DIR/explicit_into_iter_loop.rs:22:14 diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr index c311096117f..af46d74e989 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr @@ -53,6 +53,7 @@ LL | for _ in (&mut [1, 2, 3]).iter() {} | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` error: it is more concise to loop over references to containers instead of using explicit iteration methods --> $DIR/explicit_iter_loop.rs:33:14 diff --git a/src/tools/clippy/tests/ui/explicit_write.stderr b/src/tools/clippy/tests/ui/explicit_write.stderr index 230762c2db1..26aad266bbf 100644 --- a/src/tools/clippy/tests/ui/explicit_write.stderr +++ b/src/tools/clippy/tests/ui/explicit_write.stderr @@ -5,6 +5,7 @@ LL | write!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")` | = note: `-D clippy::explicit-write` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::explicit_write)]` error: use of `write!(stderr(), ...).unwrap()` --> $DIR/explicit_write.rs:24:9 diff --git a/src/tools/clippy/tests/ui/extend_with_drain.stderr b/src/tools/clippy/tests/ui/extend_with_drain.stderr index 2c06d71e102..e0bd5a620e7 100644 --- a/src/tools/clippy/tests/ui/extend_with_drain.stderr +++ b/src/tools/clippy/tests/ui/extend_with_drain.stderr @@ -5,6 +5,7 @@ LL | vec2.extend(vec1.drain(..)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec2.append(&mut vec1)` | = note: `-D clippy::extend-with-drain` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::extend_with_drain)]` error: use of `extend` instead of `append` for adding the full range of a second vector --> $DIR/extend_with_drain.rs:13:5 diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr index 26ebc3976df..8790fe5a5b1 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr @@ -5,6 +5,7 @@ LL | fn unused_lt<'a>(x: u8) {} | ^^ | = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::extra_unused_lifetimes)]` error: this lifetime isn't used in the function definition --> $DIR/extra_unused_lifetimes.rs:46:10 diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr index 82cdc95a1d1..9a179076c48 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr @@ -5,6 +5,7 @@ LL | fn unused_ty<T>(x: u8) { | ^^^ help: consider removing the parameter | = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::extra_unused_type_parameters)]` error: type parameters go unused in function definition: T, U --> $DIR/extra_unused_type_parameters.rs:13:16 diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.stderr b/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.stderr index bbd0cf478ab..a216c436307 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.stderr @@ -6,6 +6,7 @@ LL | fn unused_where_clause<T, U>(x: U) | = help: consider removing the parameter = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::extra_unused_type_parameters)]` error: type parameters go unused in function definition: T, V --> $DIR/extra_unused_type_parameters_unfixable.rs:11:30 diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr index da74f9ef9f7..a8cf84bd411 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr @@ -10,6 +10,7 @@ note: consider initializing the variable with `main::A { i: 42, ..Default::defau LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::field_reassign_with_default)]` error: field assignment outside of initializer for an instance created with Default::default() --> $DIR/field_reassign_with_default.rs:96:5 diff --git a/src/tools/clippy/tests/ui/filetype_is_file.stderr b/src/tools/clippy/tests/ui/filetype_is_file.stderr index 718d287e679..8876ad5c9bb 100644 --- a/src/tools/clippy/tests/ui/filetype_is_file.stderr +++ b/src/tools/clippy/tests/ui/filetype_is_file.stderr @@ -6,6 +6,7 @@ LL | if fs::metadata("foo.txt")?.file_type().is_file() { | = help: use `!FileType::is_dir()` instead = note: `-D clippy::filetype-is-file` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filetype_is_file)]` error: `!FileType::is_file()` only denies regular files --> $DIR/filetype_is_file.rs:15:8 diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr index c4215791c46..86ef6edf8ee 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr @@ -5,6 +5,7 @@ LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` | = note: `-D clippy::filter-map-bool-then` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]` error: usage of `bool::then` in `filter_map` --> $DIR/filter_map_bool_then.rs:20:27 diff --git a/src/tools/clippy/tests/ui/filter_map_identity.stderr b/src/tools/clippy/tests/ui/filter_map_identity.stderr index 248f6318f76..a08477695c9 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.stderr +++ b/src/tools/clippy/tests/ui/filter_map_identity.stderr @@ -5,6 +5,7 @@ LL | let _ = iterator.filter_map(|x| x); | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` | = note: `-D clippy::filter-map-identity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_map_identity)]` error: use of `filter_map` with an identity function --> $DIR/filter_map_identity.rs:9:22 diff --git a/src/tools/clippy/tests/ui/filter_map_next.stderr b/src/tools/clippy/tests/ui/filter_map_next.stderr index 3220ee51c2a..1841553917f 100644 --- a/src/tools/clippy/tests/ui/filter_map_next.stderr +++ b/src/tools/clippy/tests/ui/filter_map_next.stderr @@ -12,6 +12,7 @@ LL | | .next(); | |_______________^ | = note: `-D clippy::filter-map-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_map_next)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr index fcbdbc31f35..0edf4e6e07d 100644 --- a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr +++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr @@ -5,6 +5,7 @@ LL | let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())` | = note: `-D clippy::filter-map-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_map_next)]` error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead --> $DIR/filter_map_next_fixable.rs:20:26 diff --git a/src/tools/clippy/tests/ui/flat_map_identity.stderr b/src/tools/clippy/tests/ui/flat_map_identity.stderr index 6e4637874ac..d6fcc14fc56 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.stderr +++ b/src/tools/clippy/tests/ui/flat_map_identity.stderr @@ -5,6 +5,7 @@ LL | let _ = iterator.flat_map(|x| x); | ^^^^^^^^^^^^^^^ help: try: `flatten()` | = note: `-D clippy::flat-map-identity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::flat_map_identity)]` error: use of `flat_map` with an identity function --> $DIR/flat_map_identity.rs:11:22 diff --git a/src/tools/clippy/tests/ui/flat_map_option.stderr b/src/tools/clippy/tests/ui/flat_map_option.stderr index c750902eb2f..e0a59daf6a8 100644 --- a/src/tools/clippy/tests/ui/flat_map_option.stderr +++ b/src/tools/clippy/tests/ui/flat_map_option.stderr @@ -5,6 +5,7 @@ LL | let _ = [1].iter().flat_map(c); | ^^^^^^^^ help: try: `filter_map` | = note: `-D clippy::flat-map-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::flat_map_option)]` error: used `flat_map` where `filter_map` could be used instead --> $DIR/flat_map_option.rs:8:24 diff --git a/src/tools/clippy/tests/ui/float_arithmetic.stderr b/src/tools/clippy/tests/ui/float_arithmetic.stderr index fe8446c9816..da4ca976792 100644 --- a/src/tools/clippy/tests/ui/float_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/float_arithmetic.stderr @@ -5,6 +5,7 @@ LL | f * 2.0; | ^^^^^^^ | = note: `-D clippy::float-arithmetic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::float_arithmetic)]` error: floating-point arithmetic detected --> $DIR/float_arithmetic.rs:19:5 diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr index 5836b5603d6..cbe529954d0 100644 --- a/src/tools/clippy/tests/ui/float_cmp.stderr +++ b/src/tools/clippy/tests/ui/float_cmp.stderr @@ -6,6 +6,7 @@ LL | ONE as f64 != 2.0; | = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]` error: strict comparison of `f32` or `f64` --> $DIR/float_cmp.rs:64:5 diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr index 4de1d58adc0..856aaa2ea71 100644 --- a/src/tools/clippy/tests/ui/float_cmp_const.stderr +++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr @@ -6,6 +6,7 @@ LL | 1f32 == ONE; | = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin` = note: `-D clippy::float-cmp-const` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]` error: strict comparison of `f32` or `f64` constant --> $DIR/float_cmp_const.rs:19:5 diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr index c9806019f1f..155699f6fcf 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr @@ -7,6 +7,7 @@ LL | (a - b) < f32::EPSILON | help: add `.abs()`: `(a - b).abs()` | = note: `-D clippy::float-equality-without-abs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::float_equality_without_abs)]` error: float equality check without `.abs()` --> $DIR/float_equality_without_abs.rs:15:13 diff --git a/src/tools/clippy/tests/ui/floating_point_abs.stderr b/src/tools/clippy/tests/ui/floating_point_abs.stderr index 464a0af5f9f..fbc5783824d 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.stderr +++ b/src/tools/clippy/tests/ui/floating_point_abs.stderr @@ -5,6 +5,7 @@ LL | if num >= 0.0 { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: manual implementation of `abs` method --> $DIR/floating_point_abs.rs:19:5 diff --git a/src/tools/clippy/tests/ui/floating_point_exp.stderr b/src/tools/clippy/tests/ui/floating_point_exp.stderr index f84eede1987..6b64b9b6008 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.stderr +++ b/src/tools/clippy/tests/ui/floating_point_exp.stderr @@ -5,6 +5,7 @@ LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` | = note: `-D clippy::imprecise-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: (e.pow(x) - 1) can be computed more accurately --> $DIR/floating_point_exp.rs:7:13 diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.stderr b/src/tools/clippy/tests/ui/floating_point_hypot.stderr index 82b0ed31204..21e0bd8b581 100644 --- a/src/tools/clippy/tests/ui/floating_point_hypot.stderr +++ b/src/tools/clippy/tests/ui/floating_point_hypot.stderr @@ -5,6 +5,7 @@ LL | let _ = (x * x + y * y).sqrt(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)` | = note: `-D clippy::imprecise-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: hypotenuse can be computed more accurately --> $DIR/floating_point_hypot.rs:7:13 diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr index cbadd239aa2..a426f4c3dde 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.stderr +++ b/src/tools/clippy/tests/ui/floating_point_log.stderr @@ -5,6 +5,7 @@ LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: logarithm for bases 2, 10 and e can be computed more accurately --> $DIR/floating_point_log.rs:10:13 @@ -61,6 +62,7 @@ LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` | = note: `-D clippy::imprecise-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:25:13 diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.stderr b/src/tools/clippy/tests/ui/floating_point_logbase.stderr index 384e3554cbb..463bdb84c15 100644 --- a/src/tools/clippy/tests/ui/floating_point_logbase.stderr +++ b/src/tools/clippy/tests/ui/floating_point_logbase.stderr @@ -5,6 +5,7 @@ LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: log base can be expressed more clearly --> $DIR/floating_point_logbase.rs:8:13 diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr index 613954724a5..81b7126db54 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr @@ -5,6 +5,7 @@ LL | let _ = a * b + c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: multiply and add expressions can be calculated more efficiently and accurately --> $DIR/floating_point_mul_add.rs:21:13 diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr index e9693de8fc9..0ff8f82d9a7 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr @@ -5,6 +5,7 @@ LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: exponent for bases 2 and e can be computed more accurately --> $DIR/floating_point_powf.rs:7:13 @@ -49,6 +50,7 @@ LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` | = note: `-D clippy::imprecise-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: cube-root of a number can be computed more accurately --> $DIR/floating_point_powf.rs:14:13 diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr index d60885e1b9a..ddf20ff40ba 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr @@ -5,6 +5,7 @@ LL | let _ = x.powi(2) + y; | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: multiply and add expressions can be calculated more efficiently and accurately --> $DIR/floating_point_powi.rs:10:13 diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr index 914358c9867..e7b42de04bd 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.stderr +++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr @@ -5,6 +5,7 @@ LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: conversion to degrees can be done more accurately --> $DIR/floating_point_rad.rs:12:13 diff --git a/src/tools/clippy/tests/ui/fn_address_comparisons.stderr b/src/tools/clippy/tests/ui/fn_address_comparisons.stderr index 87415a0d904..be7fa62f1b7 100644 --- a/src/tools/clippy/tests/ui/fn_address_comparisons.stderr +++ b/src/tools/clippy/tests/ui/fn_address_comparisons.stderr @@ -5,6 +5,7 @@ LL | let _ = f == a; | ^^^^^^ | = note: `-D clippy::fn-address-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::fn_address_comparisons)]` error: comparing with a non-unique address of a function item --> $DIR/fn_address_comparisons.rs:18:13 diff --git a/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr b/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr index db09418cd80..f529d8cc411 100644 --- a/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr +++ b/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr @@ -6,6 +6,7 @@ LL | fn g(_: bool, _: bool, _: bool, _: bool) {} | = help: consider refactoring bools into two-variant enums = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::fn_params_excessive_bools)]` error: more than 3 bools in function parameters --> $DIR/fn_params_excessive_bools.rs:23:1 diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr index 5b2e8bdf30b..53e8ac3c4b4 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr @@ -5,6 +5,7 @@ LL | let _ = foo as i8; | ^^^^^^^^^ help: try: `foo as usize` | = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_with_truncation)]` error: casting function pointer `foo` to `i16`, which truncates the value --> $DIR/fn_to_numeric_cast.rs:13:13 @@ -25,6 +26,7 @@ LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` | = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast)]` error: casting function pointer `foo` to `i128` --> $DIR/fn_to_numeric_cast.rs:20:13 diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr index 36058965479..a1514c87b5e 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr @@ -5,6 +5,7 @@ LL | let _ = foo as i8; | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8` | = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_any)]` error: casting function pointer `foo` to `i16` --> $DIR/fn_to_numeric_cast_any.rs:26:13 diff --git a/src/tools/clippy/tests/ui/for_kv_map.stderr b/src/tools/clippy/tests/ui/for_kv_map.stderr index d5e4ef0b4ba..d29617e24f2 100644 --- a/src/tools/clippy/tests/ui/for_kv_map.stderr +++ b/src/tools/clippy/tests/ui/for_kv_map.stderr @@ -5,6 +5,7 @@ LL | for (_, v) in &m { | ^^ | = note: `-D clippy::for-kv-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::for_kv_map)]` help: use the corresponding method | LL | for v in m.values() { diff --git a/src/tools/clippy/tests/ui/forget_non_drop.stderr b/src/tools/clippy/tests/ui/forget_non_drop.stderr index 4634dc67f02..c0fa433c479 100644 --- a/src/tools/clippy/tests/ui/forget_non_drop.stderr +++ b/src/tools/clippy/tests/ui/forget_non_drop.stderr @@ -10,6 +10,7 @@ note: argument has type `main::Foo` LL | forget(Foo); | ^^^ = note: `-D clippy::forget-non-drop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::forget_non_drop)]` error: call to `std::mem::forget` with a value that does not implement `Drop`. Forgetting such a type is the same as dropping it --> $DIR/forget_non_drop.rs:25:5 diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr index 7019e2c8675..d4630a8f1da 100644 --- a/src/tools/clippy/tests/ui/format.stderr +++ b/src/tools/clippy/tests/ui/format.stderr @@ -5,6 +5,7 @@ LL | format!("foo"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` | = note: `-D clippy::useless-format` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_format)]` error: useless use of `format!` --> $DIR/format.rs:21:5 diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr index a922f293b48..dcdfa668aff 100644 --- a/src/tools/clippy/tests/ui/format_args.stderr +++ b/src/tools/clippy/tests/ui/format_args.stderr @@ -5,6 +5,7 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ | ^^^^^^^^^^^^ help: remove this | = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::to_string_in_format_args)]` error: `to_string` applied to a type that implements `Display` in `write!` args --> $DIR/format_args.rs:80:27 diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.stderr b/src/tools/clippy/tests/ui/format_args_unfixable.stderr index 430c4359579..3ffe2f6c894 100644 --- a/src/tools/clippy/tests/ui/format_args_unfixable.stderr +++ b/src/tools/clippy/tests/ui/format_args_unfixable.stderr @@ -7,6 +7,7 @@ LL | println!("error: {}", format!("something failed at {}", Location::calle = help: combine the `format!(..)` arguments with the outer `println!(..)` call = help: or consider changing `format!` to `format_args!` = note: `-D clippy::format-in-format-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_in_format_args)]` error: `format!` in `println!` args --> $DIR/format_args_unfixable.rs:28:5 diff --git a/src/tools/clippy/tests/ui/format_collect.stderr b/src/tools/clippy/tests/ui/format_collect.stderr index 79e353111f3..340218ccf2c 100644 --- a/src/tools/clippy/tests/ui/format_collect.stderr +++ b/src/tools/clippy/tests/ui/format_collect.stderr @@ -16,6 +16,7 @@ LL | bytes.iter().map(|b| format!("{b:02X}")).collect() | ^^^^^^^^^^^^^^^^^^ = note: this can be written more efficiently by appending to a `String` directly = note: `-D clippy::format-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_collect)]` error: use of `format!` to build up a string from an iterator --> $DIR/format_collect.rs:11:5 diff --git a/src/tools/clippy/tests/ui/format_push_string.stderr b/src/tools/clippy/tests/ui/format_push_string.stderr index d862dd6dc5f..545915b56b5 100644 --- a/src/tools/clippy/tests/ui/format_push_string.stderr +++ b/src/tools/clippy/tests/ui/format_push_string.stderr @@ -6,6 +6,7 @@ LL | string += &format!("{:?}", 1234); | = help: consider using `write!` to avoid the extra allocation = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` error: `format!(..)` appended to existing `String` --> $DIR/format_push_string.rs:7:5 diff --git a/src/tools/clippy/tests/ui/formatting.stderr b/src/tools/clippy/tests/ui/formatting.stderr index 1266d143cb1..d4eb8e511c8 100644 --- a/src/tools/clippy/tests/ui/formatting.stderr +++ b/src/tools/clippy/tests/ui/formatting.stderr @@ -6,6 +6,7 @@ LL | a =- 35; | = note: to remove this lint, use either `-=` or `= -` = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_assignment_formatting)]` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` --> $DIR/formatting.rs:19:6 @@ -31,6 +32,7 @@ LL | -1, -2, -3 // <= no comma here | = note: to remove this lint, add a comma or write the expr in a single line = note: `-D clippy::possible-missing-comma` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::possible_missing_comma)]` error: possibly missing a comma here --> $DIR/formatting.rs:41:19 diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr index 89162e6b010..6450c5f9460 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr @@ -6,6 +6,7 @@ LL | | fn a() {} | |_ | = note: `-D clippy::four-forward-slashes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::four_forward_slashes)]` help: make this a doc comment by removing one `/` | LL + /// whoops diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr index 7944da14feb..afb7c6b4dbd 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr @@ -6,6 +6,7 @@ LL | | fn a() {} | |_ | = note: `-D clippy::four-forward-slashes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::four_forward_slashes)]` help: make this a doc comment by removing one `/` | LL + /// borked doc comment on the first line. doesn't combust! diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr index e42851bf846..6e86341d157 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr @@ -5,6 +5,7 @@ LL | <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::from_iter_instead_of_collect)]` error: usage of `FromIterator::from_iter` --> $DIR/from_iter_instead_of_collect.rs:23:13 diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index 96afec3de30..784843ce5fd 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -5,6 +5,7 @@ LL | impl Into<StringWrapper> for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::from-over-into` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::from_over_into)]` help: replace the `Into` implementation with `From<std::string::String>` | LL ~ impl From<String> for StringWrapper { diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr index 3470eff9e95..8ef36f082e0 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr @@ -6,6 +6,7 @@ LL | impl Into<InMacro> for String { | = help: replace the `Into` implementation with `From<std::string::String>` = note: `-D clippy::from-over-into` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::from_over_into)]` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true --> $DIR/from_over_into_unfixable.rs:20:1 diff --git a/src/tools/clippy/tests/ui/from_raw_with_void_ptr.stderr b/src/tools/clippy/tests/ui/from_raw_with_void_ptr.stderr index b6460862419..6e1ad0d99c4 100644 --- a/src/tools/clippy/tests/ui/from_raw_with_void_ptr.stderr +++ b/src/tools/clippy/tests/ui/from_raw_with_void_ptr.stderr @@ -10,6 +10,7 @@ help: cast this to a pointer of the appropriate type LL | let _ = unsafe { Box::from_raw(ptr) }; | ^^^ = note: `-D clippy::from-raw-with-void-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::from_raw_with_void_ptr)]` error: creating a `Rc` from a void raw pointer --> $DIR/from_raw_with_void_ptr.rs:23:22 diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr index 1fbd1e3a5f2..439dcff74d9 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -5,6 +5,7 @@ LL | u32::from_str_radix("30", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()` | = note: `-D clippy::from-str-radix-10` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]` error: this call to `from_str_radix` can be replaced with a call to `str::parse` --> $DIR/from_str_radix_10.rs:31:5 diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr index fb8f4511e99..371ea161260 100644 --- a/src/tools/clippy/tests/ui/functions.stderr +++ b/src/tools/clippy/tests/ui/functions.stderr @@ -5,6 +5,7 @@ LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::too-many-arguments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]` error: this function has too many arguments (8/7) --> $DIR/functions.rs:13:1 @@ -37,6 +38,7 @@ LL | println!("{}", unsafe { *p }); | ^ | = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::not_unsafe_ptr_arg_deref)]` error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:71:35 diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr index 6551892363c..1d6ddad79ff 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.stderr +++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr @@ -11,6 +11,7 @@ LL | | } | |_^ | = note: `-D clippy::too-many-lines` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr index 9628cf3a1b9..e417de723ff 100644 --- a/src/tools/clippy/tests/ui/future_not_send.stderr +++ b/src/tools/clippy/tests/ui/future_not_send.stderr @@ -27,6 +27,7 @@ LL | } | - `cell` is later dropped here = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` = note: `-D clippy::future-not-send` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:12:42 diff --git a/src/tools/clippy/tests/ui/get_first.stderr b/src/tools/clippy/tests/ui/get_first.stderr index 51ebb1f3f06..56b4c29a313 100644 --- a/src/tools/clippy/tests/ui/get_first.stderr +++ b/src/tools/clippy/tests/ui/get_first.stderr @@ -5,6 +5,7 @@ LL | let _ = x.get(0); // Use x.first() | ^^^^^^^^ help: try: `x.first()` | = note: `-D clippy::get-first` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::get_first)]` error: accessing first element with `y.get(0)` --> $DIR/get_first.rs:22:13 diff --git a/src/tools/clippy/tests/ui/get_last_with_len.stderr b/src/tools/clippy/tests/ui/get_last_with_len.stderr index 8e852bbb265..0056adc57f2 100644 --- a/src/tools/clippy/tests/ui/get_last_with_len.stderr +++ b/src/tools/clippy/tests/ui/get_last_with_len.stderr @@ -5,6 +5,7 @@ LL | let _ = x.get(x.len() - 1); | ^^^^^^^^^^^^^^^^^^ help: try: `x.last()` | = note: `-D clippy::get-last-with-len` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::get_last_with_len)]` error: accessing last element with `s.field.get(s.field.len() - 1)` --> $DIR/get_last_with_len.rs:32:13 diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr index 242c339bbf1..384860ea116 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.stderr +++ b/src/tools/clippy/tests/ui/get_unwrap.stderr @@ -19,6 +19,7 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: if this value is `None`, it will panic = help: consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:37:17 diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr index cb251935b60..2a61327f15f 100644 --- a/src/tools/clippy/tests/ui/identity_op.stderr +++ b/src/tools/clippy/tests/ui/identity_op.stderr @@ -5,6 +5,7 @@ LL | x + 0; | ^^^^^ help: consider reducing it to: `x` | = note: `-D clippy::identity-op` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::identity_op)]` error: this operation has no effect --> $DIR/identity_op.rs:43:5 diff --git a/src/tools/clippy/tests/ui/if_let_mutex.stderr b/src/tools/clippy/tests/ui/if_let_mutex.stderr index 6bbaadbe855..8934294430b 100644 --- a/src/tools/clippy/tests/ui/if_let_mutex.stderr +++ b/src/tools/clippy/tests/ui/if_let_mutex.stderr @@ -16,6 +16,7 @@ LL | | }; | = help: move the lock call outside of the `if let ...` expression = note: `-D clippy::if-let-mutex` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::if_let_mutex)]` error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock --> $DIR/if_let_mutex.rs:23:5 diff --git a/src/tools/clippy/tests/ui/if_not_else.stderr b/src/tools/clippy/tests/ui/if_not_else.stderr index 2a7500fdc61..8b86f82fa8e 100644 --- a/src/tools/clippy/tests/ui/if_not_else.stderr +++ b/src/tools/clippy/tests/ui/if_not_else.stderr @@ -11,6 +11,7 @@ LL | | } | = help: remove the `!` and swap the blocks of the `if`/`else` = note: `-D clippy::if-not-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::if_not_else)]` error: unnecessary `!=` operation --> $DIR/if_not_else.rs:18:5 diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr index 774cc08685a..fb33e94e6c3 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr @@ -24,6 +24,7 @@ LL | | foo(); LL | | } | |_____^ = note: `-D clippy::if-same-then-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]` error: this `if` has identical blocks --> $DIR/if_same_then_else.rs:67:21 diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr index 56e5f3e45b2..fe68ef2711b 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr @@ -24,6 +24,7 @@ LL | | } LL | | } | |_____^ = note: `-D clippy::if-same-then-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]` error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:36:13 diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr index f63298a7fce..5c97b06da15 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr @@ -13,6 +13,7 @@ LL | | }; | = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })` = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]` error: this could be simplified with `bool::then` --> $DIR/if_then_some_else_none.rs:14:13 diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr index 3f52c10b762..c5cd6b2c42e 100644 --- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr +++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr @@ -10,6 +10,7 @@ note: same as this LL | if b { | ^ = note: `-D clippy::ifs-same-cond` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]` error: this `if` has the same condition as a previous `if` --> $DIR/ifs_same_cond.rs:19:15 diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr index 6cb8b60ac0c..a8ced22397d 100644 --- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr +++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr @@ -5,6 +5,7 @@ LL | Ok(_) => {}, | ^ help: use `()` instead of `_`: `()` | = note: `-D clippy::ignored-unit-patterns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]` error: matching over `()` is more explicit --> $DIR/ignored_unit_patterns.rs:11:13 diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr index 2eac1ce3dd7..833a106062a 100644 --- a/src/tools/clippy/tests/ui/impl.stderr +++ b/src/tools/clippy/tests/ui/impl.stderr @@ -15,6 +15,7 @@ LL | | fn first() {} LL | | } | |_^ = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::multiple_inherent_impl)]` error: multiple implementations of this structure --> $DIR/impl.rs:25:5 diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr index ad035abc635..36b4f27e9a4 100644 --- a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr +++ b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr @@ -5,6 +5,7 @@ LL | pub fn a(_: impl Trait) {} | ^^^^^^^^^^ | = note: `-D clippy::impl-trait-in-params` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::impl_trait_in_params)]` help: add a type parameter | LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {} diff --git a/src/tools/clippy/tests/ui/implicit_clone.stderr b/src/tools/clippy/tests/ui/implicit_clone.stderr index 59f000c06e2..64c31e65175 100644 --- a/src/tools/clippy/tests/ui/implicit_clone.stderr +++ b/src/tools/clippy/tests/ui/implicit_clone.stderr @@ -5,6 +5,7 @@ LL | let _ = vec.to_owned(); | ^^^^^^^^^^^^^^ help: consider using: `vec.clone()` | = note: `-D clippy::implicit-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_clone)]` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type --> $DIR/implicit_clone.rs:66:13 diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr index a761b427395..1edc6cc6f77 100644 --- a/src/tools/clippy/tests/ui/implicit_return.stderr +++ b/src/tools/clippy/tests/ui/implicit_return.stderr @@ -5,6 +5,7 @@ LL | true | ^^^^ help: add `return` as shown: `return true` | = note: `-D clippy::implicit-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]` error: missing `return` statement --> $DIR/implicit_return.rs:15:15 diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.stderr b/src/tools/clippy/tests/ui/implicit_saturating_add.stderr index cfd600c53c3..7119c8bf6fa 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_add.stderr +++ b/src/tools/clippy/tests/ui/implicit_saturating_add.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);` | = note: `-D clippy::implicit-saturating-add` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_add)]` error: manual saturating add detected --> $DIR/implicit_saturating_add.rs:25:5 diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr index 75d8a88e8d4..6e026d1a698 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: try: `u_8 = u_8.saturating_sub(1);` | = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` error: implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:34:13 diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr index 8dffc674444..e2b1ecb9f1e 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr @@ -5,6 +5,7 @@ LL | fn deref_derefmut<T>(x: T) -> impl Deref<Target = T> + DerefMut<Target = T> | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::implied-bounds-in-impls` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implied_bounds_in_impls)]` help: try removing this bound | LL - fn deref_derefmut<T>(x: T) -> impl Deref<Target = T> + DerefMut<Target = T> { diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr index 485c1fdb912..6aeb33edafd 100644 --- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr @@ -5,6 +5,7 @@ LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f | ^^^^^^^^ help: consider: `123_456` | = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]` error: digits grouped inconsistently by underscores --> $DIR/inconsistent_digit_grouping.rs:25:26 diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr index a2bee121ebf..fc080d7ec05 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -5,6 +5,7 @@ LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` | = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]` error: struct constructor field order is inconsistent with struct definition field order --> $DIR/inconsistent_struct_constructor.rs:55:9 diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index edb47d39412..64facf20803 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -7,6 +7,7 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: consider using `.get(n)` or `.get_mut(n)` instead = note: the suggestion might not be applicable in constant blocks = note: `-D clippy::indexing-slicing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic --> $DIR/indexing_slicing_index.rs:16:24 diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr index 0f83ea52d01..eebe67810a0 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr @@ -6,6 +6,7 @@ LL | &x[index..]; | = help: consider using `.get(n..)` or .get_mut(n..)` instead = note: `-D clippy::indexing-slicing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: slicing may panic --> $DIR/indexing_slicing_slice.rs:14:6 @@ -54,6 +55,7 @@ LL | &x[5..][..10]; | ^ | = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic --> $DIR/indexing_slicing_slice.rs:25:6 diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr index ada02741692..93851aae82b 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr @@ -7,6 +7,7 @@ LL | | }; | |______^ help: try: `let SingleVariantEnum::Variant(data) = wrapper;` | = note: `-D clippy::infallible-destructuring-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::infallible_destructuring_match)]` error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let` --> $DIR/infallible_destructuring_match.rs:60:5 diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr index 5ba806be867..c32b5e323c0 100644 --- a/src/tools/clippy/tests/ui/infinite_loop.stderr +++ b/src/tools/clippy/tests/ui/infinite_loop.stderr @@ -98,6 +98,7 @@ LL | fn fn_mutref(i: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr index cfe8600e926..cf8d0918019 100644 --- a/src/tools/clippy/tests/ui/inherent_to_string.stderr +++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr @@ -9,6 +9,7 @@ LL | | } | = help: implement trait `Display` for type `A` instead = note: `-D clippy::inherent-to-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inherent_to_string)]` error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display` --> $DIR/inherent_to_string.rs:47:5 diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.stderr b/src/tools/clippy/tests/ui/inline_fn_without_body.stderr index 87d2da71280..60f6eb8dff0 100644 --- a/src/tools/clippy/tests/ui/inline_fn_without_body.stderr +++ b/src/tools/clippy/tests/ui/inline_fn_without_body.stderr @@ -7,6 +7,7 @@ LL | | fn default_inline(); | |____- help: remove | = note: `-D clippy::inline-fn-without-body` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_fn_without_body)]` error: use of `#[inline]` on trait method `always_inline` which has no body --> $DIR/inline_fn_without_body.rs:8:5 diff --git a/src/tools/clippy/tests/ui/inspect_for_each.stderr b/src/tools/clippy/tests/ui/inspect_for_each.stderr index bdeb1d84460..80df86ad64e 100644 --- a/src/tools/clippy/tests/ui/inspect_for_each.stderr +++ b/src/tools/clippy/tests/ui/inspect_for_each.stderr @@ -12,6 +12,7 @@ LL | | }); | = help: move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)` = note: `-D clippy::inspect-for-each` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inspect_for_each)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/int_plus_one.stderr b/src/tools/clippy/tests/ui/int_plus_one.stderr index a0c5b32a205..6a62eac7cc4 100644 --- a/src/tools/clippy/tests/ui/int_plus_one.stderr +++ b/src/tools/clippy/tests/ui/int_plus_one.stderr @@ -5,6 +5,7 @@ LL | let _ = x >= y + 1; | ^^^^^^^^^^ help: change it to: `x > y` | = note: `-D clippy::int-plus-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::int_plus_one)]` error: unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:8:13 diff --git a/src/tools/clippy/tests/ui/integer_division.stderr b/src/tools/clippy/tests/ui/integer_division.stderr index 9bc41ef8385..420f0f30e77 100644 --- a/src/tools/clippy/tests/ui/integer_division.stderr +++ b/src/tools/clippy/tests/ui/integer_division.stderr @@ -6,6 +6,7 @@ LL | let n = 1 / 2; | = help: division of integers may cause loss of precision. consider using floats = note: `-D clippy::integer-division` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::integer_division)]` error: integer division --> $DIR/integer_division.rs:7:13 diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr index 2c81518d8db..481957d50e2 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr @@ -5,6 +5,7 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` | = note: `-D clippy::into-iter-on-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::into_iter_on_ref)]` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:14:46 diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr index b201db3ddb1..a57b4b02dce 100644 --- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr +++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr @@ -5,6 +5,7 @@ LL | (u8 as u32) > 300; | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::invalid-upcast-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::invalid_upcast_comparisons)]` error: because of the numeric bounds on `u8` prior to casting, this expression is always false --> $DIR/invalid_upcast_comparisons.rs:24:5 diff --git a/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr b/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr index 7bc21b216d5..28040c3a9c2 100644 --- a/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr +++ b/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr @@ -5,6 +5,7 @@ LL | let _ = c.is_digit(10); | ^^^^^^^^^^^^^^ help: try: `c.is_ascii_digit()` | = note: `-D clippy::is-digit-ascii-radix` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::is_digit_ascii_radix)]` error: use of `char::is_digit` with literal radix of 16 --> $DIR/is_digit_ascii_radix.rs:10:13 diff --git a/src/tools/clippy/tests/ui/issue-7447.stderr b/src/tools/clippy/tests/ui/issue-7447.stderr index 27e102af62f..51ecac4559c 100644 --- a/src/tools/clippy/tests/ui/issue-7447.stderr +++ b/src/tools/clippy/tests/ui/issue-7447.stderr @@ -5,6 +5,7 @@ LL | byte_view(panic!()); | ^^^^^^^^ | = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::diverging_sub_expression)]` = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: sub-expression diverges diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr index acfa01e9f2b..692de2ae58c 100644 --- a/src/tools/clippy/tests/ui/issue_4266.stderr +++ b/src/tools/clippy/tests/ui/issue_4266.stderr @@ -5,6 +5,7 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint | ^^ ^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_lifetimes)]` error: the following explicit lifetimes could be elided: 'a --> $DIR/issue_4266.rs:10:21 @@ -20,6 +21,7 @@ LL | pub async fn new(&mut self) -> Self { | = help: consider choosing a less ambiguous name = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/items_after_statement.stderr b/src/tools/clippy/tests/ui/items_after_statement.stderr index 0e043b1742f..fa494f21748 100644 --- a/src/tools/clippy/tests/ui/items_after_statement.stderr +++ b/src/tools/clippy/tests/ui/items_after_statement.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::items-after-statements` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::items_after_statements)]` error: adding items after statements is confusing, since items exist from the start of the scope --> $DIR/items_after_statement.rs:22:5 diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr index 36f70d5aec2..aa7fb98a7c8 100644 --- a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr +++ b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr @@ -5,6 +5,7 @@ LL | let v2: Vec<isize> = v.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` | = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_cloned_collect)]` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable --> $DIR/iter_cloned_collect.rs:13:38 diff --git a/src/tools/clippy/tests/ui/iter_count.stderr b/src/tools/clippy/tests/ui/iter_count.stderr index 2e3d7fc35de..2882b7d2850 100644 --- a/src/tools/clippy/tests/ui/iter_count.stderr +++ b/src/tools/clippy/tests/ui/iter_count.stderr @@ -5,6 +5,7 @@ LL | &vec[..].iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` | = note: `-D clippy::iter-count` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_count)]` error: called `.iter().count()` on a `Vec` --> $DIR/iter_count.rs:55:5 diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr index 75804af01ce..62155b7f838 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.stderr +++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr @@ -5,6 +5,7 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` | = note: `-D clippy::iter-kv-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_kv_map)]` error: iterating on a map's values --> $DIR/iter_kv_map.rs:15:13 diff --git a/src/tools/clippy/tests/ui/iter_next_slice.stderr b/src/tools/clippy/tests/ui/iter_next_slice.stderr index d8b89061ff8..e6b4bd6c0b4 100644 --- a/src/tools/clippy/tests/ui/iter_next_slice.stderr +++ b/src/tools/clippy/tests/ui/iter_next_slice.stderr @@ -5,6 +5,7 @@ LL | let _ = s.iter().next(); | ^^^^^^^^^^^^^^^ help: try calling: `s.first()` | = note: `-D clippy::iter-next-slice` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_next_slice)]` error: using `.iter().next()` on a Slice without end index --> $DIR/iter_next_slice.rs:12:13 diff --git a/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr b/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr index 3145ade4448..c695b1932d3 100644 --- a/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr +++ b/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr @@ -5,6 +5,7 @@ LL | fn iter(&self) -> Counter2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iter-not-returning-iterator` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_not_returning_iterator)]` error: this method is named `iter_mut` but its return type does not implement `Iterator` --> $DIR/iter_not_returning_iterator.rs:36:5 diff --git a/src/tools/clippy/tests/ui/iter_nth.stderr b/src/tools/clippy/tests/ui/iter_nth.stderr index 24be814548a..162e6c33849 100644 --- a/src/tools/clippy/tests/ui/iter_nth.stderr +++ b/src/tools/clippy/tests/ui/iter_nth.stderr @@ -6,6 +6,7 @@ LL | let bad_vec = some_vec.iter().nth(3); | = help: calling `.get()` is both faster and more readable = note: `-D clippy::iter-nth` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_nth)]` error: called `.iter().nth()` on a slice --> $DIR/iter_nth.rs:35:26 diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.stderr b/src/tools/clippy/tests/ui/iter_nth_zero.stderr index 8338d7f7b93..939fd0063c0 100644 --- a/src/tools/clippy/tests/ui/iter_nth_zero.stderr +++ b/src/tools/clippy/tests/ui/iter_nth_zero.stderr @@ -5,6 +5,7 @@ LL | let _x = s.iter().nth(0); | ^^^^^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `s.iter().next()` | = note: `-D clippy::iter-nth-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_nth_zero)]` error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent --> $DIR/iter_nth_zero.rs:23:14 diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr index c115c127838..57a53201996 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr @@ -5,6 +5,7 @@ LL | assert_eq!([].into_iter().next(), Option::<i32>::None); | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` | = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_on_empty_collections)]` error: `iter_mut` call on an empty collection --> $DIR/iter_on_empty_collections.rs:6:16 diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.stderr b/src/tools/clippy/tests/ui/iter_on_single_items.stderr index c6714143ba5..00398f541e9 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.stderr +++ b/src/tools/clippy/tests/ui/iter_on_single_items.stderr @@ -5,6 +5,7 @@ LL | assert_eq!([123].into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` | = note: `-D clippy::iter-on-single-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_on_single_items)]` error: `iter_mut` call on a collection with only one item --> $DIR/iter_on_single_items.rs:6:16 diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr index 4417a40a63b..fbcd33066d8 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr @@ -7,6 +7,7 @@ LL | let _: Option<String> = vec.iter().cloned().last(); | help: try: `.last().cloned()` | = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_overeager_cloned)]` error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:9:29 @@ -25,6 +26,7 @@ LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); | help: try: `.count()` | = note: `-D clippy::redundant-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: unnecessarily eager cloning of iterator items --> $DIR/iter_overeager_cloned.rs:13:21 diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr index ca6970b27f1..0b6bf652b1f 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr @@ -5,6 +5,7 @@ LL | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` | = note: `-D clippy::iter-skip-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_skip_next)]` error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:17:36 diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr index 3160dc03a4f..09a467793bd 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr @@ -10,6 +10,7 @@ help: for this change `sp` has to be mutable LL | let sp = test_string.split('|').map(|s| s.trim()); | ^^ = note: `-D clippy::iter-skip-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_skip_next)]` error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next_unfixable.rs:12:29 diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.stderr b/src/tools/clippy/tests/ui/iter_skip_zero.stderr index 6616020d0bd..6b8b3b1056a 100644 --- a/src/tools/clippy/tests/ui/iter_skip_zero.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_zero.stderr @@ -6,6 +6,7 @@ LL | let _ = [1, 2, 3].iter().skip(0); | = note: this call to `skip` does nothing and is useless; remove it = note: `-D clippy::iter-skip-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_skip_zero)]` error: usage of `.skip(0)` --> $DIR/iter_skip_zero.rs:12:39 diff --git a/src/tools/clippy/tests/ui/iter_with_drain.stderr b/src/tools/clippy/tests/ui/iter_with_drain.stderr index 0a302657088..ac04f9396f5 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.stderr +++ b/src/tools/clippy/tests/ui/iter_with_drain.stderr @@ -5,6 +5,7 @@ LL | let mut a: BinaryHeap<_> = a.drain(..).collect(); | ^^^^^^^^^ help: try: `into_iter()` | = note: `-D clippy::iter-with-drain` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_with_drain)]` error: `drain(..)` used on a `VecDeque` --> $DIR/iter_with_drain.rs:13:27 diff --git a/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr b/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr index fcf2930c26b..20ea29322e8 100644 --- a/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr +++ b/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr @@ -5,6 +5,7 @@ LL | let _ = vec!["A", "B", "B"].iter().step_by(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iterator_step_by_zero)]` error: `Iterator::step_by(0)` will panic at runtime --> $DIR/iterator_step_by_zero.rs:7:13 diff --git a/src/tools/clippy/tests/ui/large_const_arrays.stderr b/src/tools/clippy/tests/ui/large_const_arrays.stderr index e2348629088..e522550ffcb 100644 --- a/src/tools/clippy/tests/ui/large_const_arrays.stderr +++ b/src/tools/clippy/tests/ui/large_const_arrays.stderr @@ -7,6 +7,7 @@ LL | pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; | help: make this a static item: `static` | = note: `-D clippy::large-const-arrays` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_const_arrays)]` error: large array defined as const --> $DIR/large_const_arrays.rs:11:1 diff --git a/src/tools/clippy/tests/ui/large_digit_groups.stderr b/src/tools/clippy/tests/ui/large_digit_groups.stderr index 7e5ce7ad8d5..e5f37a6cce9 100644 --- a/src/tools/clippy/tests/ui/large_digit_groups.stderr +++ b/src/tools/clippy/tests/ui/large_digit_groups.stderr @@ -5,6 +5,7 @@ LL | 0xd_e_adbee_f_usize, | ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize` | = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unusual_byte_groupings)]` error: digit groups should be smaller --> $DIR/large_digit_groups.rs:23:9 @@ -13,6 +14,7 @@ LL | 1_23456_f32, | ^^^^^^^^^^^ help: consider: `123_456_f32` | = note: `-D clippy::large-digit-groups` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_digit_groups)]` error: digit groups should be smaller --> $DIR/large_digit_groups.rs:24:9 diff --git a/src/tools/clippy/tests/ui/large_enum_variant.stderr b/src/tools/clippy/tests/ui/large_enum_variant.stderr index 709972b4a6e..7026ca785f3 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.stderr +++ b/src/tools/clippy/tests/ui/large_enum_variant.stderr @@ -10,6 +10,7 @@ LL | | } | |_^ the entire enum is at least 32004 bytes | = note: `-D clippy::large-enum-variant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]` help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box<[i32; 8000]>), diff --git a/src/tools/clippy/tests/ui/large_futures.stderr b/src/tools/clippy/tests/ui/large_futures.stderr index 5a0f00b67ec..861366dafac 100644 --- a/src/tools/clippy/tests/ui/large_futures.stderr +++ b/src/tools/clippy/tests/ui/large_futures.stderr @@ -5,6 +5,7 @@ LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` | = note: `-D clippy::large-futures` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: large future with a size of 16386 bytes --> $DIR/large_futures.rs:15:5 diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr index 5126f452785..0dfb6732b02 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr +++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr @@ -6,6 +6,7 @@ LL | let _x = [build(); 3]; | = help: consider allocating on the heap with `vec![build(); 3].into_boxed_slice()` = note: `-D clippy::large-stack-arrays` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_stack_arrays)]` error: allocating a local array larger than 512000 bytes --> $DIR/large_stack_arrays.rs:32:14 diff --git a/src/tools/clippy/tests/ui/large_stack_frames.stderr b/src/tools/clippy/tests/ui/large_stack_frames.stderr index 6b14badca69..12a458db807 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.stderr +++ b/src/tools/clippy/tests/ui/large_stack_frames.stderr @@ -12,6 +12,7 @@ LL | | } | = note: allocating large amounts of stack space can overflow the stack = note: `-D clippy::large-stack-frames` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` error: this function allocates a large amount of stack space --> $DIR/large_stack_frames.rs:36:1 diff --git a/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr b/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr index 5f42dcfb9b5..b3f102cc498 100644 --- a/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr +++ b/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr @@ -5,6 +5,7 @@ LL | fn bad(a: LargeAndCopy) {} | ^^^^^^^^^^^^ help: consider passing by reference instead: `&LargeAndCopy` | = note: `-D clippy::large-types-passed-by-value` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::large_types_passed_by_value)]` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) --> $DIR/large_types_passed_by_value.rs:25:37 diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.stderr b/src/tools/clippy/tests/ui/len_without_is_empty.stderr index 1042ea2e1b3..4815ce6a04b 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty.stderr +++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr @@ -5,6 +5,7 @@ LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::len-without-is-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::len_without_is_empty)]` error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method --> $DIR/len_without_is_empty.rs:57:1 @@ -96,6 +97,7 @@ LL | pub fn len(&self) -> Result<usize, ()> { | = help: use a custom `Error` type instead = note: `-D clippy::result-unit-err` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_unit_err)]` error: this returns a `Result<_, ()>` --> $DIR/len_without_is_empty.rs:250:5 diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr index 45130a3008d..e1f2434415d 100644 --- a/src/tools/clippy/tests/ui/len_zero.stderr +++ b/src/tools/clippy/tests/ui/len_zero.stderr @@ -5,6 +5,7 @@ LL | if x.len() == 0 { | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()` | = note: `-D clippy::len-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::len_zero)]` error: length comparison to zero --> $DIR/len_zero.rs:86:8 @@ -19,6 +20,7 @@ LL | println!("{}", *s1 == ""); | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()` | = note: `-D clippy::comparison-to-empty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]` error: comparison to empty slice --> $DIR/len_zero.rs:96:20 diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.stderr b/src/tools/clippy/tests/ui/len_zero_ranges.stderr index 25a940181d4..1922e9b3044 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.stderr +++ b/src/tools/clippy/tests/ui/len_zero_ranges.stderr @@ -5,6 +5,7 @@ LL | let _ = (0..42).len() == 0; | ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()` | = note: `-D clippy::len-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::len_zero)]` error: length comparison to zero --> $DIR/len_zero_ranges.rs:11:17 diff --git a/src/tools/clippy/tests/ui/let_and_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr index 3f60b69df45..c09c2b32aad 100644 --- a/src/tools/clippy/tests/ui/let_and_return.stderr +++ b/src/tools/clippy/tests/ui/let_and_return.stderr @@ -7,6 +7,7 @@ LL | x | ^ | = note: `-D clippy::let-and-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]` help: return the expression directly | LL ~ diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr index b739268dacd..bfb4bb9d0d2 100644 --- a/src/tools/clippy/tests/ui/let_if_seq.stderr +++ b/src/tools/clippy/tests/ui/let_if_seq.stderr @@ -11,6 +11,7 @@ LL | | } | = note: you might not need `mut` at all = note: `-D clippy::useless-let-if-seq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_let_if_seq)]` error: `if _ { .. } else { .. }` is an expression --> $DIR/let_if_seq.rs:73:5 diff --git a/src/tools/clippy/tests/ui/let_underscore_future.stderr b/src/tools/clippy/tests/ui/let_underscore_future.stderr index e3a628236e7..3ba99c6377b 100644 --- a/src/tools/clippy/tests/ui/let_underscore_future.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_future.stderr @@ -6,6 +6,7 @@ LL | let _ = some_async_fn(); | = help: consider awaiting the future or dropping explicitly with `std::mem::drop` = note: `-D clippy::let-underscore-future` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]` error: non-binding `let` on a future --> $DIR/let_underscore_future.rs:18:5 @@ -30,6 +31,7 @@ LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.stderr b/src/tools/clippy/tests/ui/let_underscore_lock.stderr index 9c9ff9c917c..ac6e0978e63 100644 --- a/src/tools/clippy/tests/ui/let_underscore_lock.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_lock.stderr @@ -6,6 +6,7 @@ LL | let _ = p_m.lock(); | = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` = note: `-D clippy::let-underscore-lock` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_underscore_lock)]` error: non-binding `let` on a synchronization lock --> $DIR/let_underscore_lock.rs:14:5 diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr index 5cd02a6e812..83d0372e668 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr @@ -6,6 +6,7 @@ LL | let _ = f(); | = help: consider explicitly using function result = note: `-D clippy::let-underscore-must-use` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_underscore_must_use)]` error: non-binding `let` on an expression with `#[must_use]` type --> $DIR/let_underscore_must_use.rs:69:5 diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr index e0c39b6eeaf..0e5647fa1e9 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr @@ -10,6 +10,7 @@ help: consider adding a type annotation LL | let _ = a(); | ^ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_underscore_untyped)]` error: non-binding `let` without a type annotation --> $DIR/let_underscore_untyped.rs:52:5 diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr index c54d4392a34..de106f50e0e 100644 --- a/src/tools/clippy/tests/ui/let_unit.stderr +++ b/src/tools/clippy/tests/ui/let_unit.stderr @@ -5,6 +5,7 @@ LL | let _x = println!("x"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");` | = note: `-D clippy::let-unit-value` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` error: this let-binding has unit value --> $DIR/let_unit.rs:16:9 diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr index a749552c7fa..d4c9ba19c39 100644 --- a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr +++ b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr @@ -10,6 +10,7 @@ help: remove the explicit type `_` declaration LL | let x: _ = 1; | ^^^ = note: `-D clippy::let-with-type-underscore` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_with_type_underscore)]` error: variable declared with type underscore --> $DIR/let_with_type_underscore.rs:16:5 diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr b/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr index 4244d85b448..fa2ba0a9a46 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr @@ -10,6 +10,7 @@ note: this expression returning a `std::io::Lines` may produce an infinite numbe LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::lines-filter-map-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::lines_filter_map_ok)]` error: `flat_map()` will run forever if the iterator repeatedly produces an `Err` --> $DIR/lines_filter_map_ok.rs:12:31 diff --git a/src/tools/clippy/tests/ui/linkedlist.stderr b/src/tools/clippy/tests/ui/linkedlist.stderr index b31b0cd9314..792af4dd06e 100644 --- a/src/tools/clippy/tests/ui/linkedlist.stderr +++ b/src/tools/clippy/tests/ui/linkedlist.stderr @@ -6,6 +6,7 @@ LL | const C: LinkedList<i32> = LinkedList::new(); | = help: a `VecDeque` might work = note: `-D clippy::linkedlist` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::linkedlist)]` error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? --> $DIR/linkedlist.rs:10:11 diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr index 7c79436752f..bc755b1123d 100644 --- a/src/tools/clippy/tests/ui/literals.stderr +++ b/src/tools/clippy/tests/ui/literals.stderr @@ -5,6 +5,7 @@ LL | let ok4 = 0xab_cd_i32; | ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32` | = note: `-D clippy::separated-literal-suffix` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::separated_literal_suffix)]` error: integer type suffix should not be separated by an underscore --> $DIR/literals.rs:16:15 @@ -25,6 +26,7 @@ LL | let fail1 = 0xabCD; | ^^^^^^ | = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mixed_case_hex_literals)]` error: integer type suffix should not be separated by an underscore --> $DIR/literals.rs:23:17 @@ -57,6 +59,7 @@ LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize` | = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unseparated_literal_suffix)]` error: this is a decimal constant --> $DIR/literals.rs:29:27 @@ -65,6 +68,7 @@ LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ | = note: `-D clippy::zero-prefixed-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zero_prefixed_literal)]` help: if you mean to use a decimal constant, remove the `0` to avoid confusion | LL | let fail_multi_zero = 123usize; @@ -108,6 +112,7 @@ LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` | = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]` error: digits grouped inconsistently by underscores --> $DIR/literals.rs:55:18 @@ -128,6 +133,7 @@ LL | let fail24 = 0xAB_ABC_AB; | ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB` | = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unusual_byte_groupings)]` error: this is a decimal constant --> $DIR/literals.rs:70:13 diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr index d2193c0c819..ea787f5726a 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr +++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr @@ -5,6 +5,7 @@ LL | let _: f32 = 16_777_217.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0` | = note: `-D clippy::lossy-float-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::lossy_float_literal)]` error: literal cannot be represented as the underlying type without loss of precision --> $DIR/lossy_float_literal.rs:7:18 diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index 2259e5abf2f..6de869699ec 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -5,6 +5,7 @@ LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::macro_use_imports)]` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:23:5 diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr index 1bf61fa33bf..b19cca4d5f9 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);` | = note: `-D clippy::manual-assert` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]` error: only a `panic!` in `if`-then statement --> $DIR/manual_assert.rs:33:5 diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr index 1bf61fa33bf..b19cca4d5f9 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);` | = note: `-D clippy::manual-assert` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]` error: only a `panic!` in `if`-then statement --> $DIR/manual_assert.rs:33:5 diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index b196614dff9..c0c471912e4 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -5,6 +5,7 @@ LL | fn fut() -> impl Future<Output = i32> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-async-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_async_fn)]` help: make the function `async` and return the output of the future directly | LL | async fn fut() -> i32 { diff --git a/src/tools/clippy/tests/ui/manual_bits.stderr b/src/tools/clippy/tests/ui/manual_bits.stderr index 95910650da9..2f2ed5909c1 100644 --- a/src/tools/clippy/tests/ui/manual_bits.stderr +++ b/src/tools/clippy/tests/ui/manual_bits.stderr @@ -5,6 +5,7 @@ LL | size_of::<i8>() * 8; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize` | = note: `-D clippy::manual-bits` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_bits)]` error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits --> $DIR/manual_bits.rs:15:5 diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr index 95e0cf5d4ec..2fa68ede126 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.stderr +++ b/src/tools/clippy/tests/ui/manual_clamp.stderr @@ -12,6 +12,7 @@ LL | | } | = note: clamp will panic if max < min = note: `-D clippy::manual-clamp` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]` error: clamp-like pattern without using clamp function --> $DIR/manual_clamp.rs:113:5 diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr index a2d56f87b64..1490f209735 100644 --- a/src/tools/clippy/tests/ui/manual_filter.stderr +++ b/src/tools/clippy/tests/ui/manual_filter.stderr @@ -11,6 +11,7 @@ LL | | }; | |_____^ help: try: `Some(0).filter(|&x| x <= 0)` | = note: `-D clippy::manual-filter` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_filter)]` error: manual implementation of `Option::filter` --> $DIR/manual_filter.rs:16:5 diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr index 5b8a553f84f..0bfc1f5c745 100644 --- a/src/tools/clippy/tests/ui/manual_filter_map.stderr +++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr @@ -10,6 +10,7 @@ note: the suggestion might change the behavior of the program when merging `filt LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^ = note: `-D clippy::manual-filter-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_filter_map)]` error: `filter(..).map(..)` can be simplified as `filter_map(..)` --> $DIR/manual_filter_map.rs:11:19 @@ -98,6 +99,7 @@ LL | iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` | = note: `-D clippy::manual-find-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]` error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_filter_map.rs:34:28 diff --git a/src/tools/clippy/tests/ui/manual_find.stderr b/src/tools/clippy/tests/ui/manual_find.stderr index 41aa00a8bc1..286ad54625d 100644 --- a/src/tools/clippy/tests/ui/manual_find.stderr +++ b/src/tools/clippy/tests/ui/manual_find.stderr @@ -12,6 +12,7 @@ LL | | None | = note: you may need to dereference some variables = note: `-D clippy::manual-find` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_find)]` error: manual implementation of `Iterator::find` --> $DIR/manual_find.rs:16:5 diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.stderr b/src/tools/clippy/tests/ui/manual_find_fixable.stderr index 2c6f79e928a..387d1509c13 100644 --- a/src/tools/clippy/tests/ui/manual_find_fixable.stderr +++ b/src/tools/clippy/tests/ui/manual_find_fixable.stderr @@ -10,6 +10,7 @@ LL | | None | |________^ help: replace with an iterator: `ARRAY.iter().find(|&&v| v == n).copied()` | = note: `-D clippy::manual-find` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_find)]` error: manual implementation of `Iterator::find` --> $DIR/manual_find_fixable.rs:19:5 diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr index 67523711cc8..0dc9ae1df03 100644 --- a/src/tools/clippy/tests/ui/manual_find_map.stderr +++ b/src/tools/clippy/tests/ui/manual_find_map.stderr @@ -10,6 +10,7 @@ note: the suggestion might change the behavior of the program when merging `filt LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^ = note: `-D clippy::manual-find-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]` error: `find(..).map(..)` can be simplified as `find_map(..)` --> $DIR/manual_find_map.rs:11:19 diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr index 227bf3c5eae..aa5c2104f65 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.stderr +++ b/src/tools/clippy/tests/ui/manual_flatten.stderr @@ -20,6 +20,7 @@ LL | | println!("{}", y); LL | | } | |_________^ = note: `-D clippy::manual-flatten` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_flatten)]` error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> $DIR/manual_flatten.rs:16:5 diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr index 35beb6fec73..680ab2efa09 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.stderr +++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr @@ -5,6 +5,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` | = note: `-D clippy::manual-is-infinite` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]` error: manually checking if a float is finite --> $DIR/manual_float_methods.rs:24:8 @@ -13,6 +14,7 @@ LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-is-finite` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_finite)]` help: use the dedicated method instead | LL | if x.is_finite() {} diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr index 5537f5642a2..56d0b9cd77b 100644 --- a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr @@ -5,6 +5,7 @@ LL | let duration = Instant::now() - prev_instant; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()` | = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_instant_elapsed)]` error: manual implementation of `Instant::elapsed` --> $DIR/manual_instant_elapsed.rs:26:5 diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr index 0497259b69b..e0fb46e59fa 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr @@ -5,6 +5,7 @@ LL | assert!(matches!('x', 'a'..='z')); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_lowercase()` | = note: `-D clippy::manual-is-ascii-check` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_ascii_check)]` error: manual check for common ascii range --> $DIR/manual_is_ascii_check.rs:6:13 diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index 309ce3986f3..49dbd7615e0 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -5,6 +5,7 @@ LL | let v = if let Some(v_some) = g() { v_some } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]` error: this could be rewritten as `let...else` --> $DIR/manual_let_else.rs:28:5 diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr index fb7d83f3244..8ca2c84072d 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr @@ -10,6 +10,7 @@ LL | | }; | |______^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]` error: this could be rewritten as `let...else` --> $DIR/manual_let_else_match.rs:43:5 diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr index ea35618e3c1..bf0b1bbf0dd 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr @@ -5,6 +5,7 @@ LL | let Some(v) = g() else { return None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `let v = g()?;` | = note: `-D clippy::question-mark` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::question_mark)]` error: this `let...else` may be rewritten with the `?` operator --> $DIR/manual_let_else_question_mark.rs:35:5 @@ -29,6 +30,7 @@ LL | | }; | |______^ | = note: `-D clippy::manual-let-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]` help: consider writing | LL ~ let Some(v) = g() else { diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.stderr b/src/tools/clippy/tests/ui/manual_main_separator_str.stderr index f7612efa500..3e92bd0238c 100644 --- a/src/tools/clippy/tests/ui/manual_main_separator_str.stderr +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.stderr @@ -5,6 +5,7 @@ LL | let _: &str = &MAIN_SEPARATOR.to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` | = note: `-D clippy::manual-main-separator-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_main_separator_str)]` error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` --> $DIR/manual_main_separator_str.rs:22:17 diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr index 3e5fd923df8..ff6ed974d4a 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option.stderr @@ -8,6 +8,7 @@ LL | | }; | |_____^ help: try: `Some(0).map(|_| 2)` | = note: `-D clippy::manual-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_map)]` error: manual implementation of `Option::map` --> $DIR/manual_map_option.rs:18:5 diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.stderr b/src/tools/clippy/tests/ui/manual_map_option_2.stderr index e71000dd5d5..bf242c0416c 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option_2.stderr @@ -12,6 +12,7 @@ LL | | }; | |_____^ | = note: `-D clippy::manual-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_map)]` help: try | LL ~ let _ = Some(0).map(|x| { diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr index e23c95dc8a4..3f000fbab69 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -10,6 +10,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[3..src.len()].copy_from_slice(&src[..(src.len() - 3)]);` | = note: `-D clippy::manual-memcpy` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_memcpy)]` error: it looks like you're manually copying between slices --> $DIR/with_loop_counters.rs:13:5 diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr index 4f02c698a0d..b9dbda6ede7 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr +++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[..]);` | = note: `-D clippy::manual-memcpy` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_memcpy)]` error: it looks like you're manually copying between slices --> $DIR/without_loop_counters.rs:15:5 diff --git a/src/tools/clippy/tests/ui/manual_next_back.stderr b/src/tools/clippy/tests/ui/manual_next_back.stderr index d2e52b40b4f..a63d266dd62 100644 --- a/src/tools/clippy/tests/ui/manual_next_back.stderr +++ b/src/tools/clippy/tests/ui/manual_next_back.stderr @@ -5,6 +5,7 @@ LL | let _ = (0..10).rev().next().unwrap(); | ^^^^^^^^^^^^^ help: use: `.next_back()` | = note: `-D clippy::manual-next-back` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_next_back)]` error: manual backwards iteration --> $DIR/manual_next_back.rs:33:32 diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr index ab068d4827e..ce7e21c94bb 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr @@ -20,6 +20,7 @@ help: remove this variant LL | _C, | ^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` error: this seems like a manual implementation of the non-exhaustive pattern --> $DIR/manual_non_exhaustive_enum.rs:15:1 diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr index c062af6356c..028b8ff7639 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr @@ -19,6 +19,7 @@ help: remove this field LL | _c: (), | ^^^^^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` error: this seems like a manual implementation of the non-exhaustive pattern --> $DIR/manual_non_exhaustive_struct.rs:14:5 diff --git a/src/tools/clippy/tests/ui/manual_ok_or.stderr b/src/tools/clippy/tests/ui/manual_ok_or.stderr index 65459a09738..ddb2cf261e4 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.stderr +++ b/src/tools/clippy/tests/ui/manual_ok_or.stderr @@ -5,6 +5,7 @@ LL | foo.map_or(Err("error"), |v| Ok(v)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` | = note: `-D clippy::manual-ok-or` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_ok_or)]` error: this pattern reimplements `Option::ok_or` --> $DIR/manual_ok_or.rs:14:5 diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.stderr b/src/tools/clippy/tests/ui/manual_range_patterns.stderr index 1cf58d7df6a..3eee39af86e 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.stderr +++ b/src/tools/clippy/tests/ui/manual_range_patterns.stderr @@ -5,6 +5,7 @@ LL | let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` | = note: `-D clippy::manual-range-patterns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_range_patterns)]` error: this OR pattern can be rewritten using a range --> $DIR/manual_range_patterns.rs:9:25 diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr index c93d37a8bd4..f296f264665 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr @@ -5,6 +5,7 @@ LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` | = note: `-D clippy::manual-rem-euclid` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_rem_euclid)]` error: manual `rem_euclid` implementation --> $DIR/manual_rem_euclid.rs:14:18 diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr index cc1b449d25a..0c5b1383b6a 100644 --- a/src/tools/clippy/tests/ui/manual_retain.stderr +++ b/src/tools/clippy/tests/ui/manual_retain.stderr @@ -5,6 +5,7 @@ LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` | = note: `-D clippy::manual-retain` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]` error: this expression can be written more simply using `.retain()` --> $DIR/manual_retain.rs:23:5 diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr index 06f578b3c1d..dc36a5ee7c6 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr @@ -5,6 +5,7 @@ LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` | = note: `-D clippy::manual-saturating-arithmetic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]` error: manual saturating arithmetic --> $DIR/manual_saturating_arithmetic.rs:7:13 diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr index 812d02c96fc..ebdb748137a 100644 --- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr @@ -5,6 +5,7 @@ LL | let _ = s_i32.len() * size_of::<i32>(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` | = note: `-D clippy::manual-slice-size-calculation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_slice_size_calculation)]` error: manual slice size calculation --> $DIR/manual_slice_size_calculation.rs:16:13 diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr index d425f0881c0..494a035edc3 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.stderr +++ b/src/tools/clippy/tests/ui/manual_split_once.stderr @@ -5,6 +5,7 @@ LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` | = note: `-D clippy::manual-split-once` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_split_once)]` error: manual implementation of `split_once` --> $DIR/manual_split_once.rs:12:13 diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr index b92835884d9..9a13aa97227 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.stderr +++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr @@ -5,6 +5,7 @@ LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` | = note: `-D clippy::manual-str-repeat` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_str_repeat)]` error: manual implementation of `str::repeat` using iterators --> $DIR/manual_str_repeat.rs:8:21 diff --git a/src/tools/clippy/tests/ui/manual_string_new.stderr b/src/tools/clippy/tests/ui/manual_string_new.stderr index 02aac6fdfeb..399652d3fec 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.stderr +++ b/src/tools/clippy/tests/ui/manual_string_new.stderr @@ -5,6 +5,7 @@ LL | let _ = "".to_string(); | ^^^^^^^^^^^^^^ help: consider using: `String::new()` | = note: `-D clippy::manual-string-new` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_string_new)]` error: empty String is being created manually --> $DIR/manual_string_new.rs:16:13 diff --git a/src/tools/clippy/tests/ui/manual_strip.stderr b/src/tools/clippy/tests/ui/manual_strip.stderr index e7be2b4b9ce..0bf6975b1e3 100644 --- a/src/tools/clippy/tests/ui/manual_strip.stderr +++ b/src/tools/clippy/tests/ui/manual_strip.stderr @@ -10,6 +10,7 @@ note: the prefix was tested here LL | if s.starts_with("ab") { | ^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::manual-strip` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_strip)]` help: try using the `strip_prefix` method | LL ~ if let Some(<stripped>) = s.strip_prefix("ab") { diff --git a/src/tools/clippy/tests/ui/manual_try_fold.stderr b/src/tools/clippy/tests/ui/manual_try_fold.stderr index f1bb97c6d0f..4eb3e302b21 100644 --- a/src/tools/clippy/tests/ui/manual_try_fold.stderr +++ b/src/tools/clippy/tests/ui/manual_try_fold.stderr @@ -5,6 +5,7 @@ LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` | = note: `-D clippy::manual-try-fold` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_try_fold)]` error: usage of `Iterator::fold` on a type that implements `Try` --> $DIR/manual_try_fold.rs:63:10 diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr index 8b6de5d18bf..3a0759dccaf 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr @@ -8,6 +8,7 @@ LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(42)` | = note: `-D clippy::manual-unwrap-or` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or)]` error: this pattern reimplements `Option::unwrap_or` --> $DIR/manual_unwrap_or.rs:12:5 diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.stderr b/src/tools/clippy/tests/ui/manual_while_let_some.stderr index 33dd313b21a..37387c8c320 100644 --- a/src/tools/clippy/tests/ui/manual_while_let_some.stderr +++ b/src/tools/clippy/tests/ui/manual_while_let_some.stderr @@ -5,6 +5,7 @@ LL | let number = numbers.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-while-let-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_while_let_some)]` help: consider using a `while..let` loop | LL ~ while let Some(number) = numbers.pop() { diff --git a/src/tools/clippy/tests/ui/many_single_char_names.stderr b/src/tools/clippy/tests/ui/many_single_char_names.stderr index 4f5a69a9b60..688158cff6b 100644 --- a/src/tools/clippy/tests/ui/many_single_char_names.stderr +++ b/src/tools/clippy/tests/ui/many_single_char_names.stderr @@ -11,6 +11,7 @@ LL | let e: i32; | ^ | = note: `-D clippy::many-single-char-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::many_single_char_names)]` error: 6 bindings with single-character names in scope --> $DIR/many_single_char_names.rs:5:9 diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr index d84a5bf8d4d..eb11f084887 100644 --- a/src/tools/clippy/tests/ui/map_clone.stderr +++ b/src/tools/clippy/tests/ui/map_clone.stderr @@ -5,6 +5,7 @@ LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` | = note: `-D clippy::map-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_clone)]` error: you are using an explicit closure for cloning elements --> $DIR/map_clone.rs:12:26 diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr index 3108582aa43..1a505d4cecc 100644 --- a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr +++ b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr @@ -5,6 +5,7 @@ LL | let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<(), _>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(0..3).try_for_each(|t| Err(t + 1))` | = note: `-D clippy::map-collect-result-unit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_collect_result_unit)]` error: `.map().collect()` can be replaced with `.try_for_each()` --> $DIR/map_collect_result_unit.rs:6:32 diff --git a/src/tools/clippy/tests/ui/map_err.stderr b/src/tools/clippy/tests/ui/map_err.stderr index d44403a84a5..6a845c84a2a 100644 --- a/src/tools/clippy/tests/ui/map_err.stderr +++ b/src/tools/clippy/tests/ui/map_err.stderr @@ -6,6 +6,7 @@ LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | = help: consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`) = note: `-D clippy::map-err-ignore` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_err_ignore)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr index 88fdd04c023..a65d8f75ddd 100644 --- a/src/tools/clippy/tests/ui/map_flatten.stderr +++ b/src/tools/clippy/tests/ui/map_flatten.stderr @@ -12,6 +12,7 @@ LL | | .flatten(); | |__________________^ | = note: `-D clippy::map-flatten` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|x| { diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr index 86592942153..e5387eead2e 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr @@ -5,6 +5,7 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` | = note: `-D clippy::map-flatten` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` error: called `map(..).flatten()` on `Iterator` --> $DIR/map_flatten_fixable.rs:17:47 diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr index 97ff7ea70d7..8942fd7c0d2 100644 --- a/src/tools/clippy/tests/ui/map_identity.stderr +++ b/src/tools/clippy/tests/ui/map_identity.stderr @@ -5,6 +5,7 @@ LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); | ^^^^^^^^^^^^^^^^^^ help: remove the call to `map` | = note: `-D clippy::map-identity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_identity)]` error: unnecessary map of the identity function --> $DIR/map_identity.rs:8:57 diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr index 5b3c61acf74..7b7eeb322a5 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr @@ -8,6 +8,7 @@ LL | | .unwrap_or(0); | |_____________________^ | = note: `-D clippy::map-unwrap-or` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` help: use `map_or(<a>, <f>)` instead | LL - let _ = opt.map(|x| x + 1) diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr index 0635a8c79bd..ca611ac9d7f 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr @@ -8,6 +8,7 @@ LL | | .unwrap_or_else(|| 0); | |_____________________________^ help: try: `opt.map_or_else(|| 0, |x| x + 1)` | = note: `-D clippy::map-unwrap-or` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead --> $DIR/map_unwrap_or_fixable.rs:46:13 diff --git a/src/tools/clippy/tests/ui/match_as_ref.stderr b/src/tools/clippy/tests/ui/match_as_ref.stderr index 79ca203ee13..cb0191370ea 100644 --- a/src/tools/clippy/tests/ui/match_as_ref.stderr +++ b/src/tools/clippy/tests/ui/match_as_ref.stderr @@ -9,6 +9,7 @@ LL | | }; | |_____^ help: try: `owned.as_ref()` | = note: `-D clippy::match-as-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_as_ref)]` error: use `as_mut()` instead --> $DIR/match_as_ref.rs:12:39 diff --git a/src/tools/clippy/tests/ui/match_bool.stderr b/src/tools/clippy/tests/ui/match_bool.stderr index 351ebfc08cd..369f4e1c6fa 100644 --- a/src/tools/clippy/tests/ui/match_bool.stderr +++ b/src/tools/clippy/tests/ui/match_bool.stderr @@ -5,6 +5,7 @@ LL | match test && test { | ^^^^^^^^^^^^ help: try: `test` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: you seem to be trying to match on a boolean expression --> $DIR/match_bool.rs:7:5 diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr index 06006e26aff..c702523783e 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr @@ -9,6 +9,7 @@ LL | | }; | |_____^ help: try: `matches!(x, Some(0))` | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]` error: redundant pattern matching, consider using `is_some()` --> $DIR/match_expr_like_matches_macro.rs:20:14 @@ -21,6 +22,7 @@ LL | | }; | |_____^ help: try: `x.is_some()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` --> $DIR/match_expr_like_matches_macro.rs:26:14 diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.stderr b/src/tools/clippy/tests/ui/match_on_vec_items.stderr index 71038aaad49..140a458cb9a 100644 --- a/src/tools/clippy/tests/ui/match_on_vec_items.stderr +++ b/src/tools/clippy/tests/ui/match_on_vec_items.stderr @@ -5,6 +5,7 @@ LL | match arr[idx] { | ^^^^^^^^ help: try: `arr.get(idx)` | = note: `-D clippy::match-on-vec-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_on_vec_items)]` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:19:11 diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr index ceec40e8def..322c704f2aa 100644 --- a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr +++ b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr @@ -10,6 +10,7 @@ note: overlaps with this LL | 0..=11 => println!("0..=11"), | ^^^^^^ = note: `-D clippy::match-overlapping-arm` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_overlapping_arm)]` error: some ranges overlap --> $DIR/match_overlapping_arm.rs:19:9 diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr index c65a2d100be..e3bb2824aa0 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.stderr +++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr @@ -8,6 +8,7 @@ LL | | } | |_________^ | = note: `-D clippy::match-ref-pats` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_ref_pats)]` help: instead of prefixing all patterns with `&`, you can dereference the expression | LL ~ match *v { @@ -38,6 +39,7 @@ LL | if let &None = a { | -------^^^^^---- help: try: `if a.is_none()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` --> $DIR/match_ref_pats.rs:42:12 diff --git a/src/tools/clippy/tests/ui/match_result_ok.stderr b/src/tools/clippy/tests/ui/match_result_ok.stderr index 2cf38624e57..de0361bd6b4 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.stderr +++ b/src/tools/clippy/tests/ui/match_result_ok.stderr @@ -5,6 +5,7 @@ LL | if let Some(y) = x.parse().ok() { y } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::match-result-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_result_ok)]` help: consider matching on `Ok(y)` and removing the call to `ok` instead | LL | if let Ok(y) = x.parse() { y } else { 0 } diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr index 5f7e2b47556..824dcfdce83 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms.stderr @@ -11,6 +11,7 @@ note: `_` wildcard arm here LL | _ => 0, | ^^^^^^ = note: `-D clippy::match-same-arms` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to another arm --> $DIR/match_same_arms.rs:18:9 diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index a7348187573..40b20c7e16d 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -23,6 +23,7 @@ LL | | a LL | | }, | |_________^ = note: `-D clippy::match-same-arms` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to another arm --> $DIR/match_same_arms2.rs:38:9 @@ -147,6 +148,7 @@ LL | | }; | |_____^ help: try: `!matches!(x, E::A | E::B)` | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]` error: this match arm has an identical body to another arm --> $DIR/match_same_arms2.rs:199:9 diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr index 9ee8f14ad90..a039536338b 100644 --- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr @@ -11,6 +11,7 @@ note: `_` wildcard arm here LL | _ => panic!(), | ^^^^^^^^^^^^^ = note: `-D clippy::match-same-arms` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to the `_` wildcard arm --> $DIR/match_same_arms_non_exhaustive.rs:55:13 diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index 9d16af76c6a..81ec200dfc7 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::match-single-binding` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_single_binding)]` help: consider using a `let` statement | LL ~ let (x, y, z) = (a, b, c); diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr index 17ef9c36767..e7b9ef8a1cd 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr @@ -8,6 +8,7 @@ LL | | }, | |_____________^ | = note: `-D clippy::match-single-binding` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_single_binding)]` help: consider using a `let` statement | LL ~ Some((iter, _item)) => { diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index 3c946b30a90..f799a4698b9 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -5,6 +5,7 @@ LL | "Bar" => {}, | ^^^^^ | = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_str_case_mismatch)]` help: consider changing the case of this arm to respect `to_ascii_lowercase` | LL | "bar" => {}, diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr index 696ba7303a9..c120aec5b23 100644 --- a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr +++ b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr @@ -6,6 +6,7 @@ LL | Err(_) => panic!("err"), | = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_wild_err_arm)]` error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:32:9 diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr index dfb6e695aa9..e07d3bdd32e 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr @@ -5,6 +5,7 @@ LL | _ => (), | ^ help: try: `Self::Rgb(..)` | = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::match_wildcard_for_single_variants)]` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:32:9 diff --git a/src/tools/clippy/tests/ui/mem_forget.stderr b/src/tools/clippy/tests/ui/mem_forget.stderr index dd2ea751855..a5ab150317a 100644 --- a/src/tools/clippy/tests/ui/mem_forget.stderr +++ b/src/tools/clippy/tests/ui/mem_forget.stderr @@ -6,6 +6,7 @@ LL | memstuff::forget(six); | = note: argument has type `std::sync::Arc<i32>` = note: `-D clippy::mem-forget` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_forget)]` error: usage of `mem::forget` on `Drop` type --> $DIR/mem_forget.rs:19:5 diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr index 00f3ccbdbea..ae5f4e5340a 100644 --- a/src/tools/clippy/tests/ui/mem_replace.stderr +++ b/src/tools/clippy/tests/ui/mem_replace.stderr @@ -5,6 +5,7 @@ LL | let _ = mem::replace(&mut an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` | = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` error: replacing an `Option` with `None` --> $DIR/mem_replace.rs:16:13 @@ -19,6 +20,7 @@ LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` --> $DIR/mem_replace.rs:24:13 diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.stderr b/src/tools/clippy/tests/ui/mem_replace_macro.stderr index 35dda93da3d..842ad3a8565 100644 --- a/src/tools/clippy/tests/ui/mem_replace_macro.stderr +++ b/src/tools/clippy/tests/ui/mem_replace_macro.stderr @@ -5,6 +5,7 @@ LL | inline!(std::mem::replace($s, Default::default())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr index 6be38b24fbd..e32b3b336af 100644 --- a/src/tools/clippy/tests/ui/methods.stderr +++ b/src/tools/clippy/tests/ui/methods.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead --> $DIR/methods.rs:124:13 @@ -19,6 +20,7 @@ LL | | ).next(); | |___________________________^ | = note: `-D clippy::filter-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/methods_fixable.stderr b/src/tools/clippy/tests/ui/methods_fixable.stderr index e4e626192ca..1bfe56d912b 100644 --- a/src/tools/clippy/tests/ui/methods_fixable.stderr +++ b/src/tools/clippy/tests/ui/methods_fixable.stderr @@ -5,6 +5,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)` | = note: `-D clippy::filter-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/methods_unfixable.stderr b/src/tools/clippy/tests/ui/methods_unfixable.stderr index 6e101fe16b0..581a985e0b5 100644 --- a/src/tools/clippy/tests/ui/methods_unfixable.stderr +++ b/src/tools/clippy/tests/ui/methods_unfixable.stderr @@ -10,6 +10,7 @@ help: you will also need to make `iter` mutable, because `find` takes `&mut self LL | let iter = (0..10); | ^^^^ = note: `-D clippy::filter-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr index 4dff6588bb1..253636cf91d 100644 --- a/src/tools/clippy/tests/ui/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr @@ -5,6 +5,7 @@ LL | struct A { | ^ | = note: `-D clippy::min-ident-chars` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]` error: this ident consists of a single char --> $DIR/min_ident_chars.rs:9:5 diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr index 128394e627c..e9c64e56b61 100644 --- a/src/tools/clippy/tests/ui/min_max.stderr +++ b/src/tools/clippy/tests/ui/min_max.stderr @@ -5,6 +5,7 @@ LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::min-max` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::min_max)]` error: this `min`/`max` combination leads to constant result --> $DIR/min_max.rs:25:5 diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr index 3d41510a856..795d043e2ac 100644 --- a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr +++ b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr @@ -7,6 +7,7 @@ LL | #[cfg(hermit)] | help: try: `target_os = "hermit"` | = note: `-D clippy::mismatched-target-os` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mismatched_target_os)]` error: operating system used in target family position --> $DIR/mismatched_target_os_non_unix.rs:7:1 diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr index 8f4c60fc9ca..261c33754e7 100644 --- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr +++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr @@ -8,6 +8,7 @@ LL | #[cfg(linux)] | = help: did you mean `unix`? = note: `-D clippy::mismatched-target-os` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mismatched_target_os)]` error: operating system used in target family position --> $DIR/mismatched_target_os_unix.rs:7:1 diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr b/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr index b3200a51d78..8edbe329503 100644 --- a/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr +++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr @@ -6,6 +6,7 @@ LL | impl<B, A> Foo<B, A> {} | = help: try `A`, or a name that does not conflict with `Foo`'s generic params = note: `-D clippy::mismatching-type-param-order` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mismatching_type_param_order)]` error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order --> $DIR/mismatching_type_param_order.rs:11:23 diff --git a/src/tools/clippy/tests/ui/misnamed_getters.stderr b/src/tools/clippy/tests/ui/misnamed_getters.stderr index 58f6f3eb738..aadec654908 100644 --- a/src/tools/clippy/tests/ui/misnamed_getters.stderr +++ b/src/tools/clippy/tests/ui/misnamed_getters.stderr @@ -10,6 +10,7 @@ LL | | } | |_____^ | = note: `-D clippy::misnamed-getters` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]` error: getter function appears to return the wrong field --> $DIR/misnamed_getters.rs:16:5 diff --git a/src/tools/clippy/tests/ui/missing_assert_message.stderr b/src/tools/clippy/tests/ui/missing_assert_message.stderr index 00b9a36e909..e07f52e3f66 100644 --- a/src/tools/clippy/tests/ui/missing_assert_message.stderr +++ b/src/tools/clippy/tests/ui/missing_assert_message.stderr @@ -6,6 +6,7 @@ LL | assert!(foo()); | = help: consider describing why the failing assert is problematic = note: `-D clippy::missing-assert-message` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_assert_message)]` error: assert without any message --> $DIR/missing_assert_message.rs:14:5 diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index 5c6f9e8a7f0..b3a8ad8fa71 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` error: this could be a `const fn` --> $DIR/could_be_const.rs:20:5 diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr index 4e8a49bf1cd..1d8007fa5b0 100644 --- a/src/tools/clippy/tests/ui/missing_doc.stderr +++ b/src/tools/clippy/tests/ui/missing_doc.stderr @@ -5,6 +5,7 @@ LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a module --> $DIR/missing_doc.rs:19:1 diff --git a/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr index 75e033cc94b..c684bc8e707 100644 --- a/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr +++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr @@ -9,6 +9,7 @@ LL | | fn main() {} | |____________^ | = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr index 111d6546966..e303b7b7d9f 100644 --- a/src/tools/clippy/tests/ui/missing_doc_impl.stderr +++ b/src/tools/clippy/tests/ui/missing_doc_impl.stderr @@ -8,6 +8,7 @@ LL | | } | |_^ | = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a struct field --> $DIR/missing_doc_impl.rs:14:5 diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr index 51b5e7b314a..481b2c63217 100644 --- a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr +++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr @@ -18,6 +18,7 @@ LL | hidden: u32, = help: consider including all fields in this `Debug` impl = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields = note: `-D clippy::missing-fields-in-debug` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]` error: manual `Debug` impl does not include all fields --> $DIR/missing_fields_in_debug.rs:32:1 diff --git a/src/tools/clippy/tests/ui/missing_inline.stderr b/src/tools/clippy/tests/ui/missing_inline.stderr index be24af49273..da2a2a7fedd 100644 --- a/src/tools/clippy/tests/ui/missing_inline.stderr +++ b/src/tools/clippy/tests/ui/missing_inline.stderr @@ -5,6 +5,7 @@ LL | pub fn pub_foo() {} | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_inline_in_public_items)]` error: missing `#[inline]` for a default trait method --> $DIR/missing_inline.rs:39:5 diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr index 3dbe2dfbd88..efee485508e 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.stderr +++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr @@ -10,6 +10,7 @@ note: first possible panic found here LL | result.unwrap() | ^^^^^^^^^^^^^^^ = note: `-D clippy::missing-panics-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_panics_doc)]` error: docs for function which may panic missing `# Panics` section --> $DIR/missing_panics_doc.rs:19:1 diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.stderr b/src/tools/clippy/tests/ui/missing_spin_loop.stderr index b525406bbf0..a84c19d5926 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop.stderr +++ b/src/tools/clippy/tests/ui/missing_spin_loop.stderr @@ -5,6 +5,7 @@ LL | while b.load(Ordering::Acquire) {} | ^^ help: try: `{ std::hint::spin_loop() }` | = note: `-D clippy::missing-spin-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_spin_loop)]` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:12:37 diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr index 33e5d32fe88..0b7be461651 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr @@ -5,6 +5,7 @@ LL | while b.load(Ordering::Acquire) {} | ^^ help: try: `{ core::hint::spin_loop() }` | = note: `-D clippy::missing-spin-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_spin_loop)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.stderr b/src/tools/clippy/tests/ui/missing_trait_methods.stderr index 8f50e76135c..3e20a51e084 100644 --- a/src/tools/clippy/tests/ui/missing_trait_methods.stderr +++ b/src/tools/clippy/tests/ui/missing_trait_methods.stderr @@ -10,6 +10,7 @@ help: implement the method LL | fn provided() {} | ^^^^^^^^^^^^^ = note: `-D clippy::missing-trait-methods` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_trait_methods)]` error: missing trait method provided by default: `b` --> $DIR/missing_trait_methods.rs:25:1 diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr index e0b405ddece..3dad98815c6 100644 --- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr +++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr @@ -10,6 +10,7 @@ note: whether read occurs before this write depends on evaluation order LL | x = 1; | ^^^^^ = note: `-D clippy::mixed-read-write-in-expression` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mixed_read_write_in_expression)]` error: unsequenced read of `x` --> $DIR/mixed_read_write_in_expression.rs:18:5 diff --git a/src/tools/clippy/tests/ui/module_inception.stderr b/src/tools/clippy/tests/ui/module_inception.stderr index b4f80a5bc7c..d5856614f91 100644 --- a/src/tools/clippy/tests/ui/module_inception.stderr +++ b/src/tools/clippy/tests/ui/module_inception.stderr @@ -9,6 +9,7 @@ LL | | } | |_________^ | = note: `-D clippy::module-inception` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_inception)]` error: module has the same name as its containing module --> $DIR/module_inception.rs:12:5 diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.stderr b/src/tools/clippy/tests/ui/module_name_repetitions.stderr index 3c7fa1def2b..1854d3a859a 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.stderr +++ b/src/tools/clippy/tests/ui/module_name_repetitions.stderr @@ -5,6 +5,7 @@ LL | pub fn foo_bar() {} | ^^^^^^^ | = note: `-D clippy::module-name-repetitions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` error: item name ends with its containing module's name --> $DIR/module_name_repetitions.rs:11:12 diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr index 3faf8c5aee1..46c8d0288a3 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr @@ -6,6 +6,7 @@ LL | -1.6 % 2.1; | = note: double check for expected result especially when interoperating with different languages = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` error: you are using modulo operator on constants with different signs: `1.600 % -2.100` --> $DIR/modulo_arithmetic_float.rs:9:5 diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr index 6d61afa0c31..033a016c0e6 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr @@ -7,6 +7,7 @@ LL | a % b; = note: double check for expected result especially when interoperating with different languages = note: or consider using `rem_euclid` or similar function = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` error: you are using modulo operator on types that might have different signs --> $DIR/modulo_arithmetic_integral.rs:11:5 diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr index 59267b0e796..47ed2261a7b 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr @@ -7,6 +7,7 @@ LL | -1 % 2; = note: double check for expected result especially when interoperating with different languages = note: or consider using `rem_euclid` or similar function = note: `-D clippy::modulo-arithmetic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` error: you are using modulo operator on constants with different signs: `1 % -2` --> $DIR/modulo_arithmetic_integral_const.rs:14:5 diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr index 62e23ee9a59..cc211ab6cd3 100644 --- a/src/tools/clippy/tests/ui/modulo_one.stderr +++ b/src/tools/clippy/tests/ui/modulo_one.stderr @@ -25,6 +25,7 @@ LL | 10 % 1; | ^^^^^^ | = note: `-D clippy::modulo-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::modulo_one)]` error: any number modulo -1 will panic/overflow or result in 0 --> $DIR/modulo_one.rs:11:5 diff --git a/src/tools/clippy/tests/ui/multi_assignments.stderr b/src/tools/clippy/tests/ui/multi_assignments.stderr index 813e920f74d..9719b5e6684 100644 --- a/src/tools/clippy/tests/ui/multi_assignments.stderr +++ b/src/tools/clippy/tests/ui/multi_assignments.stderr @@ -5,6 +5,7 @@ LL | a = b = c; | ^^^^^^^^^ | = note: `-D clippy::multi-assignments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::multi_assignments)]` error: assignments don't nest intuitively --> $DIR/multi_assignments.rs:7:5 diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr index badc284ec42..4803a5089ab 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -18,6 +18,7 @@ note: unsafe function call occurs here LL | not_very_safe(); | ^^^^^^^^^^^^^^^ = note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` error: this `unsafe` block contains 2 unsafe operations, expected only one --> $DIR/multiple_unsafe_ops_per_block.rs:45:5 diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr index 35da27d83a4..581399f3e48 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.stderr +++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr @@ -5,6 +5,7 @@ LL | pub fn pure(i: u8) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8` | = note: `-D clippy::must-use-candidate` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]` error: this method could have a `#[must_use]` attribute --> $DIR/must_use_candidates.rs:21:5 diff --git a/src/tools/clippy/tests/ui/must_use_unit.stderr b/src/tools/clippy/tests/ui/must_use_unit.stderr index bb421abc663..e67d9b5b9d8 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.stderr +++ b/src/tools/clippy/tests/ui/must_use_unit.stderr @@ -7,6 +7,7 @@ LL | pub fn must_use_default() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::must-use-unit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::must_use_unit)]` error: this unit-returning function has a `#[must_use]` attribute --> $DIR/must_use_unit.rs:13:1 diff --git a/src/tools/clippy/tests/ui/mut_from_ref.stderr b/src/tools/clippy/tests/ui/mut_from_ref.stderr index 1c3df2b54fc..38f47b9ad7b 100644 --- a/src/tools/clippy/tests/ui/mut_from_ref.stderr +++ b/src/tools/clippy/tests/ui/mut_from_ref.stderr @@ -10,6 +10,7 @@ note: immutable borrow here LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^ = note: `-D clippy::mut-from-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]` error: mutable borrow from immutable input(s) --> $DIR/mut_from_ref.rs:14:25 diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr index bce9d4b5892..3701769a9ca 100644 --- a/src/tools/clippy/tests/ui/mut_key.stderr +++ b/src/tools/clippy/tests/ui/mut_key.stderr @@ -5,6 +5,7 @@ LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> Hash | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::mutable-key-type` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mutable_key_type)]` error: mutable key type --> $DIR/mut_key.rs:31:72 @@ -109,6 +110,7 @@ LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> Hash | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/mut_mut.stderr b/src/tools/clippy/tests/ui/mut_mut.stderr index 58a1c4e683c..5ed9cd1aff9 100644 --- a/src/tools/clippy/tests/ui/mut_mut.stderr +++ b/src/tools/clippy/tests/ui/mut_mut.stderr @@ -5,6 +5,7 @@ LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ | = note: `-D clippy::mut-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` error: generally you want to avoid `&mut &mut _` if possible --> $DIR/mut_mut.rs:31:17 diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.stderr b/src/tools/clippy/tests/ui/mut_mutex_lock.stderr index f7b371822de..9b20016be79 100644 --- a/src/tools/clippy/tests/ui/mut_mutex_lock.stderr +++ b/src/tools/clippy/tests/ui/mut_mutex_lock.stderr @@ -5,6 +5,7 @@ LL | let mut value = value_mutex.lock().unwrap(); | ^^^^ help: change this to: `get_mut` | = note: `-D clippy::mut-mutex-lock` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/mut_range_bound.stderr b/src/tools/clippy/tests/ui/mut_range_bound.stderr index c9de5393a2b..42f8a161f74 100644 --- a/src/tools/clippy/tests/ui/mut_range_bound.stderr +++ b/src/tools/clippy/tests/ui/mut_range_bound.stderr @@ -6,6 +6,7 @@ LL | m = 5; | = note: the range of the loop is unchanged = note: `-D clippy::mut-range-bound` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mut_range_bound)]` error: attempt to mutate range bound within loop --> $DIR/mut_range_bound.rs:17:9 diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr index 4346560cea5..d7a0d0c2252 100644 --- a/src/tools/clippy/tests/ui/mut_reference.stderr +++ b/src/tools/clippy/tests/ui/mut_reference.stderr @@ -5,6 +5,7 @@ LL | takes_an_immutable_reference(&mut 42); | ^^^^^^^ | = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` error: the function `as_ptr` doesn't need a mutable reference --> $DIR/mut_reference.rs:36:12 @@ -25,6 +26,7 @@ LL | fn takes_a_mutable_reference(&self, a: &mut i32) {} | ^^^^^^^^ help: consider changing to: `&i32` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/mutex_atomic.stderr b/src/tools/clippy/tests/ui/mutex_atomic.stderr index 2f669067da6..483e1ce15f6 100644 --- a/src/tools/clippy/tests/ui/mutex_atomic.stderr +++ b/src/tools/clippy/tests/ui/mutex_atomic.stderr @@ -5,6 +5,7 @@ LL | Mutex::new(true); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::mutex-atomic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mutex_atomic)]` error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:11:5 @@ -37,6 +38,7 @@ LL | Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::mutex-integer` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]` error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` --> $DIR/mutex_atomic.rs:23:5 diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr index c5b0b25c10b..fe2ac34f79f 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr @@ -5,6 +5,7 @@ LL | pub fn bad(self: Self) { | ^^^^^^^^^^ help: consider to change this parameter to: `self` | = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_arbitrary_self_type)]` error: the type of the `self` parameter does not need to be arbitrary --> $DIR/needless_arbitrary_self_type.rs:18:20 diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr index c7df5936d70..183e2dbc8c1 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr @@ -5,6 +5,7 @@ LL | fn call_with_mut_self(self: &mut Self) {} | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&mut self` | = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_arbitrary_self_type)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr index 9752624902c..2ed9208e623 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr @@ -5,6 +5,7 @@ LL | if y & !x { | ^^^^^^ help: try: `y && !x` | = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_bitwise_bool)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index a2dfa2fd482..2b189c89851 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -9,6 +9,7 @@ LL | | }; | |_____^ help: you can reduce it to: `x` | = note: `-D clippy::needless-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression returns a bool literal --> $DIR/fixable.rs:45:5 @@ -137,6 +138,7 @@ LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` | = note: `-D clippy::bool-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation --> $DIR/fixable.rs:147:8 diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.stderr b/src/tools/clippy/tests/ui/needless_bool/simple.stderr index 0ccc9416bcd..a44205c59b7 100644 --- a/src/tools/clippy/tests/ui/needless_bool/simple.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/simple.stderr @@ -9,6 +9,7 @@ LL | | }; | |_____^ | = note: `-D clippy::needless-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression will always return false --> $DIR/simple.rs:19:5 diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.stderr b/src/tools/clippy/tests/ui/needless_bool_assign.stderr index 8e7ea615c7d..7866c89bd61 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.stderr +++ b/src/tools/clippy/tests/ui/needless_bool_assign.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ help: you can reduce it to: `a.field = random() && random();` | = note: `-D clippy::needless-bool-assign` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_bool_assign)]` error: this if-then-else expression assigns a bool literal --> $DIR/needless_bool_assign.rs:18:5 diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index d26c317124b..8e27014d53c 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -5,6 +5,7 @@ LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` | = note: `-D clippy::needless-borrow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this expression creates a reference which is immediately dereferenced by the compiler --> $DIR/needless_borrow.rs:19:13 diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr index 4eac32fcd9c..ce3a36e35b8 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr @@ -5,6 +5,7 @@ LL | Some(ref x) => x, | ^^^^^ help: try: `x` | = note: `-D clippy::needless-borrow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:67:14 diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr index 553b068c6b4..15261cfce0c 100644 --- a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr +++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr @@ -5,6 +5,7 @@ LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); | ^^^^^^ | = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_borrowed_reference)]` help: try removing the `&ref` part | LL - let _ = v.iter_mut().filter(|&ref a| a.is_empty()); diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index c24568bba9c..2c21fc5965d 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -5,6 +5,7 @@ LL | let len = sample.iter().collect::<Vec<_>>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` | = note: `-D clippy::needless-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]` error: avoid using `collect()` when not needed --> $DIR/needless_collect.rs:10:22 diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr index 9337a741242..3d1ad2a1cfa 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr @@ -8,6 +8,7 @@ LL | indirect_iter.into_iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>( | ------------------------- the iterator could be used here instead | = note: `-D clippy::needless-collect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]` help: use the original Iterator instead of collecting it and then producing a new one | LL ~ diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr index 9a65248c991..31b5dc2808d 100644 --- a/src/tools/clippy/tests/ui/needless_continue.stderr +++ b/src/tools/clippy/tests/ui/needless_continue.stderr @@ -35,6 +35,7 @@ LL | | } println!("bleh"); } = note: `-D clippy::needless-continue` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_continue)]` error: there is no need for an explicit `else` block for this `if` expression --> $DIR/needless_continue.rs:46:9 diff --git a/src/tools/clippy/tests/ui/needless_doc_main.stderr b/src/tools/clippy/tests/ui/needless_doc_main.stderr index be6675e6482..8dd93bb05dd 100644 --- a/src/tools/clippy/tests/ui/needless_doc_main.stderr +++ b/src/tools/clippy/tests/ui/needless_doc_main.stderr @@ -5,6 +5,7 @@ LL | /// fn main() { | ^^^^^^^^^^^^ | = note: `-D clippy::needless-doctest-main` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]` error: needless `fn main` in doctest --> $DIR/needless_doc_main.rs:16:4 diff --git a/src/tools/clippy/tests/ui/needless_else.stderr b/src/tools/clippy/tests/ui/needless_else.stderr index 006e4d7d30f..e6f7138e948 100644 --- a/src/tools/clippy/tests/ui/needless_else.stderr +++ b/src/tools/clippy/tests/ui/needless_else.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: you can remove it | = note: `-D clippy::needless-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_else)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr index 08e995851d7..3b5163b0171 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr @@ -7,6 +7,7 @@ LL | | }); | |_______^ | = note: `-D clippy::needless-for-each` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_for_each)]` help: try | LL ~ for elem in v.iter() { diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr index dad0053f559..73f249ae6c2 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr @@ -11,6 +11,7 @@ LL | | }); | |_______^ | = note: `-D clippy::needless-for-each` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_for_each)]` help: try | LL ~ for v in v.iter() { diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr index bf131f2d7e4..ed5b9452b86 100644 --- a/src/tools/clippy/tests/ui/needless_if.stderr +++ b/src/tools/clippy/tests/ui/needless_if.stderr @@ -5,6 +5,7 @@ LL | if (true) {} | ^^^^^^^^^^^^ help: you can remove it | = note: `-D clippy::needless-if` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_if)]` error: this `if` branch is empty --> $DIR/needless_if.rs:28:5 diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index eff782f8bf1..602b1a683e5 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -7,6 +7,7 @@ LL | a = "zero"; | ^^^^^^^^^^ initialised here | = note: `-D clippy::needless-late-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_late_init)]` help: declare `a` here | LL | let a = "zero"; diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index 23b9cbe3f85..7051a2604b9 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -5,6 +5,7 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^ ^^ ^^ ^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_lifetimes)]` help: elide the lifetimes | LL - fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/src/tools/clippy/tests/ui/needless_match.stderr b/src/tools/clippy/tests/ui/needless_match.stderr index 6ae2f38bf50..736926b4415 100644 --- a/src/tools/clippy/tests/ui/needless_match.stderr +++ b/src/tools/clippy/tests/ui/needless_match.stderr @@ -11,6 +11,7 @@ LL | | }; | |_____^ help: replace it with: `i` | = note: `-D clippy::needless-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_match)]` error: this match expression is unnecessary --> $DIR/needless_match.rs:22:19 diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.stderr b/src/tools/clippy/tests/ui/needless_option_as_deref.stderr index 94be76a9a45..024d30c1717 100644 --- a/src/tools/clippy/tests/ui/needless_option_as_deref.stderr +++ b/src/tools/clippy/tests/ui/needless_option_as_deref.stderr @@ -5,6 +5,7 @@ LL | let _: Option<&usize> = Some(&1).as_deref(); | ^^^^^^^^^^^^^^^^^^^ help: try: `Some(&1)` | = note: `-D clippy::needless-option-as-deref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_option_as_deref)]` error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:8:33 diff --git a/src/tools/clippy/tests/ui/needless_option_take.stderr b/src/tools/clippy/tests/ui/needless_option_take.stderr index b6b50d6f2ff..d3c22441d00 100644 --- a/src/tools/clippy/tests/ui/needless_option_take.stderr +++ b/src/tools/clippy/tests/ui/needless_option_take.stderr @@ -5,6 +5,7 @@ LL | x.as_ref().take(); | ^^^^^^^^^^^^^^^^^ help: try: `x.as_ref()` | = note: `-D clippy::needless-option-take` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_option_take)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr index 0fe331ecc75..c73564e210c 100644 --- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr +++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr @@ -5,6 +5,7 @@ LL | let _ = ('a')..=('z'); | ^^^^^ help: try: `'a'` | = note: `-D clippy::needless-parens-on-range-literals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_parens_on_range_literals)]` error: needless parenthesis on range literals can be removed --> $DIR/needless_parens_on_range_literals.rs:7:21 diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index 2e06e7252d9..df3df045776 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -5,6 +5,7 @@ LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably --> $DIR/needless_pass_by_ref_mut.rs:31:12 diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr index a6bf30b1cdf..1c3a63d661f 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr @@ -5,6 +5,7 @@ LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T | ^^^^^^ help: consider changing the type to: `&[T]` | = note: `-D clippy::needless-pass-by-value` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_value)]` error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:34:11 diff --git a/src/tools/clippy/tests/ui/needless_pub_self.stderr b/src/tools/clippy/tests/ui/needless_pub_self.stderr index 3aa2feb5ecd..c1f6b908b53 100644 --- a/src/tools/clippy/tests/ui/needless_pub_self.stderr +++ b/src/tools/clippy/tests/ui/needless_pub_self.stderr @@ -5,6 +5,7 @@ LL | pub(self) fn a() {} | ^^^^^^^^^ help: remove it | = note: `-D clippy::needless-pub-self` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pub_self)]` error: unnecessary `pub(in self)` --> $DIR/needless_pub_self.rs:14:1 diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index 3e1d2c17c30..cd961a49f42 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -5,6 +5,7 @@ LL | return Some(to.magic?); | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` | = note: `-D clippy::needless-question-mark` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]` error: question mark operator is useless here --> $DIR/needless_question_mark.rs:28:12 diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr index 0358b2fb025..0d8893c2619 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop.stderr +++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr @@ -5,6 +5,7 @@ LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ | = note: `-D clippy::needless-range-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_range_loop)]` help: consider using an iterator | LL | for <item> in &vec { diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.stderr b/src/tools/clippy/tests/ui/needless_range_loop2.stderr index 6e6ef73c1f6..3d1d9e1bff4 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop2.stderr +++ b/src/tools/clippy/tests/ui/needless_range_loop2.stderr @@ -5,6 +5,7 @@ LL | for i in 3..10 { | ^^^^^ | = note: `-D clippy::needless-range-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_range_loop)]` help: consider using an iterator | LL | for <item> in ns.iter().take(10).skip(3) { diff --git a/src/tools/clippy/tests/ui/needless_raw_string.stderr b/src/tools/clippy/tests/ui/needless_raw_string.stderr index ddc36af2e72..83cc6d332ee 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string.stderr @@ -5,6 +5,7 @@ LL | r#"aaa"#; | ^^^^^^^^ help: try: `"aaa"` | = note: `-D clippy::needless-raw-strings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]` error: unnecessary raw string literal --> $DIR/needless_raw_string.rs:9:5 diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr index 9649d59a71f..94c51c423b8 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr @@ -5,6 +5,7 @@ LL | r##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `r#"Hello "world"!"#` | = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]` error: unnecessary hashes around raw string literal --> $DIR/needless_raw_string_hashes.rs:8:5 diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index eea9a5ff9cf..cc48831115d 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -5,6 +5,7 @@ LL | return true; | ^^^^^^^^^^^ | = note: `-D clippy::needless-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_return)]` help: remove `return` | LL - return true; diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr index 5cc20e9682b..0de0633803b 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr @@ -5,6 +5,7 @@ LL | return Err(())?; | ^^^^^^^ help: remove it | = note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_return_with_question_mark)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/needless_splitn.stderr b/src/tools/clippy/tests/ui/needless_splitn.stderr index 14c576e6457..f347ca760db 100644 --- a/src/tools/clippy/tests/ui/needless_splitn.stderr +++ b/src/tools/clippy/tests/ui/needless_splitn.stderr @@ -5,6 +5,7 @@ LL | let _ = str.splitn(2, '=').next(); | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` | = note: `-D clippy::needless-splitn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_splitn)]` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:14:13 diff --git a/src/tools/clippy/tests/ui/needless_update.stderr b/src/tools/clippy/tests/ui/needless_update.stderr index b154b3b306d..3e9e2941a7a 100644 --- a/src/tools/clippy/tests/ui/needless_update.stderr +++ b/src/tools/clippy/tests/ui/needless_update.stderr @@ -5,6 +5,7 @@ LL | S { a: 1, b: 1, ..base }; | ^^^^ | = note: `-D clippy::needless-update` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_update)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr index c2e1f8702dd..c64d96b4b20 100644 --- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr @@ -5,6 +5,7 @@ LL | let _not_less = !(a_value < another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::neg_cmp_op_on_partial_ord)]` error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable --> $DIR/neg_cmp_op_on_partial_ord.rs:21:30 diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr index 8b31bca0b7d..abfc94f9770 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.stderr +++ b/src/tools/clippy/tests/ui/neg_multiply.stderr @@ -5,6 +5,7 @@ LL | x * -1; | ^^^^^^ help: consider using: `-x` | = note: `-D clippy::neg-multiply` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::neg_multiply)]` error: this multiplication by -1 can be written more succinctly --> $DIR/neg_multiply.rs:30:5 diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr index 6d6d2c8ac52..234780007b1 100644 --- a/src/tools/clippy/tests/ui/never_loop.stderr +++ b/src/tools/clippy/tests/ui/never_loop.stderr @@ -137,6 +137,7 @@ LL | break 'a; | ^^^^^^^^ | = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::diverging_sub_expression)]` error: this loop never actually loops --> $DIR/never_loop.rs:294:13 diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr index 4c76603f596..8436e101ff9 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.stderr +++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` error: methods called `new` usually return `Self` --> $DIR/new_ret_no_self.rs:84:5 diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr index 4293cd5972d..acba5b0d7bd 100644 --- a/src/tools/clippy/tests/ui/new_without_default.stderr +++ b/src/tools/clippy/tests/ui/new_without_default.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::new-without-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::new_without_default)]` help: try adding this | LL + impl Default for Foo { diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index 4b8499a23a5..feba35697f5 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -5,6 +5,7 @@ LL | 0; | ^^ | = note: `-D clippy::no-effect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::no_effect)]` error: statement with no effect --> $DIR/no_effect.rs:101:5 @@ -157,6 +158,7 @@ LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect --> $DIR/no_effect.rs:154:5 diff --git a/src/tools/clippy/tests/ui/no_effect_replace.stderr b/src/tools/clippy/tests/ui/no_effect_replace.stderr index 685b20b75d4..e1162f04f85 100644 --- a/src/tools/clippy/tests/ui/no_effect_replace.stderr +++ b/src/tools/clippy/tests/ui/no_effect_replace.stderr @@ -5,6 +5,7 @@ LL | let _ = "12345".replace('1', "1"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::no-effect-replace` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::no_effect_replace)]` error: replacing text with itself --> $DIR/no_effect_replace.rs:7:13 diff --git a/src/tools/clippy/tests/ui/no_effect_return.stderr b/src/tools/clippy/tests/ui/no_effect_return.stderr index 6b146a03abc..b036e634204 100644 --- a/src/tools/clippy/tests/ui/no_effect_return.stderr +++ b/src/tools/clippy/tests/ui/no_effect_return.stderr @@ -7,6 +7,7 @@ LL | 0u32; | help: did you mean to return it?: `return` | = note: `-D clippy::no-effect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::no_effect)]` error: statement with no effect --> $DIR/no_effect_return.rs:18:9 diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr index 721dcf603b1..62d53c8395f 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr @@ -5,6 +5,7 @@ LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::no_mangle_with_rust_abi)]` help: set an ABI | LL | extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} diff --git a/src/tools/clippy/tests/ui/non_expressive_names.stderr b/src/tools/clippy/tests/ui/non_expressive_names.stderr index b62748d4989..1b78124a903 100644 --- a/src/tools/clippy/tests/ui/non_expressive_names.stderr +++ b/src/tools/clippy/tests/ui/non_expressive_names.stderr @@ -5,6 +5,7 @@ LL | let _1 = 1; | ^^ | = note: `-D clippy::just-underscores-and-digits` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::just_underscores_and_digits)]` error: consider choosing a more descriptive name --> $DIR/non_expressive_names.rs:29:9 diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr index d0212e23021..c33c35ed8df 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr @@ -5,6 +5,7 @@ LL | #[cfg(all(windows))] | ^^^^^^^^^^^^ help: try: `windows` | = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_minimal_cfg)]` error: unneeded sub `cfg` when there is only one condition --> $DIR/non_minimal_cfg.rs:6:7 diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr index 2a9a36fbcef..001fcddd906 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr @@ -5,6 +5,7 @@ LL | #[cfg(all())] | ^^^^^ | = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_minimal_cfg)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr index 32845d06594..78c8f1a2fcf 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr @@ -5,6 +5,7 @@ LL | options.mode(440); | ^^^ help: consider using an octal literal instead: `0o440` | = note: `-D clippy::non-octal-unix-permissions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_octal_unix_permissions)]` error: using a non-octal value to set unix file permissions --> $DIR/non_octal_unix_permissions.rs:17:47 diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr index 08a53b3a891..1ea76196af9 100644 --- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr +++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr @@ -11,6 +11,7 @@ LL | data: Vec<UnsafeCell<T>>, | ^^^^^^^^^^^^^^^^^^^^^^^^ = help: add bounds on type parameter `T` that satisfy `Vec<UnsafeCell<T>>: Send` = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_send_fields_in_send_ty)]` error: some fields in `MvccRwLock<T>` are not safe to be sent to another thread --> $DIR/non_send_fields_in_send_ty.rs:26:1 diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr index 2eba55555f4..deae389dbef 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr @@ -5,6 +5,7 @@ LL | let _ = !true; | ^^^^^ help: try: `false` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified --> $DIR/nonminimal_bool.rs:16:13 diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr index a2df889d623..d47bbf7e079 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr @@ -5,6 +5,7 @@ LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified --> $DIR/nonminimal_bool_methods.rs:10:13 diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/numbered_fields.stderr index 076c7aa0c6a..d52a0cf15a8 100644 --- a/src/tools/clippy/tests/ui/numbered_fields.stderr +++ b/src/tools/clippy/tests/ui/numbered_fields.stderr @@ -10,6 +10,7 @@ LL | | }; | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)` | = note: `-D clippy::init-numbered-fields` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]` error: used a field initializer for a tuple struct --> $DIR/numbered_fields.rs:25:13 diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr index 1848151b1da..ca9f5e1e374 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr @@ -5,6 +5,7 @@ LL | true.then_some("a").unwrap_or("b"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` | = note: `-D clippy::obfuscated-if-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::obfuscated_if_else)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr index 98f7d21261f..d2161582b82 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.stderr +++ b/src/tools/clippy/tests/ui/octal_escapes.stderr @@ -6,6 +6,7 @@ LL | let _bad1 = "\033[0m"; | = help: octal escapes are not supported, `\0` is always a null character = note: `-D clippy::octal-escapes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::octal_escapes)]` help: if an octal escape was intended, use the hexadecimal representation instead | LL | let _bad1 = "\x1b[0m"; diff --git a/src/tools/clippy/tests/ui/ok_expect.stderr b/src/tools/clippy/tests/ui/ok_expect.stderr index 4c295d7a4c2..ac2b6dcc83b 100644 --- a/src/tools/clippy/tests/ui/ok_expect.stderr +++ b/src/tools/clippy/tests/ui/ok_expect.stderr @@ -6,6 +6,7 @@ LL | res.ok().expect("disaster!"); | = help: you can call `expect()` directly on the `Result` = note: `-D clippy::ok-expect` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ok_expect)]` error: called `ok().expect()` on a `Result` value --> $DIR/ok_expect.rs:23:5 diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion.stderr index b731d37c62c..85eee99c01c 100644 --- a/src/tools/clippy/tests/ui/only_used_in_recursion.stderr +++ b/src/tools/clippy/tests/ui/only_used_in_recursion.stderr @@ -10,6 +10,7 @@ note: parameter used here LL | if flag == 0 { 0 } else { _one_unused(flag - 1, a) } | ^ = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]` error: parameter is only used in recursion --> $DIR/only_used_in_recursion.rs:16:27 diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr index ae349fd29e9..3ddd9758c26 100644 --- a/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr +++ b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr @@ -10,6 +10,7 @@ note: parameter used here LL | if flag == 0 { 0 } else { _with_inner(flag, a, b + x) } | ^ = note: `-D clippy::only-used-in-recursion` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]` error: parameter is only used in recursion --> $DIR/only_used_in_recursion2.rs:5:25 diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr index 5f3769ddfab..f03e24b8400 100644 --- a/src/tools/clippy/tests/ui/op_ref.stderr +++ b/src/tools/clippy/tests/ui/op_ref.stderr @@ -5,6 +5,7 @@ LL | let foo = &5 - &6; | ^^^^^^^ | = note: `-D clippy::op-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::op_ref)]` help: use the values directly | LL | let foo = 5 - 6; diff --git a/src/tools/clippy/tests/ui/open_options.stderr b/src/tools/clippy/tests/ui/open_options.stderr index c136cf2dbf4..7ac826f52fa 100644 --- a/src/tools/clippy/tests/ui/open_options.stderr +++ b/src/tools/clippy/tests/ui/open_options.stderr @@ -5,6 +5,7 @@ LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::nonsensical-open-options` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::nonsensical_open_options)]` error: file opened with `append` and `truncate` --> $DIR/open_options.rs:9:5 diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr index b5dc6a7f331..eb0661c523a 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr @@ -5,6 +5,7 @@ LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()` | = note: `-D clippy::option-as-ref-deref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_deref)]` error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead --> $DIR/option_as_ref_deref.rs:14:13 diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr index cfa9dd58a30..de31d0c7f09 100644 --- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr +++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr @@ -6,6 +6,7 @@ LL | let _ = option_env!("PATH").unwrap(); | = help: consider using the `env!` macro instead = note: `-D clippy::option-env-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_env_unwrap)]` error: this will panic at run-time if the environment variable doesn't exist at compile-time --> $DIR/option_env_unwrap.rs:11:13 diff --git a/src/tools/clippy/tests/ui/option_filter_map.stderr b/src/tools/clippy/tests/ui/option_filter_map.stderr index e7da7c29287..148f9d02f5e 100644 --- a/src/tools/clippy/tests/ui/option_filter_map.stderr +++ b/src/tools/clippy/tests/ui/option_filter_map.stderr @@ -5,6 +5,7 @@ LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` | = note: `-D clippy::option-filter-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_filter_map)]` error: `filter` for `Some` followed by `unwrap` --> $DIR/option_filter_map.rs:6:27 diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr index aa2da217400..6d7d02f8c25 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ help: try: `string.map_or((false, "hello"), |x| (true, x))` | = note: `-D clippy::option-if-let-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]` error: use Option::map_or instead of an if let/else --> $DIR/option_if_let_else.rs:30:13 diff --git a/src/tools/clippy/tests/ui/option_map_or_none.stderr b/src/tools/clippy/tests/ui/option_map_or_none.stderr index 76c46455343..fa150718f89 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr @@ -5,6 +5,7 @@ LL | let _: Option<i32> = opt.map_or(None, |x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_map_or_none)]` error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead --> $DIR/option_map_or_none.rs:13:26 @@ -48,6 +49,7 @@ LL | let _: Option<i32> = r.map_or(None, Some); | ^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `r.ok()` | = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr index 38bcb5967f6..34aca31e95c 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr @@ -7,6 +7,7 @@ LL | x.field.map(do_nothing); | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }` | = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_map_unit_fn)]` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:39:5 diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 5a904c2f490..afa4b762811 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -5,6 +5,7 @@ LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)` | = note: `-D clippy::or-fun-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]` error: use of `unwrap_or` to construct default value --> $DIR/or_fun_call.rs:55:14 @@ -13,6 +14,7 @@ LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` | = note: `-D clippy::unwrap-or-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:58:21 diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.stderr b/src/tools/clippy/tests/ui/or_then_unwrap.stderr index 4b47f538a6c..99e4488c040 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.stderr +++ b/src/tools/clippy/tests/ui/or_then_unwrap.stderr @@ -5,6 +5,7 @@ LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` | = note: `-D clippy::or-then-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::or_then_unwrap)]` error: found `.or(Ok(…)).unwrap()` --> $DIR/or_then_unwrap.rs:25:20 diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr index b50b76bd9b2..37db11caab8 100644 --- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr +++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr @@ -5,6 +5,7 @@ LL | &x[num..10]; | ^^ | = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: range is out of bounds --> $DIR/issue-3102.rs:12:8 diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr index ea5e83e87e0..ddef38beb31 100644 --- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr +++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr @@ -5,6 +5,7 @@ LL | &x[..=4]; | ^ | = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: range is out of bounds --> $DIR/simple.rs:10:11 diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr index b1e9f1eee54..b3cab8a2109 100644 --- a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr +++ b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr @@ -5,6 +5,7 @@ LL | if a + b < a {} | ^^^^^^^^^ | = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]` error: you are trying to use classic C overflow conditions that will fail in Rust --> $DIR/overflow_check_conditional.rs:8:8 diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr index d296b88224d..dc62d0e1dbd 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr @@ -10,6 +10,7 @@ help: this expression can be optimized out by applying boolean operations to the LL | let _ = a && b || a; | ^ = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::overly_complex_bool_expr)]` error: this boolean expression contains a logic bug --> $DIR/overly_complex_bool_expr.rs:14:13 diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr index 9040018f1d4..d55c5cf36f6 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr @@ -15,6 +15,7 @@ note: return Err() instead of panicking LL | panic!("error"); | ^^^^^^^^^^^^^^^ = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panic_in_result_fn)]` error: used `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn.rs:53:1 diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr index 368a9970af8..a80e6f27abc 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr +++ b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr @@ -16,6 +16,7 @@ note: return Err() instead of panicking LL | assert!(x == 5, "wrong argument"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panic_in_result_fn)]` error: used `panic!()` or assertion in a function that returns `Result` --> $DIR/panic_in_result_fn_assertions.rs:14:5 diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr index b47220d2cdc..59ce57d0b3d 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.stderr +++ b/src/tools/clippy/tests/ui/panicking_macros.stderr @@ -5,6 +5,7 @@ LL | panic!(); | ^^^^^^^^ | = note: `-D clippy::panic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::panic)]` error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:26:5 @@ -25,6 +26,7 @@ LL | todo!(); | ^^^^^^^ | = note: `-D clippy::todo` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::todo)]` error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:38:5 @@ -45,6 +47,7 @@ LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unimplemented` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]` error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:50:5 @@ -65,6 +68,7 @@ LL | unreachable!(); | ^^^^^^^^^^^^^^ | = note: `-D clippy::unreachable` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unreachable)]` error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:62:5 diff --git a/src/tools/clippy/tests/ui/partial_pub_fields.stderr b/src/tools/clippy/tests/ui/partial_pub_fields.stderr index 95960201769..a152287403b 100644 --- a/src/tools/clippy/tests/ui/partial_pub_fields.stderr +++ b/src/tools/clippy/tests/ui/partial_pub_fields.stderr @@ -6,6 +6,7 @@ LL | pub paths: HashMap<u32, String>, | = help: consider using private field here = note: `-D clippy::partial-pub-fields` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::partial_pub_fields)]` error: mixed usage of pub and non-pub fields --> $DIR/partial_pub_fields.rs:17:9 diff --git a/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr b/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr index 04b29dd8764..163d6b1dd7b 100644 --- a/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr +++ b/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::partialeq-ne-impl` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::partialeq_ne_impl)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr index d06ab7aee55..50ce15001f4 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.stderr +++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr @@ -5,6 +5,7 @@ LL | if f != None { "yay" } else { "nay" } | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` | = note: `-D clippy::partialeq-to-none` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::partialeq_to_none)]` error: binary comparison to literal `Option::None` --> $DIR/partialeq_to_none.rs:44:13 diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr b/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr index c94b3217804..1453d020c41 100644 --- a/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr +++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr @@ -5,6 +5,7 @@ LL | x.push("/bar"); | ^^^^^^ help: try: `"bar"` | = note: `-D clippy::path-buf-push-overwrite` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::path_buf_push_overwrite)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr index b512f5e1ee2..f21e1894af2 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr @@ -6,6 +6,7 @@ LL | Some(_) => (), | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type --> $DIR/mutability.rs:16:9 diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr index 8e0d13bc8bd..b72c24840d7 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr @@ -6,6 +6,7 @@ LL | if let Value::B | Value::A(_) = ref_value {} | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type --> $DIR/pattern_alternatives.rs:17:34 diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr index a0c7a67b521..c46c7de6dd6 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr @@ -6,6 +6,7 @@ LL | let Struct { .. } = ref_value; | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type --> $DIR/pattern_structs.rs:15:33 diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr index 1001f4f63c6..b365731d561 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr @@ -6,6 +6,7 @@ LL | let TupleStruct(_) = ref_value; | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type --> $DIR/pattern_tuples.rs:13:25 diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr index 36869598815..dfe4639c774 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr @@ -6,6 +6,7 @@ LL | Some(_) => (), | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type --> $DIR/syntax.rs:31:12 diff --git a/src/tools/clippy/tests/ui/patterns.stderr b/src/tools/clippy/tests/ui/patterns.stderr index e2431cb3009..2f608bbc18f 100644 --- a/src/tools/clippy/tests/ui/patterns.stderr +++ b/src/tools/clippy/tests/ui/patterns.stderr @@ -5,6 +5,7 @@ LL | y @ _ => (), | ^^^^^ help: try: `y` | = note: `-D clippy::redundant-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern)]` error: the `x @ _` pattern can be written as just `x` --> $DIR/patterns.rs:29:9 diff --git a/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr b/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr index e7a8ee6cb19..58a7de84d8f 100644 --- a/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr +++ b/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr @@ -8,6 +8,7 @@ LL | permissions.set_readonly(false); = help: you can set the desired permissions using `PermissionsExt`. For more information, see https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::permissions_set_readonly_false)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/precedence.stderr b/src/tools/clippy/tests/ui/precedence.stderr index 30f4607ad17..bd0cbccc787 100644 --- a/src/tools/clippy/tests/ui/precedence.stderr +++ b/src/tools/clippy/tests/ui/precedence.stderr @@ -5,6 +5,7 @@ LL | 1 << 2 + 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `1 << (2 + 3)` | = note: `-D clippy::precedence` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::precedence)]` error: operator precedence can trip the unwary --> $DIR/precedence.rs:17:5 diff --git a/src/tools/clippy/tests/ui/print.stderr b/src/tools/clippy/tests/ui/print.stderr index e9d88df33f5..bb8d945081e 100644 --- a/src/tools/clippy/tests/ui/print.stderr +++ b/src/tools/clippy/tests/ui/print.stderr @@ -5,6 +5,7 @@ LL | write!(f, "{:?}", 43.1415) | ^^^^ | = note: `-D clippy::use-debug` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::use_debug)]` error: use of `println!` --> $DIR/print.rs:25:5 @@ -13,6 +14,7 @@ LL | println!("Hello"); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::print-stdout` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_stdout)]` error: use of `print!` --> $DIR/print.rs:28:5 diff --git a/src/tools/clippy/tests/ui/print_in_format_impl.stderr b/src/tools/clippy/tests/ui/print_in_format_impl.stderr index 7a7a2dc1c2a..57f06dc1143 100644 --- a/src/tools/clippy/tests/ui/print_in_format_impl.stderr +++ b/src/tools/clippy/tests/ui/print_in_format_impl.stderr @@ -5,6 +5,7 @@ LL | print!("{}", 1); | ^^^^^^^^^^^^^^^ help: replace with: `write!(f, ..)` | = note: `-D clippy::print-in-format-impl` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_in_format_impl)]` error: use of `println!` in `Debug` impl --> $DIR/print_in_format_impl.rs:23:9 diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index d7a2fa7f4bb..1d9751b92e9 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr @@ -5,6 +5,7 @@ LL | print!("Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::print-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_literal)]` help: try | LL - print!("Hello {}", "world"); diff --git a/src/tools/clippy/tests/ui/print_stderr.stderr b/src/tools/clippy/tests/ui/print_stderr.stderr index 0a56fbcec99..7de16331067 100644 --- a/src/tools/clippy/tests/ui/print_stderr.stderr +++ b/src/tools/clippy/tests/ui/print_stderr.stderr @@ -5,6 +5,7 @@ LL | eprintln!("Hello"); | ^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::print-stderr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_stderr)]` error: use of `eprint!` --> $DIR/print_stderr.rs:8:5 diff --git a/src/tools/clippy/tests/ui/print_with_newline.stderr b/src/tools/clippy/tests/ui/print_with_newline.stderr index 1c5f2548c89..7ff6a5f060d 100644 --- a/src/tools/clippy/tests/ui/print_with_newline.stderr +++ b/src/tools/clippy/tests/ui/print_with_newline.stderr @@ -5,6 +5,7 @@ LL | print!("Hello\n"); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::print-with-newline` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::print_with_newline)]` help: use `println!` instead | LL - print!("Hello\n"); diff --git a/src/tools/clippy/tests/ui/println_empty_string.stderr b/src/tools/clippy/tests/ui/println_empty_string.stderr index eb740abc6b0..c89e64f665a 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.stderr +++ b/src/tools/clippy/tests/ui/println_empty_string.stderr @@ -7,6 +7,7 @@ LL | println!(""); | help: remove the empty string | = note: `-D clippy::println-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::println_empty_string)]` error: empty string literal in `println!` --> $DIR/println_empty_string.rs:8:14 diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index e5708ce3a7e..cccf2d62d63 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -5,6 +5,7 @@ LL | fn do_vec(x: &Vec<i64>) { | ^^^^^^^^^ help: change this to: `&[i64]` | = note: `-D clippy::ptr-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_arg)]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do --> $DIR/ptr_arg.rs:20:18 diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index 9bd8f9b17d4..c0ce69b4357 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -5,6 +5,7 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()` | = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` error: `as` casting between raw pointers without changing its mutability --> $DIR/ptr_as_ptr.rs:27:13 diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr index 76a5c7e0165..a4bf778ad19 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr @@ -5,6 +5,7 @@ LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` | = note: `-D clippy::ptr-cast-constness` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_cast_constness)]` error: `as` casting between raw pointers while changing only its constness --> $DIR/ptr_cast_constness.rs:11:19 diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr index 3cdc30f970a..2a384accac5 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq.stderr @@ -5,6 +5,7 @@ LL | let _ = a as *const _ as usize == b as *const _ as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` | = note: `-D clippy::ptr-eq` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` error: use `std::ptr::eq` when comparing raw pointers --> $DIR/ptr_eq.rs:20:13 diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr index fd45224ca06..e9905384679 100644 --- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr +++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr @@ -5,6 +5,7 @@ LL | let _ = ptr.offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` | = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_offset_with_cast)]` error: use of `wrapping_offset` with a `usize` casted to an `isize` --> $DIR/ptr_offset_with_cast.rs:16:17 diff --git a/src/tools/clippy/tests/ui/pub_use.stderr b/src/tools/clippy/tests/ui/pub_use.stderr index ba4ee732c05..78157273664 100644 --- a/src/tools/clippy/tests/ui/pub_use.stderr +++ b/src/tools/clippy/tests/ui/pub_use.stderr @@ -6,6 +6,7 @@ LL | pub use inner::Test; | = help: move the exported item to a public module instead = note: `-D clippy::pub-use` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pub_use)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/pub_with_shorthand.stderr b/src/tools/clippy/tests/ui/pub_with_shorthand.stderr index 323b5a23b24..423b0508092 100644 --- a/src/tools/clippy/tests/ui/pub_with_shorthand.stderr +++ b/src/tools/clippy/tests/ui/pub_with_shorthand.stderr @@ -5,6 +5,7 @@ LL | pub(self) fn a() {} | ^^^^^^^^^ help: add it: `pub(in self)` | = note: `-D clippy::pub-with-shorthand` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pub_with_shorthand)]` error: usage of `pub` without `in` --> $DIR/pub_with_shorthand.rs:19:5 diff --git a/src/tools/clippy/tests/ui/pub_without_shorthand.stderr b/src/tools/clippy/tests/ui/pub_without_shorthand.stderr index a18c9bf8934..4fb11cb3d4a 100644 --- a/src/tools/clippy/tests/ui/pub_without_shorthand.stderr +++ b/src/tools/clippy/tests/ui/pub_without_shorthand.stderr @@ -5,6 +5,7 @@ LL | pub(in self) fn b() {} | ^^^^^^^^^^^^ help: remove it: `pub(self)` | = note: `-D clippy::pub-without-shorthand` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pub_without_shorthand)]` error: usage of `pub` with `in` --> $DIR/pub_without_shorthand.rs:18:5 diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 5dc62fadd8d..7b7b85d08e6 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ help: replace it with: `a?;` | = note: `-D clippy::question-mark` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::question_mark)]` error: this block may be rewritten with the `?` operator --> $DIR/question_mark.rs:52:9 diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr index 8b5fcbcdbfd..a3f440de80a 100644 --- a/src/tools/clippy/tests/ui/question_mark_used.stderr +++ b/src/tools/clippy/tests/ui/question_mark_used.stderr @@ -6,6 +6,7 @@ LL | other_function()?; | = help: consider using a custom macro or match expression = note: `-D clippy::question-mark-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::question_mark_used)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/range.stderr b/src/tools/clippy/tests/ui/range.stderr index ac83b67fde3..9f174307b82 100644 --- a/src/tools/clippy/tests/ui/range.stderr +++ b/src/tools/clippy/tests/ui/range.stderr @@ -5,6 +5,7 @@ LL | let _x = v1.iter().zip(0..v1.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::range-zip-with-len` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::range_zip_with_len)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr index ea34023a466..349adea2193 100644 --- a/src/tools/clippy/tests/ui/range_contains.stderr +++ b/src/tools/clippy/tests/ui/range_contains.stderr @@ -5,6 +5,7 @@ LL | x >= 8 && x < 12; | ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)` | = note: `-D clippy::manual-range-contains` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_range_contains)]` error: manual `Range::contains` implementation --> $DIR/range_contains.rs:14:5 diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr index f92826fb753..c5c9b145db8 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr @@ -5,6 +5,7 @@ LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` | = note: `-D clippy::range-plus-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::range_plus_one)]` error: an inclusive range would be more readable --> $DIR/range_plus_minus_one.rs:32:14 @@ -31,6 +32,7 @@ LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` | = note: `-D clippy::range-minus-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]` error: an exclusive range would be more readable --> $DIR/range_plus_minus_one.rs:46:13 diff --git a/src/tools/clippy/tests/ui/rc_buffer.stderr b/src/tools/clippy/tests/ui/rc_buffer.stderr index d78e39a010d..04080326ae0 100644 --- a/src/tools/clippy/tests/ui/rc_buffer.stderr +++ b/src/tools/clippy/tests/ui/rc_buffer.stderr @@ -5,6 +5,7 @@ LL | bad1: Rc<String>, | ^^^^^^^^^^ help: try: `Rc<str>` | = note: `-D clippy::rc-buffer` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rc_buffer)]` error: usage of `Rc<T>` when T is a buffer type --> $DIR/rc_buffer.rs:12:11 diff --git a/src/tools/clippy/tests/ui/rc_buffer_arc.stderr b/src/tools/clippy/tests/ui/rc_buffer_arc.stderr index 70d4381151a..52522dd725f 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_arc.stderr +++ b/src/tools/clippy/tests/ui/rc_buffer_arc.stderr @@ -5,6 +5,7 @@ LL | bad1: Arc<String>, | ^^^^^^^^^^^ help: try: `Arc<str>` | = note: `-D clippy::rc-buffer` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rc_buffer)]` error: usage of `Arc<T>` when T is a buffer type --> $DIR/rc_buffer_arc.rs:11:11 diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr index 87f7ed56cd3..5dc4b5a10e5 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr @@ -6,6 +6,7 @@ LL | let v = vec![Arc::new("x".to_string()); 2]; | = note: each element will point to the same `Arc` instance = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rc_clone_in_vec_init)]` help: consider initializing each `Arc` element individually | LL ~ let v = { diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr index 3fa187f0b81..e6bc6f68b3e 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr @@ -6,6 +6,7 @@ LL | let v = vec![Rc::new("x".to_string()); 2]; | = note: each element will point to the same `Rc` instance = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rc_clone_in_vec_init)]` help: consider initializing each `Rc` element individually | LL ~ let v = { diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr index 9b60c22c281..25d7dae72da 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr @@ -6,6 +6,7 @@ LL | let v = vec![SyncWeak::<u32>::new(); 2]; | = note: each element will point to the same `Weak` instance = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rc_clone_in_vec_init)]` help: consider initializing each `Weak` element individually | LL ~ let v = { diff --git a/src/tools/clippy/tests/ui/rc_mutex.stderr b/src/tools/clippy/tests/ui/rc_mutex.stderr index e21337b0f2e..50922fb67e4 100644 --- a/src/tools/clippy/tests/ui/rc_mutex.stderr +++ b/src/tools/clippy/tests/ui/rc_mutex.stderr @@ -6,6 +6,7 @@ LL | foo: Rc<Mutex<i32>>, | = help: consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead = note: `-D clippy::rc-mutex` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rc_mutex)]` error: usage of `Rc<Mutex<_>>` --> $DIR/rc_mutex.rs:27:18 diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.stderr b/src/tools/clippy/tests/ui/read_line_without_trim.stderr index a7751eb68d8..8d46e0f7907 100644 --- a/src/tools/clippy/tests/ui/read_line_without_trim.stderr +++ b/src/tools/clippy/tests/ui/read_line_without_trim.stderr @@ -12,6 +12,7 @@ note: call to `.read_line()` here, which leaves a trailing newline character in LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::read-line-without-trim` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::read_line_without_trim)]` error: calling `.parse()` without trimming the trailing newline character --> $DIR/read_line_without_trim.rs:16:20 diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr index b80a614eceb..523ecb2948d 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr @@ -5,6 +5,7 @@ LL | f.read_exact(&mut data).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();` | = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]` error: reading zero byte data to `Vec` --> $DIR/read_zero_byte_vec.rs:27:5 diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.stderr b/src/tools/clippy/tests/ui/readonly_write_lock.stderr index ca754e5c8f2..b4a093ce9c9 100644 --- a/src/tools/clippy/tests/ui/readonly_write_lock.stderr +++ b/src/tools/clippy/tests/ui/readonly_write_lock.stderr @@ -5,6 +5,7 @@ LL | let writer = lock.write().unwrap(); | ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()` | = note: `-D clippy::readonly-write-lock` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::readonly_write_lock)]` error: this write lock is used only for reading --> $DIR/readonly_write_lock.rs:23:22 diff --git a/src/tools/clippy/tests/ui/recursive_format_impl.stderr b/src/tools/clippy/tests/ui/recursive_format_impl.stderr index c80e90ba61b..adb16f44a99 100644 --- a/src/tools/clippy/tests/ui/recursive_format_impl.stderr +++ b/src/tools/clippy/tests/ui/recursive_format_impl.stderr @@ -5,6 +5,7 @@ LL | write!(f, "{}", self.to_string()) | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::recursive-format-impl` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::recursive_format_impl)]` error: using `self` as `Display` in `impl Display` will cause infinite recursion --> $DIR/recursive_format_impl.rs:77:9 diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr index 233e3eb4289..d72f6b202ec 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation.stderr +++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr @@ -7,6 +7,7 @@ LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {} = note: `Rc<T>` is already on the heap, `Box<Rc<T>>` makes an extra allocation = help: consider using just `Box<T>` or `Rc<T>` = note: `-D clippy::redundant-allocation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]` error: usage of `Box<Arc<T>>` --> $DIR/redundant_allocation.rs:20:30 diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr index 2e6e078b24b..603600f3022 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr @@ -6,6 +6,7 @@ LL | pub fn box_test1<T>(foo: Box<&T>) {} | = note: `&T` is already a pointer, `Box<&T>` allocates a pointer on the heap = note: `-D clippy::redundant-allocation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]` error: usage of `Box<&MyStruct>` --> $DIR/redundant_allocation_fixable.rs:25:27 diff --git a/src/tools/clippy/tests/ui/redundant_async_block.stderr b/src/tools/clippy/tests/ui/redundant_async_block.stderr index 0ebd4d2cece..adb44d7a62e 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.stderr +++ b/src/tools/clippy/tests/ui/redundant_async_block.stderr @@ -5,6 +5,7 @@ LL | let x = async { f.await }; | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` | = note: `-D clippy::redundant-async-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_async_block)]` error: this async expression only awaits a single future --> $DIR/redundant_async_block.rs:20:16 diff --git a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr index 008db304daf..3a44636fc78 100644 --- a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr +++ b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr @@ -5,6 +5,7 @@ LL | if let [a @ ..] = [()] {} | ^^^^^^^^ help: this is better represented with just the binding: `a` | = note: `-D clippy::redundant-at-rest-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_at_rest_pattern)]` error: using a rest pattern to bind an entire slice to a local --> $DIR/redundant_at_rest_pattern.rs:10:12 diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index a1c09d2b3c7..4115fcf2122 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -10,6 +10,7 @@ note: this value is dropped without further use LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::redundant-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone --> $DIR/redundant_clone.rs:18:15 diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr index 4a2ce175b5c..be7a981dc27 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr @@ -5,6 +5,7 @@ LL | let mut k = (|m| m + 1)(i); | ^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: try not to call a closure in the expression where it is declared --> $DIR/redundant_closure_call_early.rs:14:9 diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr index a285420ea8f..a7cdb43693f 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr @@ -5,6 +5,7 @@ LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: try not to call a closure in the expression where it is declared --> $DIR/redundant_closure_call_fixable.rs:17:13 diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr index 4a0fe95d573..a89bfc7703d 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr @@ -5,6 +5,7 @@ LL | i = redun_closure(); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: closure called just once immediately after it was declared --> $DIR/redundant_closure_call_late.rs:22:5 diff --git a/src/tools/clippy/tests/ui/redundant_else.stderr b/src/tools/clippy/tests/ui/redundant_else.stderr index d6759422e95..af33e05a608 100644 --- a/src/tools/clippy/tests/ui/redundant_else.stderr +++ b/src/tools/clippy/tests/ui/redundant_else.stderr @@ -10,6 +10,7 @@ LL | | } | = help: remove the `else` block and move the contents out = note: `-D clippy::redundant-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_else)]` error: redundant else block --> $DIR/redundant_else.rs:18:16 diff --git a/src/tools/clippy/tests/ui/redundant_field_names.stderr b/src/tools/clippy/tests/ui/redundant_field_names.stderr index 8bcf33007db..5fee60b8ea4 100644 --- a/src/tools/clippy/tests/ui/redundant_field_names.stderr +++ b/src/tools/clippy/tests/ui/redundant_field_names.stderr @@ -5,6 +5,7 @@ LL | gender: gender, | ^^^^^^^^^^^^^^ help: replace it with: `gender` | = note: `-D clippy::redundant-field-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_field_names)]` error: redundant field names in struct initialization --> $DIR/redundant_field_names.rs:34:9 diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr index 50077234382..0a45a6d7619 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.stderr +++ b/src/tools/clippy/tests/ui/redundant_guards.stderr @@ -5,6 +5,7 @@ LL | C(x, y) if let 1 = y => .., | ^^^^^^^^^ | = note: `-D clippy::redundant-guards` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_guards)]` help: try | LL - C(x, y) if let 1 = y => .., diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr index 587de057524..13b872e9576 100644 --- a/src/tools/clippy/tests/ui/redundant_locals.stderr +++ b/src/tools/clippy/tests/ui/redundant_locals.stderr @@ -8,6 +8,7 @@ LL | let x = x; | = help: remove the redefinition of `x` = note: `-D clippy::redundant-locals` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]` error: redundant redefinition of a binding --> $DIR/redundant_locals.rs:16:9 diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr index 636d1a292ac..28f0244b9e8 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -7,6 +7,7 @@ LL | if let Ok(_) = m.lock() {} = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:16:12 diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr index f5f5d268a62..d36129a2bee 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -5,6 +5,7 @@ LL | if let V4(_) = &ipaddr {} | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:17:12 diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr index 73b0353ce34..fdf395d8286 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -5,6 +5,7 @@ LL | matches!(maybe_some, None if !boolean) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:18:13 diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr index 6c4603bcf3d..c010c3c4437 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr @@ -5,6 +5,7 @@ LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:17:12 diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr index 4467e8e8107..19e7f82298e 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr @@ -5,6 +5,7 @@ LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try: `if result.is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:17:12 diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr index f8c7d7a9e69..5d7744aa864 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr @@ -7,6 +7,7 @@ LL | pub(crate) fn g() {} // private due to m1 | help: consider using: `pub` | = note: `-D clippy::redundant-pub-crate` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_pub_crate)]` error: pub(crate) function inside private module --> $DIR/redundant_pub_crate.rs:11:9 diff --git a/src/tools/clippy/tests/ui/redundant_slicing.stderr b/src/tools/clippy/tests/ui/redundant_slicing.stderr index e0db72765a8..05287c882f7 100644 --- a/src/tools/clippy/tests/ui/redundant_slicing.stderr +++ b/src/tools/clippy/tests/ui/redundant_slicing.stderr @@ -5,6 +5,7 @@ LL | let _ = &slice[..]; // Redundant slice | ^^^^^^^^^^ help: use the original value instead: `slice` | = note: `-D clippy::redundant-slicing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_slicing)]` error: redundant slicing of the whole range --> $DIR/redundant_slicing.rs:12:13 diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr index 3e344fc67f9..26f50345351 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr @@ -5,6 +5,7 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removi | -^^^^^^^---- help: consider removing `'static`: `&str` | = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_static_lifetimes)]` error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:10:21 diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr index 297f505d968..bf4d211200f 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr @@ -5,6 +5,7 @@ LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]` | = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_static_lifetimes)]` error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:4:30 diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr index 927761c7437..d1f26f1832e 100644 --- a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr +++ b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr @@ -5,6 +5,7 @@ LL | let v: u32 = self.return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-type-annotations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_type_annotations)]` error: redundant type annotation --> $DIR/redundant_type_annotations.rs:84:9 diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr index 2505d7d500b..6e8b43a3e52 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr @@ -5,6 +5,7 @@ LL | Some(ref x) => x, | ^^^^^ | = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_binding_to_reference)]` help: try | LL | Some(x) => &x, diff --git a/src/tools/clippy/tests/ui/ref_option_ref.stderr b/src/tools/clippy/tests/ui/ref_option_ref.stderr index 430dd9c0e8d..6a28a68dc2b 100644 --- a/src/tools/clippy/tests/ui/ref_option_ref.stderr +++ b/src/tools/clippy/tests/ui/ref_option_ref.stderr @@ -5,6 +5,7 @@ LL | static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD); | ^^^^^^^^^^^^^ help: try: `Option<&i32>` | = note: `-D clippy::ref-option-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_option_ref)]` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` --> $DIR/ref_option_ref.rs:14:18 diff --git a/src/tools/clippy/tests/ui/ref_patterns.stderr b/src/tools/clippy/tests/ui/ref_patterns.stderr index 5883a7883e6..74892bac6e4 100644 --- a/src/tools/clippy/tests/ui/ref_patterns.stderr +++ b/src/tools/clippy/tests/ui/ref_patterns.stderr @@ -6,6 +6,7 @@ LL | Some(ref opt) => {}, | = help: consider using `&` for clarity instead = note: `-D clippy::ref-patterns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_patterns)]` error: usage of ref pattern --> $DIR/ref_patterns.rs:15:9 diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr index ed5aa29e079..91f90157e68 100644 --- a/src/tools/clippy/tests/ui/regex.stderr +++ b/src/tools/clippy/tests/ui/regex.stderr @@ -6,6 +6,7 @@ LL | let pipe_in_wrong_position = Regex::new("|"); | = help: the regex is unlikely to be useful as it is = note: `-D clippy::trivial-regex` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::trivial_regex)]` error: trivial regex --> $DIR/regex.rs:20:60 @@ -22,6 +23,7 @@ LL | let wrong_char_ranice = Regex::new("[z-a]"); | ^^^ | = note: `-D clippy::invalid-regex` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::invalid_regex)]` error: regex syntax error: invalid character class range, the start must be <= the end --> $DIR/regex.rs:25:37 diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 2b26af16bad..d98fc7b30db 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -5,6 +5,7 @@ LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` | = note: `-D renamed-and-removed-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` --> $DIR/rename.rs:53:9 diff --git a/src/tools/clippy/tests/ui/repeat_once.stderr b/src/tools/clippy/tests/ui/repeat_once.stderr index ae5258d4c2f..89572939078 100644 --- a/src/tools/clippy/tests/ui/repeat_once.stderr +++ b/src/tools/clippy/tests/ui/repeat_once.stderr @@ -5,6 +5,7 @@ LL | let a = [1; 5].repeat(1); | ^^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `[1; 5].to_vec()` | = note: `-D clippy::repeat-once` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeat_once)]` error: calling `repeat(1)` on slice --> $DIR/repeat_once.rs:10:13 diff --git a/src/tools/clippy/tests/ui/repl_uninit.stderr b/src/tools/clippy/tests/ui/repl_uninit.stderr index 6bbefcadb86..c82f29adb5a 100644 --- a/src/tools/clippy/tests/ui/repl_uninit.stderr +++ b/src/tools/clippy/tests/ui/repl_uninit.stderr @@ -5,6 +5,7 @@ LL | let taken_v = mem::replace(&mut v, mem::uninitialized()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)` | = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_uninit)]` error: replacing with `mem::MaybeUninit::uninit().assume_init()` --> $DIR/repl_uninit.rs:23:23 diff --git a/src/tools/clippy/tests/ui/reserve_after_initialization.stderr b/src/tools/clippy/tests/ui/reserve_after_initialization.stderr index 4a6164d8ebc..a9103389076 100644 --- a/src/tools/clippy/tests/ui/reserve_after_initialization.stderr +++ b/src/tools/clippy/tests/ui/reserve_after_initialization.stderr @@ -6,6 +6,7 @@ LL | | v1.reserve(10); | |___________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `let mut v1: Vec<usize> = Vec::with_capacity(10);` | = note: `-D clippy::reserve-after-initialization` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::reserve_after_initialization)]` error: call to `reserve` immediately after creation --> $DIR/reserve_after_initialization.rs:17:5 diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr index f8e4087823d..2c221b4dbb2 100644 --- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr +++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr @@ -6,6 +6,7 @@ LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint | = help: consider removing `..` from this binding = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]` error: unnecessary use of `..` pattern in struct binding. All fields were already bound --> $DIR/rest_pat_in_fully_bound_structs.rs:24:9 diff --git a/src/tools/clippy/tests/ui/result_large_err.stderr b/src/tools/clippy/tests/ui/result_large_err.stderr index c51531f55db..d42dd6600a3 100644 --- a/src/tools/clippy/tests/ui/result_large_err.stderr +++ b/src/tools/clippy/tests/ui/result_large_err.stderr @@ -6,6 +6,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> { | = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` = note: `-D clippy::result-large-err` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_large_err)]` error: the `Err`-variant returned from this function is very large --> $DIR/result_large_err.rs:20:21 diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr index 2b057042aee..9396ea4c064 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr @@ -5,6 +5,7 @@ LL | let _ = opt.map_or(None, Some); | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` | = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr index 5def0fe4173..42ee273c2bd 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr @@ -7,6 +7,7 @@ LL | x.field.map(do_nothing); | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }` | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_map_unit_fn)]` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:36:5 diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr index ba17e22d0b3..ccf9bfb947c 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr @@ -7,6 +7,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | help: try: `if let Ok(value) = x.field { ... }` | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_map_unit_fn)]` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:27:5 diff --git a/src/tools/clippy/tests/ui/result_unit_error.stderr b/src/tools/clippy/tests/ui/result_unit_error.stderr index 252c72481f5..72208f53916 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.stderr +++ b/src/tools/clippy/tests/ui/result_unit_error.stderr @@ -6,6 +6,7 @@ LL | pub fn returns_unit_error() -> Result<u32, ()> { | = help: use a custom `Error` type instead = note: `-D clippy::result-unit-err` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::result_unit_err)]` error: this returns a `Result<_, ()>` --> $DIR/result_unit_error.rs:13:5 diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr index adfd6564d99..b3e41470d7b 100644 --- a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr +++ b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr @@ -6,6 +6,7 @@ LL | fn what(&self) -> Self; | = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type = note: `-D clippy::return-self-not-must-use` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::return_self_not_must_use)]` error: missing `#[must_use]` attribute on a method returning `Self` --> $DIR/return_self_not_must_use.rs:19:5 diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr index 2d1bfe62c92..92fbac8e30c 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr @@ -5,6 +5,7 @@ LL | (42..=21).for_each(|x| println!("{}", x)); | ^^^^^^^^^ | = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]` help: consider using the following if you are attempting to iterate over this range in reverse | LL | (21..=42).rev().for_each(|x| println!("{}", x)); diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr index a135da488ff..843d6a36d9b 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr @@ -5,6 +5,7 @@ LL | for i in 10..0 { | ^^^^^ | = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]` help: consider using the following if you are attempting to iterate over this range in reverse | LL | for i in (0..10).rev() { diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr index f6446317495..73165e091cb 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr @@ -5,6 +5,7 @@ LL | for i in 5..5 { | ^^^^ | = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]` error: this range is empty so it will yield no values --> $DIR/reversed_empty_ranges_loops_unfixable.rs:11:14 diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr index d32301742d3..e3dc96dfb9c 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr @@ -5,6 +5,7 @@ LL | let _ = &arr[3usize..=1usize]; | ^^^^^^^^^^^^^^^ | = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]` error: this range is reversed and using it to index a slice will panic at run-time --> $DIR/reversed_empty_ranges_unfixable.rs:11:18 diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr index 8e876e914ce..f519be46369 100644 --- a/src/tools/clippy/tests/ui/same_item_push.stderr +++ b/src/tools/clippy/tests/ui/same_item_push.stderr @@ -6,6 +6,7 @@ LL | vec.push(item); | = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) = note: `-D clippy::same-item-push` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::same_item_push)]` error: it looks like the same item is being pushed into this Vec --> $DIR/same_item_push.rs:30:9 diff --git a/src/tools/clippy/tests/ui/same_name_method.stderr b/src/tools/clippy/tests/ui/same_name_method.stderr index b31d2537ead..3c5c4a53ad1 100644 --- a/src/tools/clippy/tests/ui/same_name_method.stderr +++ b/src/tools/clippy/tests/ui/same_name_method.stderr @@ -10,6 +10,7 @@ note: existing `foo` defined here LL | fn foo() {} | ^^^^^^^^^^^ = note: `-D clippy::same-name-method` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::same_name_method)]` error: method's name is the same as an existing method in a trait --> $DIR/same_name_method.rs:36:13 diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr index 7eff614d17c..a7a47447f61 100644 --- a/src/tools/clippy/tests/ui/search_is_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -10,6 +10,7 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `position` --> $DIR/search_is_some.rs:21:13 diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr index 82b81f29060..f33b0430912 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr @@ -5,6 +5,7 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_none()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_none.rs:10:13 diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr index 5466d0cb9f0..e878e62de07 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr @@ -5,6 +5,7 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable_some.rs:10:20 diff --git a/src/tools/clippy/tests/ui/seek_from_current.stderr b/src/tools/clippy/tests/ui/seek_from_current.stderr index 2549a26b23c..42eb342c10a 100644 --- a/src/tools/clippy/tests/ui/seek_from_current.stderr +++ b/src/tools/clippy/tests/ui/seek_from_current.stderr @@ -5,6 +5,7 @@ LL | f.seek(SeekFrom::Current(0))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `f.stream_position()` | = note: `-D clippy::seek-from-current` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::seek_from_current)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr index 47cddfe7ea6..05c11cf7f8c 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -5,6 +5,7 @@ LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` | = note: `-D clippy::seek-to-start-instead-of-rewind` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::seek_to_start_instead_of_rewind)]` error: used `seek` to go to the start of the stream --> $DIR/seek_to_start_instead_of_rewind.rs:57:7 diff --git a/src/tools/clippy/tests/ui/self_assignment.stderr b/src/tools/clippy/tests/ui/self_assignment.stderr index ecb62f96a93..4612f8f8244 100644 --- a/src/tools/clippy/tests/ui/self_assignment.stderr +++ b/src/tools/clippy/tests/ui/self_assignment.stderr @@ -5,6 +5,7 @@ LL | a = a; | ^^^^^ | = note: `-D clippy::self-assignment` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::self_assignment)]` error: self-assignment of `*b` to `*b` --> $DIR/self_assignment.rs:16:5 diff --git a/src/tools/clippy/tests/ui/self_named_constructors.stderr b/src/tools/clippy/tests/ui/self_named_constructors.stderr index 2024d86f91f..f299b860d47 100644 --- a/src/tools/clippy/tests/ui/self_named_constructors.stderr +++ b/src/tools/clippy/tests/ui/self_named_constructors.stderr @@ -9,6 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::self-named-constructors` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::self_named_constructors)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr index 8d9a67585cf..66373a13c56 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr @@ -5,6 +5,7 @@ LL | println!("Hello") | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` | = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_if_nothing_returned)]` error: consider adding a `;` to the last statement for consistent formatting --> $DIR/semicolon_if_nothing_returned.rs:12:5 diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr index 825c7142fdf..1bfc1f24c43 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr @@ -5,6 +5,7 @@ LL | { unit_fn_block() }; | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_inside_block)]` help: put the `;` here | LL - { unit_fn_block() }; diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr index 53c6bbd825c..427271fca64 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.stderr +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr @@ -5,6 +5,7 @@ LL | { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_outside_block)]` help: put the `;` here | LL - { unit_fn_block(); } diff --git a/src/tools/clippy/tests/ui/serde.stderr b/src/tools/clippy/tests/ui/serde.stderr index a0d8217010e..e5d64e27164 100644 --- a/src/tools/clippy/tests/ui/serde.stderr +++ b/src/tools/clippy/tests/ui/serde.stderr @@ -11,6 +11,7 @@ LL | | } | |_____^ | = note: `-D clippy::serde-api-misuse` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::serde_api_misuse)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr index 88b02f53be1..26ace287b1f 100644 --- a/src/tools/clippy/tests/ui/shadow.stderr +++ b/src/tools/clippy/tests/ui/shadow.stderr @@ -10,6 +10,7 @@ note: previous binding is here LL | let x = 1; | ^ = note: `-D clippy::shadow-same` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::shadow_same)]` error: `mut x` is shadowed by itself in `&x` --> $DIR/shadow.rs:25:13 @@ -59,6 +60,7 @@ note: previous binding is here LL | let x = ([[0]], ()); | ^ = note: `-D clippy::shadow-reuse` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::shadow_reuse)]` error: `x` is shadowed --> $DIR/shadow.rs:33:9 @@ -156,6 +158,7 @@ note: previous binding is here LL | let x = 1; | ^ = note: `-D clippy::shadow-unrelated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::shadow_unrelated)]` error: `x` shadows a previous, unrelated binding --> $DIR/shadow.rs:60:13 diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.stderr b/src/tools/clippy/tests/ui/short_circuit_statement.stderr index 1f7adea4a8b..dbdf44dfcbd 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.stderr +++ b/src/tools/clippy/tests/ui/short_circuit_statement.stderr @@ -5,6 +5,7 @@ LL | f() && g(); | ^^^^^^^^^^^ help: replace it with: `if f() { g(); }` | = note: `-D clippy::short-circuit-statement` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::short_circuit_statement)]` error: boolean short circuit operator in statement may be clearer using an explicit test --> $DIR/short_circuit_statement.rs:6:5 diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr index 7ad00d14d0c..c9894eec53a 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr @@ -9,6 +9,7 @@ LL | | } | = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name = note: `-D clippy::should-implement-trait` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]` error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` --> $DIR/method_list_1.rs:30:5 diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr index 0073c899813..79afddea247 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr @@ -9,6 +9,7 @@ LL | | } | = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name = note: `-D clippy::should-implement-trait` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]` error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` --> $DIR/method_list_2.rs:31:5 @@ -174,6 +175,7 @@ LL | pub fn hash(&self, state: &mut T) { | = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index 6ead59b0725..05bfda5475d 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -12,6 +12,7 @@ LL | }; | = note: this might lead to deadlocks or other unexpected behavior = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::significant_drop_in_scrutinee)]` help: try moving the temporary above the match | LL ~ let value = mutex.lock().unwrap().foo(); diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr index ff6f5907ebd..6572d996931 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr @@ -16,6 +16,7 @@ LL | | } | = note: this might lead to unnecessary resource contention = note: `-D clippy::significant-drop-tightening` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::significant_drop_tightening)]` help: drop the temporary after the end of its last usage | LL ~ let _ = *lock; diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr index 059e26d5891..011dbe679c0 100644 --- a/src/tools/clippy/tests/ui/similar_names.stderr +++ b/src/tools/clippy/tests/ui/similar_names.stderr @@ -10,6 +10,7 @@ note: existing binding defined here LL | let apple: i32; | ^^^^^ = note: `-D clippy::similar-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::similar_names)]` error: binding's name is too similar to existing binding --> $DIR/similar_names.rs:24:9 diff --git a/src/tools/clippy/tests/ui/single_call_fn.stderr b/src/tools/clippy/tests/ui/single_call_fn.stderr index 9ef8c487844..4acb383c408 100644 --- a/src/tools/clippy/tests/ui/single_call_fn.stderr +++ b/src/tools/clippy/tests/ui/single_call_fn.stderr @@ -14,6 +14,7 @@ help: used here LL | c(); | ^ = note: `-D clippy::single-call-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_call_fn)]` error: this function is only used once --> $DIR/single_call_fn.rs:12:1 diff --git a/src/tools/clippy/tests/ui/single_char_add_str.stderr b/src/tools/clippy/tests/ui/single_char_add_str.stderr index cea9ba7235d..a6f2b3e037b 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.stderr +++ b/src/tools/clippy/tests/ui/single_char_add_str.stderr @@ -5,6 +5,7 @@ LL | string.push_str("R"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` | = note: `-D clippy::single-char-add-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_char_add_str)]` error: calling `push_str()` using a single-character string literal --> $DIR/single_char_add_str.rs:15:5 diff --git a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr index 19bea0ae0c2..2cdfd61358e 100644 --- a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr +++ b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr @@ -6,6 +6,7 @@ LL | struct DiagnosticCtx<'a, 'b> | = help: use a more informative name = note: `-D clippy::single-char-lifetime-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_char_lifetime_names)]` error: single-character lifetime names are likely uninformative --> $DIR/single_char_lifetime_names.rs:5:26 diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index f11ab12edee..6e57ab3489f 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -5,6 +5,7 @@ LL | x.split("x"); | ^^^ help: try using a `char` instead: `'x'` | = note: `-D clippy::single-char-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:13:13 diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.stderr b/src/tools/clippy/tests/ui/single_component_path_imports.stderr index 0bff108f86a..440d34002d7 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports.stderr @@ -5,6 +5,7 @@ LL | use regex; | ^^^^^^^^^^ help: remove it entirely | = note: `-D clippy::single-component-path-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_component_path_imports)]` error: this import is redundant --> $DIR/single_component_path_imports.rs:32:5 diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr index b2a0521f7d1..d65ab5620db 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr @@ -5,6 +5,7 @@ LL | use regex; | ^^^^^^^^^^ help: remove it entirely | = note: `-D clippy::single-component-path-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_component_path_imports)]` error: this import is redundant --> $DIR/single_component_path_imports_nested_first.rs:17:10 diff --git a/src/tools/clippy/tests/ui/single_element_loop.stderr b/src/tools/clippy/tests/ui/single_element_loop.stderr index 1d89bf55387..603dd7406e4 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.stderr +++ b/src/tools/clippy/tests/ui/single_element_loop.stderr @@ -7,6 +7,7 @@ LL | | } | |_____^ | = note: `-D clippy::single-element-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_element_loop)]` help: try | LL ~ { diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr index 76f7e789589..d4b86599521 100644 --- a/src/tools/clippy/tests/ui/single_match.stderr +++ b/src/tools/clippy/tests/ui/single_match.stderr @@ -10,6 +10,7 @@ LL | | }; | |_____^ | = note: `-D clippy::single-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_match)]` help: try | LL ~ if let Some(y) = x { diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr index e85d51de6a1..3b4b1332c40 100644 --- a/src/tools/clippy/tests/ui/single_match_else.stderr +++ b/src/tools/clippy/tests/ui/single_match_else.stderr @@ -12,6 +12,7 @@ LL | | }; | |_____^ | = note: `-D clippy::single-match-else` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_match_else)]` help: try | LL ~ let _ = if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { diff --git a/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr b/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr index 1b347f4ae97..e83e49af676 100644 --- a/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr +++ b/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr @@ -5,6 +5,7 @@ LL | [0..200]; | ^^^^^^^^ | = note: `-D clippy::single-range-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_range_in_vec_init)]` help: if you wanted a `Vec` that contains the entire range, try | LL | (0..200).collect::<std::vec::Vec<i32>>(); diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr index 0c31c3a1f4b..47f9632b8d1 100644 --- a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr +++ b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr @@ -6,6 +6,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>( | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::size_of_in_element_count)]` error: found a count of bytes instead of a count of elements of `T` --> $DIR/expressions.rs:19:62 diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr index 4901d11736d..aba4c800e44 100644 --- a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr +++ b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr @@ -6,6 +6,7 @@ LL | unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of: | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::size_of_in_element_count)]` error: found a count of bytes instead of a count of elements of `T` --> $DIR/functions.rs:20:62 diff --git a/src/tools/clippy/tests/ui/size_of_ref.stderr b/src/tools/clippy/tests/ui/size_of_ref.stderr index c7a1758825c..e239c5810c9 100644 --- a/src/tools/clippy/tests/ui/size_of_ref.stderr +++ b/src/tools/clippy/tests/ui/size_of_ref.stderr @@ -6,6 +6,7 @@ LL | size_of_val(&&x); | = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type = note: `-D clippy::size-of-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::size_of_ref)]` error: argument to `std::mem::size_of_val()` is a reference to a reference --> $DIR/size_of_ref.rs:15:5 diff --git a/src/tools/clippy/tests/ui/skip_while_next.stderr b/src/tools/clippy/tests/ui/skip_while_next.stderr index 7308ab4e55c..3c33af3a160 100644 --- a/src/tools/clippy/tests/ui/skip_while_next.stderr +++ b/src/tools/clippy/tests/ui/skip_while_next.stderr @@ -6,6 +6,7 @@ LL | let _ = v.iter().skip_while(|&x| *x < 0).next(); | = help: this is more succinctly expressed by calling `.find(!<p>)` instead = note: `-D clippy::skip-while-next` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::skip_while_next)]` error: called `skip_while(<p>).next()` on an `Iterator` --> $DIR/skip_while_next.rs:17:13 diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr index 4800e6e4418..f4501551656 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr @@ -7,6 +7,7 @@ LL | vec1.extend(repeat(0).take(len)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::slow-vector-initialization` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]` error: slow zero-filling initialization --> $DIR/slow_vector_initialization.rs:20:5 @@ -103,6 +104,7 @@ LL | fn do_stuff(vec: &mut [u8]) {} | ^^^^^^^^^ help: consider changing to: `&[u8]` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr index 1432fdcff77..b6650332833 100644 --- a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr +++ b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr @@ -6,6 +6,7 @@ LL | vec.sort(); | = note: an unstable sort typically performs faster without any observable difference for this data type = note: `-D clippy::stable-sort-primitive` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::stable_sort_primitive)]` error: used `sort` on primitive type `bool` --> $DIR/stable_sort_primitive.rs:9:5 diff --git a/src/tools/clippy/tests/ui/starts_ends_with.stderr b/src/tools/clippy/tests/ui/starts_ends_with.stderr index 48d561bc4b8..c4c547949a3 100644 --- a/src/tools/clippy/tests/ui/starts_ends_with.stderr +++ b/src/tools/clippy/tests/ui/starts_ends_with.stderr @@ -5,6 +5,7 @@ LL | "".chars().next() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')` | = note: `-D clippy::chars-next-cmp` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::chars_next_cmp)]` error: you should use the `starts_with` method --> $DIR/starts_ends_with.rs:8:5 @@ -37,6 +38,7 @@ LL | if s.chars().next_back().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` | = note: `-D clippy::chars-last-cmp` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::chars_last_cmp)]` error: you should use the `ends_with` method --> $DIR/starts_ends_with.rs:25:8 diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr index f2db81e5163..7435d716157 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr +++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr @@ -6,6 +6,7 @@ LL | use std::hash::Hasher; | = help: consider importing the item from `core` = note: `-D clippy::std-instead-of-core` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` error: used import from `std` instead of `core` --> $DIR/std_instead_of_core.rs:12:9 @@ -79,6 +80,7 @@ LL | use std::vec; | = help: consider importing the item from `alloc` = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` error: used import from `std` instead of `alloc` --> $DIR/std_instead_of_core.rs:49:9 @@ -96,6 +98,7 @@ LL | use alloc::slice::from_ref; | = help: consider importing the item from `core` = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/str_to_string.stderr b/src/tools/clippy/tests/ui/str_to_string.stderr index 25af1d37663..203805eca5a 100644 --- a/src/tools/clippy/tests/ui/str_to_string.stderr +++ b/src/tools/clippy/tests/ui/str_to_string.stderr @@ -6,6 +6,7 @@ LL | let hello = "hello world".to_string(); | = help: consider using `.to_owned()` = note: `-D clippy::str-to-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::str_to_string)]` error: `to_string()` called on a `&str` --> $DIR/str_to_string.rs:7:5 diff --git a/src/tools/clippy/tests/ui/string_add.stderr b/src/tools/clippy/tests/ui/string_add.stderr index 3987641c75a..892753b9034 100644 --- a/src/tools/clippy/tests/ui/string_add.stderr +++ b/src/tools/clippy/tests/ui/string_add.stderr @@ -5,6 +5,7 @@ LL | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` | = note: `-D clippy::assign-op-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: you added something to a string. Consider using `String::push_str()` instead --> $DIR/string_add.rs:13:13 @@ -13,6 +14,7 @@ LL | x = x + "."; | ^^^^^^^ | = note: `-D clippy::string-add` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_add)]` error: you added something to a string. Consider using `String::push_str()` instead --> $DIR/string_add.rs:17:13 diff --git a/src/tools/clippy/tests/ui/string_add_assign.stderr b/src/tools/clippy/tests/ui/string_add_assign.stderr index d4b995519e3..7d37c98a8f9 100644 --- a/src/tools/clippy/tests/ui/string_add_assign.stderr +++ b/src/tools/clippy/tests/ui/string_add_assign.stderr @@ -5,6 +5,7 @@ LL | x = x + "."; | ^^^^^^^^^^^ | = note: `-D clippy::string-add-assign` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_add_assign)]` error: manual implementation of an assign operation --> $DIR/string_add_assign.rs:8:9 @@ -13,6 +14,7 @@ LL | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` | = note: `-D clippy::assign-op-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation --> $DIR/string_add_assign.rs:17:5 diff --git a/src/tools/clippy/tests/ui/string_extend.stderr b/src/tools/clippy/tests/ui/string_extend.stderr index 49ff4516db1..e063d87e37d 100644 --- a/src/tools/clippy/tests/ui/string_extend.stderr +++ b/src/tools/clippy/tests/ui/string_extend.stderr @@ -5,6 +5,7 @@ LL | s.extend(abc.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(abc)` | = note: `-D clippy::string-extend-chars` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_extend_chars)]` error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:19:5 diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr index 0fa4d59068f..cf5688a9782 100644 --- a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.stderr @@ -5,6 +5,7 @@ LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` | = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_from_utf8_as_bytes)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr index 73576f9f300..1c12cb8e56d 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr @@ -5,6 +5,7 @@ LL | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` | = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_lit_as_bytes)]` error: calling `as_bytes()` on a string literal --> $DIR/string_lit_as_bytes.rs:18:14 diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr index dac9a90b341..09c4f02eb06 100644 --- a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr +++ b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr @@ -5,6 +5,7 @@ LL | "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::string-lit-chars-any` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_lit_chars_any)]` help: use `matches!(...)` instead | LL | matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); diff --git a/src/tools/clippy/tests/ui/string_slice.stderr b/src/tools/clippy/tests/ui/string_slice.stderr index 94dad58cd97..e9e773aaf3a 100644 --- a/src/tools/clippy/tests/ui/string_slice.stderr +++ b/src/tools/clippy/tests/ui/string_slice.stderr @@ -5,6 +5,7 @@ LL | &"Ölkanne"[1..]; | ^^^^^^^^^^^^^^ | = note: `-D clippy::string-slice` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_slice)]` error: indexing into a string may panic if the index is within a UTF-8 character --> $DIR/string_slice.rs:9:6 diff --git a/src/tools/clippy/tests/ui/string_to_string.stderr b/src/tools/clippy/tests/ui/string_to_string.stderr index e304c3e346d..27a84431507 100644 --- a/src/tools/clippy/tests/ui/string_to_string.stderr +++ b/src/tools/clippy/tests/ui/string_to_string.stderr @@ -6,6 +6,7 @@ LL | let mut v = message.to_string(); | = help: consider using `.clone()` = note: `-D clippy::string-to-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::string_to_string)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr index 81881fbe3bd..6d8ad3981c0 100644 --- a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr +++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr @@ -5,6 +5,7 @@ LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.as_bytes().len()` | = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:17:13 diff --git a/src/tools/clippy/tests/ui/struct_excessive_bools.stderr b/src/tools/clippy/tests/ui/struct_excessive_bools.stderr index 05b2363eb56..5284949c2d2 100644 --- a/src/tools/clippy/tests/ui/struct_excessive_bools.stderr +++ b/src/tools/clippy/tests/ui/struct_excessive_bools.stderr @@ -12,6 +12,7 @@ LL | | } | = help: consider using a state machine or refactoring bools into two-variant enums = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::struct_excessive_bools)]` error: more than 3 bools in a struct --> $DIR/struct_excessive_bools.rs:39:5 diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr index 4a4be0712b2..3995c6eb5c4 100644 --- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr +++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr @@ -5,6 +5,7 @@ LL | Foo(self.0 - other.0) | ^ | = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_arithmetic_impl)]` error: suspicious use of `-` in `AddAssign` impl --> $DIR/suspicious_arithmetic_impl.rs:21:23 @@ -13,6 +14,7 @@ LL | *self = *self - other; | ^ | = note: `-D clippy::suspicious-op-assign-impl` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_op_assign_impl)]` error: suspicious use of `/` in `MulAssign` impl --> $DIR/suspicious_arithmetic_impl.rs:36:16 diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr index 0ed4eb20ecb..9bf3128cb8e 100644 --- a/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr +++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr @@ -5,6 +5,7 @@ LL | std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); | ^^^^^^^^^^ | = note: `-D clippy::suspicious-command-arg-space` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_command_arg_space)]` help: consider splitting the argument | LL | std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr index 8d2a2bdf6e9..1b238f501e1 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr @@ -5,6 +5,7 @@ LL | ///! Fake module documentation. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_doc_comments)]` help: use an inner doc comment to document the parent module or crate | LL | //! Fake module documentation. diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr index 3a93c289fc7..ae92c334f60 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr @@ -10,6 +10,7 @@ LL | | ///! d | |______^ | = note: `-D clippy::suspicious-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_doc_comments)]` help: use an inner doc comment to document the parent module or crate | LL + //! a diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr index 723fdd7e93e..95047cb95ee 100644 --- a/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr +++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr @@ -6,6 +6,7 @@ LL | } { | = note: to remove this lint, add the missing `else` or add a new line before the next block = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_else_formatting)]` error: this looks like an `else if` but the `else` is missing --> $DIR/suspicious_else_formatting.rs:26:6 diff --git a/src/tools/clippy/tests/ui/suspicious_map.stderr b/src/tools/clippy/tests/ui/suspicious_map.stderr index 154083f99fa..9c065e05ca6 100644 --- a/src/tools/clippy/tests/ui/suspicious_map.stderr +++ b/src/tools/clippy/tests/ui/suspicious_map.stderr @@ -6,6 +6,7 @@ LL | let _ = (0..3).map(|x| x + 2).count(); | = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` = note: `-D clippy::suspicious-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` error: this call to `map()` won't have an effect on the call to `count()` --> $DIR/suspicious_map.rs:8:13 diff --git a/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr b/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr index baf9bc74b00..0784da06e5f 100644 --- a/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr +++ b/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr @@ -5,6 +5,7 @@ LL | self.x == other.y && self.y == other.y && self.z == other.z | ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x` | = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_operation_groupings)]` error: this sequence of operators looks suspiciously like a bug --> $DIR/suspicious_operation_groupings.rs:28:20 diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr index 2bdf1043abb..4513beac8b2 100644 --- a/src/tools/clippy/tests/ui/suspicious_splitn.stderr +++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr @@ -6,6 +6,7 @@ LL | let _ = "a,b".splitn(0, ','); | = note: the resulting iterator will always return `None` = note: `-D clippy::suspicious-splitn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_splitn)]` error: `rsplitn` called with `0` splits --> $DIR/suspicious_splitn.rs:13:13 diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr index cbda1649c62..eb967a714d9 100644 --- a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr +++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr @@ -5,6 +5,7 @@ LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_to_owned)]` help: depending on intent, either make the Cow an Owned variant | LL | let _ = cow.into_owned(); @@ -66,6 +67,7 @@ LL | let _ = String::from(moo).to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()` | = note: `-D clippy::implicit-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_clone)]` error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type --> $DIR/suspicious_to_owned.rs:69:13 diff --git a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr index c44a43ea1ec..3cddde4eca7 100644 --- a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr +++ b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr @@ -6,6 +6,7 @@ LL | if a >- 30 {} | = help: put a space between `>` and `-` and remove the space after `-` = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_unary_op_formatting)]` error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator --> $DIR/suspicious_unary_op_formatting.rs:11:9 diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr index 1a260e64e77..29e9fa77101 100644 --- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr +++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr @@ -5,6 +5,7 @@ LL | let _ = 2 ^ 5; | ^^^^^ help: did you mean to write: `2.pow(5)` | = note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::suspicious_xor_used_as_pow)]` error: `^` is not the exponentiation operator --> $DIR/suspicious_xor_used_as_pow.rs:22:13 diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr index a3b9c2b744c..e69ad02b08f 100644 --- a/src/tools/clippy/tests/ui/swap.stderr +++ b/src/tools/clippy/tests/ui/swap.stderr @@ -8,6 +8,7 @@ LL | | bar.b = temp; | = note: or maybe you should use `std::mem::replace`? = note: `-D clippy::manual-swap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_swap)]` error: this looks like you are swapping elements of `foo` manually --> $DIR/swap.rs:40:5 @@ -108,6 +109,7 @@ LL | | b = a; | = note: or maybe you should use `std::mem::replace`? = note: `-D clippy::almost-swapped` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]` error: this looks like you are trying to swap `c.0` and `a` --> $DIR/swap.rs:144:5 diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr index a0f5160ee20..42455f4926e 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr @@ -5,6 +5,7 @@ LL | core::mem::swap(&mut *y, &mut *z); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(y, z)` | = note: `-D clippy::swap-ptr-to-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::swap_ptr_to_ref)]` error: call to `core::mem::swap` with a parameter derived from a raw pointer --> $DIR/swap_ptr_to_ref.rs:12:9 diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr b/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr index f0c1e7e7428..ce1d7814250 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr @@ -5,6 +5,7 @@ LL | core::mem::swap(addr_of_mut_to_ref!(x), &mut *y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::swap-ptr-to-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::swap_ptr_to_ref)]` error: call to `core::mem::swap` with a parameter derived from a raw pointer --> $DIR/swap_ptr_to_ref_unfixable.rs:17:9 diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr index 9da05fbec68..69ce214ae56 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr @@ -5,6 +5,7 @@ LL | /// - First String: | ^^^^ help: consider using four spaces per tab | = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended --> $DIR/tabs_in_doc_comments.rs:11:9 diff --git a/src/tools/clippy/tests/ui/temporary_assignment.stderr b/src/tools/clippy/tests/ui/temporary_assignment.stderr index 241abc2c5c7..cbb8924187c 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.stderr +++ b/src/tools/clippy/tests/ui/temporary_assignment.stderr @@ -5,6 +5,7 @@ LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::temporary-assignment` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::temporary_assignment)]` error: assignment to temporary --> $DIR/temporary_assignment.rs:51:5 diff --git a/src/tools/clippy/tests/ui/tests_outside_test_module.stderr b/src/tools/clippy/tests/ui/tests_outside_test_module.stderr index 71c649c5d27..112d6ce1f2c 100644 --- a/src/tools/clippy/tests/ui/tests_outside_test_module.stderr +++ b/src/tools/clippy/tests/ui/tests_outside_test_module.stderr @@ -6,6 +6,7 @@ LL | fn my_test() {} | = note: move it to a testing module marked with #[cfg(test)] = note: `-D clippy::tests-outside-test-module` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::tests_outside_test_module)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.stderr b/src/tools/clippy/tests/ui/to_digit_is_some.stderr index 9ece2fce664..5067ad7fb6d 100644 --- a/src/tools/clippy/tests/ui/to_digit_is_some.stderr +++ b/src/tools/clippy/tests/ui/to_digit_is_some.stderr @@ -5,6 +5,7 @@ LL | let _ = d.to_digit(8).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d.is_digit(8)` | = note: `-D clippy::to-digit-is-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::to_digit_is_some)]` error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:8:13 diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr index 84017669f47..2c27a3c8e91 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr @@ -5,6 +5,7 @@ LL | let ref _x = 1; | ----^^^^^^----- help: try: `let _x = &1;` | = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::toplevel_ref_arg)]` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead --> $DIR/toplevel_ref_arg.rs:16:9 diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr index 7307bd599d9..45123dd5ec0 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -5,6 +5,7 @@ LL | fn the_answer(ref mut x: u8) { | ^^^^^^^^^ | = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::toplevel_ref_arg)]` error: `ref` directly on a function argument is ignored. Consider using a reference type instead --> $DIR/toplevel_ref_arg_non_rustfix.rs:20:24 diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.stderr b/src/tools/clippy/tests/ui/trailing_empty_array.stderr index d89e77f61ce..ef7fc24c374 100644 --- a/src/tools/clippy/tests/ui/trailing_empty_array.stderr +++ b/src/tools/clippy/tests/ui/trailing_empty_array.stderr @@ -10,6 +10,7 @@ LL | | } | = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute = note: `-D clippy::trailing-empty-array` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::trailing_empty_array)]` error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_empty_array.rs:11:1 diff --git a/src/tools/clippy/tests/ui/trailing_zeros.stderr b/src/tools/clippy/tests/ui/trailing_zeros.stderr index fb4025a7548..10924ad1247 100644 --- a/src/tools/clippy/tests/ui/trailing_zeros.stderr +++ b/src/tools/clippy/tests/ui/trailing_zeros.stderr @@ -5,6 +5,7 @@ LL | let _ = (x & 0b1111 == 0); | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4` | = note: `-D clippy::verbose-bit-mask` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::verbose_bit_mask)]` error: bit mask could be simplified with a call to `trailing_zeros` --> $DIR/trailing_zeros.rs:9:13 diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 2765f763d6d..cdc733b54a9 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -5,6 +5,7 @@ LL | let _: *const T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` | = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer --> $DIR/transmute.rs:28:21 @@ -67,6 +68,7 @@ LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::crosspointer-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) --> $DIR/transmute.rs:94:24 @@ -93,6 +95,7 @@ LL | let _: char = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` | = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` error: transmute from a `i32` to a `char` --> $DIR/transmute.rs:110:28 @@ -107,6 +110,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` | = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `u32` to a `f32` --> $DIR/transmute.rs:128:31 @@ -115,6 +119,7 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` | = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i32` to a `f32` --> $DIR/transmute.rs:131:31 @@ -141,6 +146,7 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` | = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` --> $DIR/transmute.rs:159:30 @@ -227,6 +233,7 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` | = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` --> $DIR/transmute.rs:201:32 diff --git a/src/tools/clippy/tests/ui/transmute_64bit.stderr b/src/tools/clippy/tests/ui/transmute_64bit.stderr index 32d7e6bdf42..a30480eb7df 100644 --- a/src/tools/clippy/tests/ui/transmute_64bit.stderr +++ b/src/tools/clippy/tests/ui/transmute_64bit.stderr @@ -5,6 +5,7 @@ LL | let _: *const usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::wrong-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wrong_transmute)]` error: transmute from a `f64` to a pointer --> $DIR/transmute_64bit.rs:10:29 diff --git a/src/tools/clippy/tests/ui/transmute_collection.stderr b/src/tools/clippy/tests/ui/transmute_collection.stderr index e4b9963be89..2163142eef2 100644 --- a/src/tools/clippy/tests/ui/transmute_collection.stderr +++ b/src/tools/clippy/tests/ui/transmute_collection.stderr @@ -5,6 +5,7 @@ LL | let _ = transmute::<_, Vec<u32>>(vec![0u8]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unsound-collection-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unsound_collection_transmute)]` error: transmute from `std::vec::Vec<u32>` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound --> $DIR/transmute_collection.rs:13:17 diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr index dd21c0cde2c..1895120c0c9 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr @@ -5,6 +5,7 @@ LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()` | = note: `-D clippy::transmute-float-to-int` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]` error: transmute from a `f32` to a `i32` --> $DIR/transmute_float_to_int.rs:7:27 diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr index 9efba88f38f..b79a80c326d 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr @@ -5,6 +5,7 @@ LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)` | = note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_non_zero)]` error: transmute from a `u16` to a `NonZeroU16` --> $DIR/transmute_int_to_non_zero.rs:21:34 diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr index 6278f51dde2..ab0ac0dd480 100644 --- a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr +++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr @@ -6,6 +6,7 @@ LL | let _: fn() = std::mem::transmute(0 as *const ()); | = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_null_to_fn)]` error: transmuting a known null pointer into a function pointer --> $DIR/transmute_null_to_fn.rs:10:23 diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr index ee414e46bb7..564339c067e 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr @@ -5,6 +5,7 @@ LL | let _: *const f32 = std::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32` | = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ptr)]` error: transmute from a pointer to a pointer --> $DIR/transmute_ptr_to_ptr.rs:33:27 diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr index c63b5524edb..9d1b22a795b 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr @@ -5,6 +5,7 @@ LL | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` | = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ref)]` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) --> $DIR/transmute_ptr_to_ref.rs:8:21 diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr index 3618213ecd5..f87b1ece964 100644 --- a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr +++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr @@ -5,6 +5,7 @@ LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_undefined_repr)]` error: transmute into `Ty2<u32, i32>` which has an undefined layout --> $DIR/transmute_undefined_repr.rs:33:32 diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 846b982cdea..a7988dc4b39 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -5,6 +5,7 @@ LL | let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32` | = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a pointer to a pointer --> $DIR/transmutes_expressible_as_ptr_casts.rs:21:38 @@ -13,6 +14,7 @@ LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as *const i8` | = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ptr)]` error: transmute from a pointer to a pointer --> $DIR/transmutes_expressible_as_ptr_casts.rs:27:46 @@ -27,6 +29,7 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` | = note: `-D clippy::transmutes-expressible-as-ptr-casts` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer --> $DIR/transmutes_expressible_as_ptr_casts.rs:39:41 diff --git a/src/tools/clippy/tests/ui/transmuting_null.stderr b/src/tools/clippy/tests/ui/transmuting_null.stderr index a8de01ec15d..402de38fe9e 100644 --- a/src/tools/clippy/tests/ui/transmuting_null.stderr +++ b/src/tools/clippy/tests/ui/transmuting_null.stderr @@ -5,6 +5,7 @@ LL | let _: &u64 = std::mem::transmute(0 as *const u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::transmuting-null` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::transmuting_null)]` error: transmuting a known null pointer into a reference --> $DIR/transmuting_null.rs:13:23 diff --git a/src/tools/clippy/tests/ui/trim_split_whitespace.stderr b/src/tools/clippy/tests/ui/trim_split_whitespace.stderr index 0379d79ae98..a1c66eea0d1 100644 --- a/src/tools/clippy/tests/ui/trim_split_whitespace.stderr +++ b/src/tools/clippy/tests/ui/trim_split_whitespace.stderr @@ -5,6 +5,7 @@ LL | let _ = " A B C ".trim().split_whitespace(); // should trigger lint | ^^^^^^^ help: remove `trim()` | = note: `-D clippy::trim-split-whitespace` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::trim_split_whitespace)]` error: found call to `str::trim_start` before `str::split_whitespace` --> $DIR/trim_split_whitespace.rs:62:23 diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr index 70c13d10fd8..f8f5b3e7587 100644 --- a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr +++ b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr @@ -6,6 +6,7 @@ LL | let x = (x[0], x[1]); | = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed = note: `-D clippy::tuple-array-conversions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::tuple_array_conversions)]` error: it looks like you're trying to convert a tuple to an array --> $DIR/tuple_array_conversions.rs:11:13 diff --git a/src/tools/clippy/tests/ui/type_complexity.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr index 496dacfbfde..a3cf6ffe975 100644 --- a/src/tools/clippy/tests/ui/type_complexity.stderr +++ b/src/tools/clippy/tests/ui/type_complexity.stderr @@ -5,6 +5,7 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::type-complexity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::type_complexity)]` error: very complex type used. Consider factoring parts into `type` definitions --> $DIR/type_complexity.rs:10:12 diff --git a/src/tools/clippy/tests/ui/type_id_on_box.stderr b/src/tools/clippy/tests/ui/type_id_on_box.stderr index 442f2c6b847..844dae158b8 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box.stderr +++ b/src/tools/clippy/tests/ui/type_id_on_box.stderr @@ -9,6 +9,7 @@ LL | let _ = any_box.type_id(); = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear = note: `-D clippy::type-id-on-box` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::type_id_on_box)]` error: calling `.type_id()` on a `Box<dyn Any>` --> $DIR/type_id_on_box.rs:28:13 diff --git a/src/tools/clippy/tests/ui/types.stderr b/src/tools/clippy/tests/ui/types.stderr index 0d489f62520..b253cf33867 100644 --- a/src/tools/clippy/tests/ui/types.stderr +++ b/src/tools/clippy/tests/ui/types.stderr @@ -5,6 +5,7 @@ LL | let c_i64: i64 = c as i64; | ^^^^^^^^ help: try: `i64::from(c)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr index fa47f6ee806..2b62bc96403 100644 --- a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr +++ b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr @@ -5,6 +5,7 @@ LL | let _ = _first - second; | ^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(second).unwrap()` | = note: `-D clippy::unchecked-duration-subtraction` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unchecked_duration_subtraction)]` error: unchecked subtraction of a 'Duration' from an 'Instant' --> $DIR/unchecked_duration_subtraction.rs:11:13 diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr index ee1d3aa285a..77f6aea2e0d 100644 --- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr +++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr @@ -6,6 +6,7 @@ LL | /* Safety: */ unsafe {} | = help: consider adding a safety comment on the preceding line = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment --> $DIR/undocumented_unsafe_blocks.rs:266:5 @@ -251,6 +252,7 @@ help: consider removing the safety comment LL | // SAFETY: | ^^^^^^^^^^ = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment --> $DIR/undocumented_unsafe_blocks.rs:472:5 diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr index 4f3bad6c032..0b6e20664e3 100644 --- a/src/tools/clippy/tests/ui/unicode.stderr +++ b/src/tools/clippy/tests/ui/unicode.stderr @@ -5,6 +5,7 @@ LL | print!("Here >< is a ZWS, and another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{200B}< is a ZWS, and \u{200B}another"` | = note: `-D clippy::invisible-characters` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::invisible_characters)]` error: invisible character detected --> $DIR/unicode.rs:7:12 @@ -25,6 +26,7 @@ LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` | = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unicode_not_nfc)]` error: literal non-ASCII character detected --> $DIR/unicode.rs:23:16 diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr index 1ffea9f8730..d39f05839ed 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.stderr +++ b/src/tools/clippy/tests/ui/uninit_vec.stderr @@ -9,6 +9,7 @@ LL | vec.set_len(200); | = help: initialize the buffer or wrap the content in `MaybeUninit` = note: `-D clippy::uninit-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values --> $DIR/uninit_vec.rs:24:5 diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.stderr b/src/tools/clippy/tests/ui/uninlined_format_args.stderr index c73c6487386..829d646b866 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.stderr +++ b/src/tools/clippy/tests/ui/uninlined_format_args.stderr @@ -5,6 +5,7 @@ LL | println!("val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::uninlined-format-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::uninlined_format_args)]` help: change this to | LL - println!("val='{}'", local_i32); diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr index 55a3bd08b31..221efeb50cd 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr @@ -5,6 +5,7 @@ LL | println!("val='{}'", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::uninlined-format-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::uninlined_format_args)]` help: change this to | LL - println!("val='{}'", var); diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr index 00e7e8f0ff7..ec1e3a1cf11 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr @@ -5,6 +5,7 @@ LL | println!("val='{}'", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::uninlined-format-args` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::uninlined_format_args)]` help: change this to | LL - println!("val='{}'", var); diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 1de9d44bb0d..8656c8fddab 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -7,6 +7,7 @@ LL | | }); | |______^ | = note: `-D clippy::unit-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` help: remove the semicolon from the last statement in the block | LL | 1 diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr index d35e931697d..b207acb5927 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr @@ -7,6 +7,7 @@ LL | foo({}); | help: use a unit literal instead: `()` | = note: `-D clippy::unit-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` error: passing a unit value to a function --> $DIR/unit_arg_empty_blocks.rs:17:5 diff --git a/src/tools/clippy/tests/ui/unit_cmp.stderr b/src/tools/clippy/tests/ui/unit_cmp.stderr index 38618c59180..17355e23797 100644 --- a/src/tools/clippy/tests/ui/unit_cmp.stderr +++ b/src/tools/clippy/tests/ui/unit_cmp.stderr @@ -12,6 +12,7 @@ LL | | } {} | |_____^ | = note: `-D clippy::unit-cmp` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_cmp)]` error: >-comparison of unit values detected. This will always be false --> $DIR/unit_cmp.rs:25:8 diff --git a/src/tools/clippy/tests/ui/unit_hash.stderr b/src/tools/clippy/tests/ui/unit_hash.stderr index eeb48cf7f37..a26fd734413 100644 --- a/src/tools/clippy/tests/ui/unit_hash.stderr +++ b/src/tools/clippy/tests/ui/unit_hash.stderr @@ -6,6 +6,7 @@ LL | Foo::Empty => ().hash(&mut state), | = note: the implementation of `Hash` for `()` is a no-op = note: `-D clippy::unit-hash` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_hash)]` error: this call to `hash` on the unit type will do nothing --> $DIR/unit_hash.rs:26:5 diff --git a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr index 74e6d6b1262..9220fb89e90 100644 --- a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr +++ b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr @@ -10,6 +10,7 @@ help: probably caused by this trailing semicolon LL | double(s.field); | ^ = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_return_expecting_ord)]` error: this closure returns the unit type which also implements PartialOrd --> $DIR/unit_return_expecting_ord.rs:24:30 diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr index d478df8056b..ee82db31c2c 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr @@ -5,6 +5,7 @@ LL | #![allow(clippy::All)] | ^^^^^^^^^^^ help: did you mean: `clippy::all` | = note: `-D unknown-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unknown_lints)]` error: unknown lint: `clippy::CMP_OWNED` --> $DIR/unknown_clippy_lints.rs:4:9 diff --git a/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr b/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr index 8909dbcdd98..944e911fa94 100644 --- a/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr @@ -6,6 +6,7 @@ LL | fn baz(&self) -> Box<usize>; | = help: changing this also requires a change to the return expressions in this function = note: `-D clippy::unnecessary-box-returns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_box_returns)]` error: boxed return of the sized type `usize` --> $DIR/unnecessary_box_returns.rs:19:22 diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index 69bbcdf7407..d4786f66e44 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -5,6 +5,7 @@ LL | ptr as *const T | ^^^^^^^^^^^^^^^ help: try: `ptr` | = note: `-D clippy::unnecessary-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting integer literal to `i32` is unnecessary --> $DIR/unnecessary_cast.rs:53:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr index ef3632db9f1..2d38a2a7709 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr @@ -5,6 +5,7 @@ LL | let _ = std::ptr::null() as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::null()` | = note: `-D clippy::unnecessary-cast` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting raw pointers to the same type and constness is unnecessary (`*mut issue11113::Vtbl` -> `*mut issue11113::Vtbl`) --> $DIR/unnecessary_cast_unfixable.rs:21:16 diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr index da387e8bb7c..eab5f042316 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr @@ -5,6 +5,7 @@ LL | rc.clone(); | ^^^^^^^^^^ help: try: `Rc::<bool>::clone(&rc)` | = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::clone_on_ref_ptr)]` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:28:5 @@ -37,6 +38,7 @@ LL | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` | = note: `-D clippy::clone-on-copy` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::clone_on_copy)]` error: using `clone` on type `Option<T>` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:50:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr index f34acdc8d7e..0dd65f65272 100644 --- a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr @@ -5,6 +5,7 @@ LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_filter_map)]` error: this `.filter_map` can be written more simply using `.filter` --> $DIR/unnecessary_filter_map.rs:7:13 diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr index 9acbd665002..662623fb617 100644 --- a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr @@ -5,6 +5,7 @@ LL | let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-find-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_find_map)]` error: this `.find_map` can be written more simply using `.find` --> $DIR/unnecessary_find_map.rs:7:13 diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.stderr b/src/tools/clippy/tests/ui/unnecessary_fold.stderr index 10920470c1a..f0d03963842 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_fold.stderr @@ -5,6 +5,7 @@ LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` | = note: `-D clippy::unnecessary-fold` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` error: this `.fold` can be written more succinctly using another method --> $DIR/unnecessary_fold.rs:8:20 diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr index e9df5afa6b9..ba40c6c14db 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr @@ -5,6 +5,7 @@ LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` help: use | LL | for (t, path) in files { diff --git a/src/tools/clippy/tests/ui/unnecessary_join.stderr b/src/tools/clippy/tests/ui/unnecessary_join.stderr index 80e5bc63a65..8bf2ac5fdb1 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_join.stderr @@ -7,6 +7,7 @@ LL | | .join(""); | |_________________^ help: try using: `collect::<String>()` | = note: `-D clippy::unnecessary-join` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_join)]` error: called `.collect::<Vec<String>>().join("")` on an iterator --> $DIR/unnecessary_join.rs:19:10 diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr index 2850a632fc7..4f1ca374872 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr @@ -7,6 +7,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` error: unnecessary closure used to substitute value for `Option::None` --> $DIR/unnecessary_lazy_eval.rs:69:13 diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 8bff2a63779..27fa560d4d7 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -7,6 +7,7 @@ LL | let _ = Ok(1).unwrap_or_else(|()| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` error: unnecessary closure used to substitute value for `Result::Err` --> $DIR/unnecessary_lazy_eval_unfixable.rs:19:13 diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr index eae74f56950..013907f59c4 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr @@ -5,6 +5,7 @@ LL | let _val = Some(1).unwrap(); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_literal_unwrap)]` help: remove the `Some` and `unwrap()` | LL - let _val = Some(1).unwrap(); diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr index 2a60896c0a3..c6ecd6de61e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr @@ -10,6 +10,7 @@ help: remove the `Some` and `unwrap()` LL | let val = Some(1); | ^^^^^^^ = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_literal_unwrap)]` error: used `expect()` on `Some` value --> $DIR/unnecessary_literal_unwrap_unfixable.rs:9:17 diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index d71aa60d4cc..fbe495f518f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -5,6 +5,7 @@ LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | = note: `-D clippy::unnecessary-operation` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]` error: unnecessary operation --> $DIR/unnecessary_operation.rs:55:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr index 2cfed265adf..58d925b1096 100644 --- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr @@ -5,6 +5,7 @@ LL | ref_str_argument(&String::new()); | ^^^^^^^^^^^^^^ help: try: `""` | = note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_owned_empty_strings)]` error: usage of `&String::from("")` for a function expecting a `&str` argument --> $DIR/unnecessary_owned_empty_strings.rs:14:22 diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr index d97048e2703..6d4ef6c308d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr @@ -10,6 +10,7 @@ help: consider removing the safety comment LL | // SAFETY: | ^^^^^^^^^^ = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: static item has unnecessary safety comment --> $DIR/unnecessary_safety_comment.rs:9:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr b/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr index 412674a85ec..4e50aaececf 100644 --- a/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr @@ -8,6 +8,7 @@ LL | use std::fs::{self as alias}; | = note: this will slightly change semantics; any non-module items at the same path will also be imported = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_self_imports)]` error: import ending with `::{self}` --> $DIR/unnecessary_self_imports.rs:7:1 diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr index 55d681487b6..9d54c8d50e3 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr @@ -5,6 +5,7 @@ LL | vec.sort_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()` | = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` error: use Vec::sort here instead --> $DIR/unnecessary_sort_by.rs:13:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr index 5311415d166..d8e0ce6ccaf 100644 --- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr @@ -5,6 +5,7 @@ LL | Self { ..*self } | ^^^^^^^^^^^^^^^^ help: replace with: `*self` | = note: `-D clippy::unnecessary-struct-initialization` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_struct_initialization)]` error: unnecessary struct building --> $DIR/unnecessary_struct_initialization.rs:39:17 diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr index b5d009ae1dd..d8971b51dca 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr @@ -10,6 +10,7 @@ note: this value is dropped without further use LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::redundant-clone` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone --> $DIR/unnecessary_to_owned.rs:149:40 @@ -66,6 +67,7 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this | = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` --> $DIR/unnecessary_to_owned.rs:58:19 diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr index b0f20fdac5f..817eb3e26ee 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr @@ -5,6 +5,7 @@ LL | pub fn apocalypse(universe: &mut ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-safety-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_doc)]` error: safe function's docs have unnecessary `# Safety` section --> $DIR/unnecessary_unsafety_doc.rs:45:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr index 01340a0abdd..20d3e070e71 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr @@ -11,6 +11,7 @@ LL | | } | |_^ | = note: `-D clippy::unnecessary-wraps` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_wraps)]` help: remove `Option` from the return type... | LL | fn func1(a: bool, b: bool) -> i32 { diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr index 3f15684986f..68b433df8aa 100644 --- a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr +++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr @@ -6,6 +6,7 @@ LL | Foo { a: _, b: 0, .. } => {}, | = help: try with `Foo { b: 0, .. }` = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unneeded_field_pattern)]` error: all the struct fields are matched to a wildcard pattern, consider using `..` --> $DIR/unneeded_field_pattern.rs:20:9 diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr index 9e4f0d45d80..98ca7e37356 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr @@ -5,6 +5,7 @@ LL | if let box 0 | box 2 = Box::new(0) {} | ^^^^^^^^^^^^^ | = note: `-D clippy::unnested-or-patterns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnested_or_patterns)]` help: nest the patterns | LL | if let box (0 | 2) = Box::new(0) {} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr index afb3100a552..182ae00de22 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr @@ -5,6 +5,7 @@ LL | if let Some(Some(0)) | Some(Some(1)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnested-or-patterns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnested_or_patterns)]` help: nest the patterns | LL | if let Some(Some(0 | 1)) = None {} diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr index b75aa75a336..d7a3377ec37 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.stderr +++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr @@ -5,6 +5,7 @@ LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` | = note: `-D clippy::unreadable-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unreadable_literal)]` error: long literal lacking separators --> $DIR/unreadable_literal.rs:32:31 diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr index 7b96500fd11..d6fb82398d8 100644 --- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr +++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr @@ -6,6 +6,7 @@ LL | #[derive(Deserialize)] | = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unsafe_derive_deserialize)]` = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr index 5daa69e1fb4..261c7837a4c 100644 --- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr +++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr @@ -5,6 +5,7 @@ LL | use std::cell::UnsafeCell as TotallySafeCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unsafe_removed_from_name)]` error: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain` --> $DIR/unsafe_removed_from_name.rs:9:1 diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr index a0c0be7a9d1..d74e7287505 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr @@ -5,6 +5,7 @@ LL | let _fail1 = 1234i32; | ^^^^^^^ help: add an underscore: `1234_i32` | = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unseparated_literal_suffix)]` error: integer type suffix should be separated by an underscore --> $DIR/unseparated_prefix_literals.rs:24:18 diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr index 06944f8f8d8..077e8cacce1 100644 --- a/src/tools/clippy/tests/ui/unused_async.stderr +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -16,6 +16,7 @@ note: `await` used in an async block, which does not require the enclosing funct LL | ready(()).await; | ^^^^^ = note: `-D clippy::unused-async` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_async)]` error: unused `async` for function with no await statements --> $DIR/unused_async.rs:46:5 diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr index e9145ff382a..183e80c853c 100644 --- a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr @@ -5,6 +5,7 @@ LL | println!("{:5}.", format_args!("")); | ^^^^ | = note: `-D clippy::unused-format-specs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_format_specs)]` help: for the width to apply consider using `format!()` | LL | println!("{:5}.", format!("")); diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr index c729a0b9016..f9aef596a1c 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.stderr +++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr @@ -6,6 +6,7 @@ LL | s.write(b"test")?; | = help: use `Write::write_all` instead, or handle partial writes = note: `-D clippy::unused-io-amount` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_io_amount)]` error: read amount is not handled --> $DIR/unused_io_amount.rs:12:5 diff --git a/src/tools/clippy/tests/ui/unused_peekable.stderr b/src/tools/clippy/tests/ui/unused_peekable.stderr index 896ca49d710..157d6fc15f2 100644 --- a/src/tools/clippy/tests/ui/unused_peekable.stderr +++ b/src/tools/clippy/tests/ui/unused_peekable.stderr @@ -6,6 +6,7 @@ LL | let peekable = std::iter::empty::<u32>().peekable(); | = help: consider removing the call to `peekable` = note: `-D clippy::unused-peekable` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_peekable)]` error: `peek` never called on `Peekable` iterator --> $DIR/unused_peekable.rs:18:9 diff --git a/src/tools/clippy/tests/ui/unused_rounding.stderr b/src/tools/clippy/tests/ui/unused_rounding.stderr index 163f78982ee..d6ce2735135 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.stderr +++ b/src/tools/clippy/tests/ui/unused_rounding.stderr @@ -5,6 +5,7 @@ LL | let _ = 1f32.ceil(); | ^^^^^^^^^^^ help: remove the `ceil` method call: `1f32` | = note: `-D clippy::unused-rounding` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_rounding)]` error: used the `floor` method with a whole number float --> $DIR/unused_rounding.rs:5:13 diff --git a/src/tools/clippy/tests/ui/unused_self.stderr b/src/tools/clippy/tests/ui/unused_self.stderr index 5cf15c00b1b..3865095bbfe 100644 --- a/src/tools/clippy/tests/ui/unused_self.stderr +++ b/src/tools/clippy/tests/ui/unused_self.stderr @@ -6,6 +6,7 @@ LL | fn unused_self_move(self) {} | = help: consider refactoring to an associated function = note: `-D clippy::unused-self` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_self)]` error: unused `self` argument --> $DIR/unused_self.rs:13:28 diff --git a/src/tools/clippy/tests/ui/unwrap.stderr b/src/tools/clippy/tests/ui/unwrap.stderr index 38904858a32..25911ded2fb 100644 --- a/src/tools/clippy/tests/ui/unwrap.stderr +++ b/src/tools/clippy/tests/ui/unwrap.stderr @@ -7,6 +7,7 @@ LL | let _ = opt.unwrap(); = note: if this value is `None`, it will panic = help: consider using `expect()` to provide a better panic message = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: used `unwrap()` on a `Result` value --> $DIR/unwrap.rs:12:13 diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr index 0b43f572745..cbe6ea22e89 100644 --- a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr +++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr @@ -6,6 +6,7 @@ LL | Some(3).unwrap(); | = note: if this value is `None`, it will panic = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: used `expect()` on an `Option` value --> $DIR/unwrap_expect_used.rs:29:5 @@ -15,6 +16,7 @@ LL | Some(3).expect("Hello world!"); | = note: if this value is `None`, it will panic = note: `-D clippy::expect-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::expect_used)]` error: used `unwrap()` on a `Result` value --> $DIR/unwrap_expect_used.rs:45:5 diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.stderr b/src/tools/clippy/tests/ui/unwrap_in_result.stderr index a394da272a8..9a0a32d471e 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.stderr +++ b/src/tools/clippy/tests/ui/unwrap_in_result.stderr @@ -17,6 +17,7 @@ note: potential non-recoverable error(s) LL | let i = i_str.parse::<i32>().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::unwrap-in-result` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_in_result)]` error: used unwrap or expect in a function that returns result or option --> $DIR/unwrap_in_result.rs:33:5 diff --git a/src/tools/clippy/tests/ui/unwrap_or.stderr b/src/tools/clippy/tests/ui/unwrap_or.stderr index 8992092bc58..3a32092f7be 100644 --- a/src/tools/clippy/tests/ui/unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/unwrap_or.stderr @@ -5,6 +5,7 @@ LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())` | = note: `-D clippy::or-fun-call` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]` error: use of `unwrap_or` followed by a function call --> $DIR/unwrap_or.rs:11:47 diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr index 40023cf3b66..3119aba19e8 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr @@ -5,6 +5,7 @@ LL | with_new.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` | = note: `-D clippy::unwrap-or-default` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]` error: use of `unwrap_or_else` to construct default value --> $DIR/unwrap_or_else_default.rs:60:23 diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr index 9be1bb304ec..c57b325e91a 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr @@ -5,6 +5,7 @@ LL | CWR, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Cwr` | = note: `-D clippy::upper-case-acronyms` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::upper_case_acronyms)]` error: name `ECE` contains a capitalized acronym --> $DIR/upper_case_acronyms.rs:12:5 diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index 0e6ae5d451b..a1d4eac5dc0 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -5,6 +5,7 @@ LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` | = note: `-D clippy::use-self` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::use_self)]` error: unnecessary structure name repetition --> $DIR/use_self.rs:22:13 diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr index 301d78e6c1e..71a227174ea 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.stderr +++ b/src/tools/clippy/tests/ui/use_self_trait.stderr @@ -5,6 +5,7 @@ LL | fn refs(p1: &Bad) -> &Bad { | ^^^ help: use the applicable keyword: `Self` | = note: `-D clippy::use-self` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::use_self)]` error: unnecessary structure name repetition --> $DIR/use_self_trait.rs:19:27 diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr index 875fafe438a..289519b172e 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr +++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr @@ -5,6 +5,7 @@ LL | _foo + 1 | ^^^^ | = note: `-D clippy::used-underscore-binding` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::used_underscore_binding)]` error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used --> $DIR/used_underscore_binding.rs:29:20 diff --git a/src/tools/clippy/tests/ui/useless_attribute.stderr b/src/tools/clippy/tests/ui/useless_attribute.stderr index 8bb7b2d3d9e..e65c59abaf8 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.stderr +++ b/src/tools/clippy/tests/ui/useless_attribute.stderr @@ -5,6 +5,7 @@ LL | #[allow(dead_code)] | ^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code)]` | = note: `-D clippy::useless-attribute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_attribute)]` error: useless lint attribute --> $DIR/useless_attribute.rs:9:1 diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr index 5cd6d9fa8c7..a28024d236a 100644 --- a/src/tools/clippy/tests/ui/vec.stderr +++ b/src/tools/clippy/tests/ui/vec.stderr @@ -5,6 +5,7 @@ LL | on_slice(&vec![]); | ^^^^^^^ help: you can use a slice directly: `&[]` | = note: `-D clippy::useless-vec` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` error: useless use of `vec!` --> $DIR/vec.rs:32:18 diff --git a/src/tools/clippy/tests/ui/vec_box_sized.stderr b/src/tools/clippy/tests/ui/vec_box_sized.stderr index 78e00f5661b..9118f284bb9 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.stderr +++ b/src/tools/clippy/tests/ui/vec_box_sized.stderr @@ -5,6 +5,7 @@ LL | const C: Vec<Box<i32>> = Vec::new(); | ^^^^^^^^^^^^^ help: try: `Vec<i32>` | = note: `-D clippy::vec-box` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::vec_box)]` error: `Vec<T>` is already on the heap, the boxing is unnecessary --> $DIR/vec_box_sized.rs:11:15 diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.stderr b/src/tools/clippy/tests/ui/vec_init_then_push.stderr index 9ad793d979b..978201bd17a 100644 --- a/src/tools/clippy/tests/ui/vec_init_then_push.stderr +++ b/src/tools/clippy/tests/ui/vec_init_then_push.stderr @@ -8,6 +8,7 @@ LL | | def_err.push(0); | |____________________^ help: consider using the `vec![]` macro: `let def_err: Vec<u32> = vec![..];` | = note: `-D clippy::vec-init-then-push` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::vec_init_then_push)]` error: calls to `push` immediately after creation --> $DIR/vec_init_then_push.rs:10:5 diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr index 8851e9f38be..715c9923b2e 100644 --- a/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr +++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr @@ -8,6 +8,7 @@ LL | v.resize(0, 5); | = help: the arguments may be inverted... = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::vec_resize_to_zero)]` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.stderr b/src/tools/clippy/tests/ui/verbose_file_reads.stderr index 592a7984305..04e1aedf7c5 100644 --- a/src/tools/clippy/tests/ui/verbose_file_reads.stderr +++ b/src/tools/clippy/tests/ui/verbose_file_reads.stderr @@ -6,6 +6,7 @@ LL | f.read_to_end(&mut buffer)?; | = help: consider using `fs::read` instead = note: `-D clippy::verbose-file-reads` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::verbose_file_reads)]` error: use of `File::read_to_string` --> $DIR/verbose_file_reads.rs:27:5 diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr index 91490afce36..83c82f3796e 100644 --- a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr +++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr @@ -6,6 +6,7 @@ LL | let _ = a == b; | = help: consider extracting and comparing data pointers only = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::vtable_address_comparisons)]` error: comparing trait object pointers compares a non-unique vtable address --> $DIR/vtable_address_comparisons.rs:16:13 diff --git a/src/tools/clippy/tests/ui/while_let_loop.stderr b/src/tools/clippy/tests/ui/while_let_loop.stderr index 00411172141..db887dc65c6 100644 --- a/src/tools/clippy/tests/ui/while_let_loop.stderr +++ b/src/tools/clippy/tests/ui/while_let_loop.stderr @@ -11,6 +11,7 @@ LL | | } | |_____^ help: try: `while let Some(_x) = y { .. }` | = note: `-D clippy::while-let-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::while_let_loop)]` error: this loop could be written as a `while let` loop --> $DIR/while_let_loop.rs:25:5 diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr index f8a66f2ad3e..cdc83b81667 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr @@ -5,6 +5,7 @@ LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` | = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::while_let_on_iterator)]` error: this loop could be written as a `for` loop --> $DIR/while_let_on_iterator.rs:20:5 diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr index 5d9ab78bbb4..4cfa0d99350 100644 --- a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr +++ b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr @@ -6,6 +6,7 @@ LL | "bar" | _ => { | = help: consider handling `_` separately = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wildcard_in_or_patterns)]` error: wildcard pattern covers any other pattern as it will match anyway --> $DIR/wild_in_or_pats.rs:17:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index f7baf234c2f..3c750815baf 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -5,6 +5,7 @@ LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` | = note: `-D clippy::wildcard-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` error: usage of wildcard import --> $DIR/wildcard_imports.rs:16:5 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr index af9ae6e786c..709a665d65c 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -5,6 +5,7 @@ LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` | = note: `-D clippy::wildcard-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` error: usage of wildcard import --> $DIR/wildcard_imports_2021.rs:14:5 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr index af9ae6e786c..709a665d65c 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -5,6 +5,7 @@ LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` | = note: `-D clippy::wildcard-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` error: usage of wildcard import --> $DIR/wildcard_imports_2021.rs:14:5 diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr index f0a09074bc6..372a54cf769 100644 --- a/src/tools/clippy/tests/ui/write_literal.stderr +++ b/src/tools/clippy/tests/ui/write_literal.stderr @@ -5,6 +5,7 @@ LL | write!(v, "Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::write_literal)]` help: try | LL - write!(v, "Hello {}", "world"); diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr index 84b302d8d3b..fc24dba4543 100644 --- a/src/tools/clippy/tests/ui/write_literal_2.stderr +++ b/src/tools/clippy/tests/ui/write_literal_2.stderr @@ -5,6 +5,7 @@ LL | writeln!(v, r"{}", r"{hello}"); | ^^^^^^^^^^ help: try: `"{hello}"` | = note: `-D clippy::needless-raw-strings` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]` error: literal with an empty format string --> $DIR/write_literal_2.rs:10:23 @@ -13,6 +14,7 @@ LL | writeln!(v, "{}", "{hello}"); | ^^^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::write_literal)]` help: try | LL - writeln!(v, "{}", "{hello}"); diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr index d84d57d84f5..78874ffadc0 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.stderr +++ b/src/tools/clippy/tests/ui/write_with_newline.stderr @@ -5,6 +5,7 @@ LL | write!(v, "Hello\n"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::write-with-newline` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::write_with_newline)]` help: use `writeln!` instead | LL - write!(v, "Hello\n"); diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.stderr b/src/tools/clippy/tests/ui/writeln_empty_string.stderr index 93e1af5a4ec..03747554361 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.stderr +++ b/src/tools/clippy/tests/ui/writeln_empty_string.stderr @@ -7,6 +7,7 @@ LL | writeln!(v, ""); | help: remove the empty string | = note: `-D clippy::writeln-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::writeln_empty_string)]` error: empty string literal in `writeln!` --> $DIR/writeln_empty_string.rs:12:5 diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr index 2d52b64c812..9f457b50ce7 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr @@ -6,6 +6,7 @@ LL | fn from_i32(self) {} | = help: consider choosing a less ambiguous name = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention.rs:23:21 diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr index 0069059203b..dc12a844332 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr @@ -6,6 +6,7 @@ LL | pub fn from_be_self(self) -> Self { | = help: consider choosing a less ambiguous name = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: methods called `from_*` usually take no `self` --> $DIR/wrong_self_convention2.rs:64:25 diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr index cd7a9aae144..21255287d72 100644 --- a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr @@ -6,6 +6,7 @@ LL | pub fn to_many(&mut self) -> Option<&mut [T]> { | = help: consider choosing a less ambiguous name = note: `-D clippy::wrong-self-convention` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference --> $DIR/wrong_self_conventions_mut.rs:23:28 diff --git a/src/tools/clippy/tests/ui/zero_div_zero.stderr b/src/tools/clippy/tests/ui/zero_div_zero.stderr index cde6bc907c6..797ae2537bb 100644 --- a/src/tools/clippy/tests/ui/zero_div_zero.stderr +++ b/src/tools/clippy/tests/ui/zero_div_zero.stderr @@ -6,6 +6,7 @@ LL | let nan = 0.0 / 0.0; | = help: consider using `f64::NAN` if you would like a constant representing NaN = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zero_divided_by_zero)]` error: constant division of `0.0` with `0.0` will always result in NaN --> $DIR/zero_div_zero.rs:6:19 diff --git a/src/tools/clippy/tests/ui/zero_ptr.stderr b/src/tools/clippy/tests/ui/zero_ptr.stderr index 21c2b8c1e35..57679a8ac56 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.stderr +++ b/src/tools/clippy/tests/ui/zero_ptr.stderr @@ -5,6 +5,7 @@ LL | let _ = 0 as *const usize; | ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::null::<usize>()` | = note: `-D clippy::zero-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zero_ptr)]` error: `0 as *mut _` detected --> $DIR/zero_ptr.rs:5:13 diff --git a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr index de122473fd2..c48e19a760a 100644 --- a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr +++ b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr @@ -6,6 +6,7 @@ LL | const CONST_NOT_OK: Option<BTreeMap<String, ()>> = None; | = help: consider using a set instead = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zero_sized_map_values)]` error: map with zero-sized value type --> $DIR/zero_sized_btreemap_values.rs:9:30 diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr index 0d489f45aca..08b1b58f3df 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr @@ -6,6 +6,7 @@ LL | const CONST_NOT_OK: Option<HashMap<String, ()>> = None; | = help: consider using a set instead = note: `-D clippy::zero-sized-map-values` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::zero_sized_map_values)]` error: map with zero-sized value type --> $DIR/zero_sized_hashmap_values.rs:9:30 diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7c17e92d0df..b91d5a958bb 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -66,6 +66,7 @@ string_enum! { JsDocTest => "js-doc-test", MirOpt => "mir-opt", Assembly => "assembly", + CoverageMap => "coverage-map", RunCoverage => "run-coverage", } } @@ -161,6 +162,9 @@ pub struct Config { /// The rust-demangler executable. pub rust_demangler_path: Option<PathBuf>, + /// The coverage-dump executable. + pub coverage_dump_path: Option<PathBuf>, + /// The Python executable to use for LLDB and htmldocck. pub python: String, @@ -639,6 +643,7 @@ pub const UI_EXTENSIONS: &[&str] = &[ UI_STDERR_32, UI_STDERR_16, UI_COVERAGE, + UI_COVERAGE_MAP, ]; pub const UI_STDERR: &str = "stderr"; pub const UI_STDOUT: &str = "stdout"; @@ -649,6 +654,7 @@ pub const UI_STDERR_64: &str = "64bit.stderr"; pub const UI_STDERR_32: &str = "32bit.stderr"; pub const UI_STDERR_16: &str = "16bit.stderr"; pub const UI_COVERAGE: &str = "coverage"; +pub const UI_COVERAGE_MAP: &str = "cov-map"; /// Absolute path to the directory where all output for all tests in the given /// `relative_dir` group should reside. Example: diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 1a765477fe5..619ff9b3221 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -48,6 +48,7 @@ pub fn parse_config(args: Vec<String>) -> Config { .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") + .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") .reqopt("", "python", "path to python to use for doc tests", "PATH") .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") @@ -218,6 +219,7 @@ pub fn parse_config(args: Vec<String>) -> Config { rustc_path: opt_path(matches, "rustc-path"), rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), + coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), jsondoclint_path: matches.opt_str("jsondoclint-path"), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index dd4c59fdff5..670441aacbd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -6,8 +6,8 @@ use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJs use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; -use crate::common::{Pretty, RunCoverage, RunPassValgrind}; -use crate::common::{UI_COVERAGE, UI_RUN_STDERR, UI_RUN_STDOUT}; +use crate::common::{CoverageMap, Pretty, RunCoverage, RunPassValgrind}; +use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP, UI_RUN_STDERR, UI_RUN_STDOUT}; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; @@ -254,6 +254,7 @@ impl<'test> TestCx<'test> { MirOpt => self.run_mir_opt_test(), Assembly => self.run_assembly_test(), JsDocTest => self.run_js_doc_test(), + CoverageMap => self.run_coverage_map_test(), RunCoverage => self.run_coverage_test(), } } @@ -467,6 +468,46 @@ impl<'test> TestCx<'test> { } } + fn run_coverage_map_test(&self) { + let Some(coverage_dump_path) = &self.config.coverage_dump_path else { + self.fatal("missing --coverage-dump"); + }; + + let proc_res = self.compile_test_and_save_ir(); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + drop(proc_res); + + let llvm_ir_path = self.output_base_name().with_extension("ll"); + + let mut dump_command = Command::new(coverage_dump_path); + dump_command.arg(llvm_ir_path); + let proc_res = self.run_command_to_procres(&mut dump_command); + if !proc_res.status.success() { + self.fatal_proc_rec("coverage-dump failed!", &proc_res); + } + + let kind = UI_COVERAGE_MAP; + + let expected_coverage_dump = self.load_expected_output(kind); + let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]); + + let coverage_dump_errors = self.compare_output( + kind, + &actual_coverage_dump, + &expected_coverage_dump, + self.props.compare_output_lines_by_subset, + ); + + if coverage_dump_errors > 0 { + self.fatal_proc_rec( + &format!("{coverage_dump_errors} errors occurred comparing coverage output."), + &proc_res, + ); + } + } + fn run_coverage_test(&self) { let should_run = self.run_if_enabled(); let proc_res = self.compile_test(should_run, Emit::None); @@ -650,6 +691,10 @@ impl<'test> TestCx<'test> { let mut cmd = Command::new(tool_path); configure_cmd_fn(&mut cmd); + self.run_command_to_procres(&mut cmd) + } + + fn run_command_to_procres(&self, cmd: &mut Command) -> ProcRes { let output = cmd.output().unwrap_or_else(|_| panic!("failed to exec `{cmd:?}`")); let proc_res = ProcRes { @@ -2321,9 +2366,11 @@ impl<'test> TestCx<'test> { } } DebugInfo => { /* debuginfo tests must be unoptimized */ } - RunCoverage => { - // Coverage reports are affected by optimization level, and - // the current snapshots assume no optimization by default. + CoverageMap | RunCoverage => { + // Coverage mappings and coverage reports are affected by + // optimization level, so they ignore the optimize-tests + // setting and set an optimization level in their mode's + // compile flags (below) or in per-test `compile-flags`. } _ => { rustc.arg("-O"); @@ -2392,8 +2439,22 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } + CoverageMap => { + rustc.arg("-Cinstrument-coverage"); + // These tests only compile to MIR, so they don't need the + // profiler runtime to be present. + rustc.arg("-Zno-profiler-runtime"); + // Coverage mappings are sensitive to MIR optimizations, and + // the current snapshots assume `opt-level=2` unless overridden + // by `compile-flags`. + rustc.arg("-Copt-level=2"); + } RunCoverage => { rustc.arg("-Cinstrument-coverage"); + // Coverage reports are sometimes sensitive to optimizations, + // and the current snapshots assume no optimization unless + // overridden by `compile-flags`. + rustc.arg("-Copt-level=0"); } RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest | Assembly => { diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml new file mode 100644 index 00000000000..7f14286b5d0 --- /dev/null +++ b/src/tools/coverage-dump/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "coverage-dump" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.71" +leb128 = "0.2.5" +md5 = { package = "md-5" , version = "0.10.5" } +miniz_oxide = "0.7.1" +regex = "1.8.4" +rustc-demangle = "0.1.23" diff --git a/src/tools/coverage-dump/README.md b/src/tools/coverage-dump/README.md new file mode 100644 index 00000000000..e2625d5adf2 --- /dev/null +++ b/src/tools/coverage-dump/README.md @@ -0,0 +1,8 @@ +This tool extracts coverage mapping information from an LLVM IR assembly file +(`.ll`), and prints it in a more human-readable form that can be used for +snapshot tests. + +The output format is mostly arbitrary, so it's OK to change the output as long +as any affected tests are also re-blessed. However, the output should be +consistent across different executions on different platforms, so avoid +printing any information that is platform-specific or non-deterministic. diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs new file mode 100644 index 00000000000..3a5866dea3e --- /dev/null +++ b/src/tools/coverage-dump/src/covfun.rs @@ -0,0 +1,296 @@ +use crate::parser::{unescape_llvm_string_contents, Parser}; +use anyhow::{anyhow, Context}; +use regex::Regex; +use std::collections::HashMap; +use std::fmt::{self, Debug, Write as _}; +use std::sync::OnceLock; + +pub(crate) fn dump_covfun_mappings( + llvm_ir: &str, + function_names: &HashMap<u64, String>, +) -> anyhow::Result<()> { + // Extract function coverage entries from the LLVM IR assembly, and associate + // each entry with its (demangled) name. + let mut covfun_entries = llvm_ir + .lines() + .filter_map(covfun_line_data) + .map(|line_data| (function_names.get(&line_data.name_hash).map(String::as_str), line_data)) + .collect::<Vec<_>>(); + covfun_entries.sort_by(|a, b| { + // Sort entries primarily by name, to help make the order consistent + // across platforms and relatively insensitive to changes. + // (Sadly we can't use `sort_by_key` because we would need to return references.) + Ord::cmp(&a.0, &b.0) + .then_with(|| Ord::cmp(&a.1.is_used, &b.1.is_used)) + .then_with(|| Ord::cmp(a.1.payload.as_slice(), b.1.payload.as_slice())) + }); + + for (name, line_data) in &covfun_entries { + let name = name.unwrap_or("(unknown)"); + let unused = if line_data.is_used { "" } else { " (unused)" }; + println!("Function name: {name}{unused}"); + + let payload: &[u8] = &line_data.payload; + println!("Raw bytes ({len}): 0x{payload:02x?}", len = payload.len()); + + let mut parser = Parser::new(payload); + + let num_files = parser.read_uleb128_u32()?; + println!("Number of files: {num_files}"); + + for i in 0..num_files { + let global_file_id = parser.read_uleb128_u32()?; + println!("- file {i} => global file {global_file_id}"); + } + + let num_expressions = parser.read_uleb128_u32()?; + println!("Number of expressions: {num_expressions}"); + + let mut expression_resolver = ExpressionResolver::new(); + for i in 0..num_expressions { + let lhs = parser.read_simple_term()?; + let rhs = parser.read_simple_term()?; + println!("- expression {i} operands: lhs = {lhs:?}, rhs = {rhs:?}"); + expression_resolver.push_operands(lhs, rhs); + } + + for i in 0..num_files { + let num_mappings = parser.read_uleb128_u32()?; + println!("Number of file {i} mappings: {num_mappings}"); + + for _ in 0..num_mappings { + let (kind, region) = parser.read_mapping_kind_and_region()?; + println!("- {kind:?} at {region:?}"); + + match kind { + // Also print expression mappings in resolved form. + MappingKind::Code(term @ CovTerm::Expression { .. }) + | MappingKind::Gap(term @ CovTerm::Expression { .. }) => { + println!(" = {}", expression_resolver.format_term(term)); + } + // If the mapping is a branch region, print both of its arms + // in resolved form (even if they aren't expressions). + MappingKind::Branch { r#true, r#false } => { + println!(" true = {}", expression_resolver.format_term(r#true)); + println!(" false = {}", expression_resolver.format_term(r#false)); + } + _ => (), + } + } + } + + parser.ensure_empty()?; + println!(); + } + Ok(()) +} + +struct CovfunLineData { + name_hash: u64, + is_used: bool, + payload: Vec<u8>, +} + +/// Checks a line of LLVM IR assembly to see if it contains an `__llvm_covfun` +/// entry, and if so extracts relevant data in a `CovfunLineData`. +fn covfun_line_data(line: &str) -> Option<CovfunLineData> { + let re = { + // We cheat a little bit and match variable names `@__covrec_[HASH]u` + // rather than the section name, because the section name is harder to + // extract and differs across Linux/Windows/macOS. We also extract the + // symbol name hash from the variable name rather than the data, since + // it's easier and both should match. + static RE: OnceLock<Regex> = OnceLock::new(); + RE.get_or_init(|| { + Regex::new( + r#"^@__covrec_(?<name_hash>[0-9A-Z]+)(?<is_used>u)? = .*\[[0-9]+ x i8\] c"(?<payload>[^"]*)".*$"#, + ) + .unwrap() + }) + }; + + let captures = re.captures(line)?; + let name_hash = u64::from_str_radix(&captures["name_hash"], 16).unwrap(); + let is_used = captures.name("is_used").is_some(); + let payload = unescape_llvm_string_contents(&captures["payload"]); + + Some(CovfunLineData { name_hash, is_used, payload }) +} + +// Extra parser methods only needed when parsing `covfun` payloads. +impl<'a> Parser<'a> { + fn read_simple_term(&mut self) -> anyhow::Result<CovTerm> { + let raw_term = self.read_uleb128_u32()?; + CovTerm::decode(raw_term).context("decoding term") + } + + fn read_mapping_kind_and_region(&mut self) -> anyhow::Result<(MappingKind, MappingRegion)> { + let mut kind = self.read_raw_mapping_kind()?; + let mut region = self.read_raw_mapping_region()?; + + const HIGH_BIT: u32 = 1u32 << 31; + if region.end_column & HIGH_BIT != 0 { + region.end_column &= !HIGH_BIT; + kind = match kind { + MappingKind::Code(term) => MappingKind::Gap(term), + // LLVM's coverage mapping reader will actually handle this + // case without complaint, but the result is almost certainly + // a meaningless implementation artifact. + _ => return Err(anyhow!("unexpected base kind for gap region: {kind:?}")), + } + } + + Ok((kind, region)) + } + + fn read_raw_mapping_kind(&mut self) -> anyhow::Result<MappingKind> { + let raw_mapping_kind = self.read_uleb128_u32()?; + if let Some(term) = CovTerm::decode(raw_mapping_kind) { + return Ok(MappingKind::Code(term)); + } + + assert_eq!(raw_mapping_kind & 0b11, 0); + assert_ne!(raw_mapping_kind, 0); + + let (high, is_expansion) = (raw_mapping_kind >> 3, raw_mapping_kind & 0b100 != 0); + if is_expansion { + Ok(MappingKind::Expansion(high)) + } else { + match high { + 0 => unreachable!("zero kind should have already been handled as a code mapping"), + 2 => Ok(MappingKind::Skip), + 4 => { + let r#true = self.read_simple_term()?; + let r#false = self.read_simple_term()?; + Ok(MappingKind::Branch { r#true, r#false }) + } + _ => Err(anyhow!("unknown mapping kind: {raw_mapping_kind:#x}")), + } + } + } + + fn read_raw_mapping_region(&mut self) -> anyhow::Result<MappingRegion> { + let start_line_offset = self.read_uleb128_u32()?; + let start_column = self.read_uleb128_u32()?; + let end_line_offset = self.read_uleb128_u32()?; + let end_column = self.read_uleb128_u32()?; + Ok(MappingRegion { start_line_offset, start_column, end_line_offset, end_column }) + } +} + +/// Enum that can hold a constant zero value, the ID of an physical coverage +/// counter, or the ID (and operation) of a coverage-counter expression. +/// +/// Terms are used as the operands of coverage-counter expressions, as the arms +/// of branch mappings, and as the value of code/gap mappings. +#[derive(Clone, Copy, Debug)] +pub(crate) enum CovTerm { + Zero, + Counter(u32), + Expression(u32, Op), +} + +/// Operator (addition or subtraction) used by an expression. +#[derive(Clone, Copy, Debug)] +pub(crate) enum Op { + Sub, + Add, +} + +impl CovTerm { + pub(crate) fn decode(input: u32) -> Option<Self> { + let (high, tag) = (input >> 2, input & 0b11); + match tag { + 0b00 if high == 0 => Some(Self::Zero), + 0b01 => Some(Self::Counter(high)), + 0b10 => Some(Self::Expression(high, Op::Sub)), + 0b11 => Some(Self::Expression(high, Op::Add)), + // When reading expression operands or branch arms, the LLVM coverage + // mapping reader will always interpret a `0b00` tag as a zero + // term, even when the high bits are non-zero. + // We treat that case as failure instead, so that this code can be + // shared by the full mapping-kind reader as well. + _ => None, + } + } +} + +#[derive(Debug)] +enum MappingKind { + Code(CovTerm), + Gap(CovTerm), + Expansion(u32), + Skip, + // Using raw identifiers here makes the dump output a little bit nicer + // (via the derived Debug), at the expense of making this tool's source + // code a little bit uglier. + Branch { r#true: CovTerm, r#false: CovTerm }, +} + +struct MappingRegion { + /// Offset of this region's start line, relative to the *start line* of + /// the *previous mapping* (or 0). Line numbers are 1-based. + start_line_offset: u32, + /// This region's start column, absolute and 1-based. + start_column: u32, + /// Offset of this region's end line, relative to the *this mapping's* + /// start line. Line numbers are 1-based. + end_line_offset: u32, + /// This region's end column, absolute, 1-based, and exclusive. + /// + /// If the highest bit is set, that bit is cleared and the associated + /// mapping becomes a gap region mapping. + end_column: u32, +} + +impl Debug for MappingRegion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(prev + {}, {}) to (start + {}, {})", + self.start_line_offset, self.start_column, self.end_line_offset, self.end_column + ) + } +} + +/// Helper type that prints expressions in a "resolved" form, so that +/// developers reading the dump don't need to resolve expressions by hand. +struct ExpressionResolver { + operands: Vec<(CovTerm, CovTerm)>, +} + +impl ExpressionResolver { + fn new() -> Self { + Self { operands: Vec::new() } + } + + fn push_operands(&mut self, lhs: CovTerm, rhs: CovTerm) { + self.operands.push((lhs, rhs)); + } + + fn format_term(&self, term: CovTerm) -> String { + let mut output = String::new(); + self.write_term(&mut output, term); + output + } + + fn write_term(&self, output: &mut String, term: CovTerm) { + match term { + CovTerm::Zero => output.push_str("Zero"), + CovTerm::Counter(id) => write!(output, "c{id}").unwrap(), + CovTerm::Expression(id, op) => { + let (lhs, rhs) = self.operands[id as usize]; + let op = match op { + Op::Sub => "-", + Op::Add => "+", + }; + + output.push('('); + self.write_term(output, lhs); + write!(output, " {op} ").unwrap(); + self.write_term(output, rhs); + output.push(')'); + } + } + } +} diff --git a/src/tools/coverage-dump/src/main.rs b/src/tools/coverage-dump/src/main.rs new file mode 100644 index 00000000000..93fed1799e0 --- /dev/null +++ b/src/tools/coverage-dump/src/main.rs @@ -0,0 +1,17 @@ +mod covfun; +mod parser; +mod prf_names; + +fn main() -> anyhow::Result<()> { + use anyhow::Context as _; + + let args = std::env::args().collect::<Vec<_>>(); + + let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?; + let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?; + + let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?; + crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?; + + Ok(()) +} diff --git a/src/tools/coverage-dump/src/parser.rs b/src/tools/coverage-dump/src/parser.rs new file mode 100644 index 00000000000..eefac1a4f94 --- /dev/null +++ b/src/tools/coverage-dump/src/parser.rs @@ -0,0 +1,80 @@ +#[cfg(test)] +mod tests; + +use anyhow::ensure; +use regex::bytes; +use std::sync::OnceLock; + +/// Given the raw contents of a string literal in LLVM IR assembly, decodes any +/// backslash escapes and returns a vector containing the resulting byte string. +pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec<u8> { + let escape_re = { + static RE: OnceLock<bytes::Regex> = OnceLock::new(); + // LLVM IR supports two string escapes: `\\` and `\xx`. + RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap()) + }; + + fn u8_from_hex_digits(digits: &[u8]) -> u8 { + // We know that the input contains exactly 2 hex digits, so these calls + // should never fail. + assert_eq!(digits.len(), 2); + let digits = std::str::from_utf8(digits).unwrap(); + u8::from_str_radix(digits, 16).unwrap() + } + + escape_re + .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| { + let byte = match captures.get(1) { + None => b'\\', + Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()), + }; + [byte] + }) + .into_owned() +} + +pub(crate) struct Parser<'a> { + rest: &'a [u8], +} + +impl<'a> Parser<'a> { + pub(crate) fn new(input: &'a [u8]) -> Self { + Self { rest: input } + } + + pub(crate) fn ensure_empty(self) -> anyhow::Result<()> { + ensure!(self.rest.is_empty(), "unparsed bytes: 0x{:02x?}", self.rest); + Ok(()) + } + + pub(crate) fn read_n_bytes(&mut self, n: usize) -> anyhow::Result<&'a [u8]> { + ensure!(n <= self.rest.len()); + + let (bytes, rest) = self.rest.split_at(n); + self.rest = rest; + Ok(bytes) + } + + pub(crate) fn read_uleb128_u32(&mut self) -> anyhow::Result<u32> { + self.read_uleb128_u64_and_convert() + } + + pub(crate) fn read_uleb128_usize(&mut self) -> anyhow::Result<usize> { + self.read_uleb128_u64_and_convert() + } + + fn read_uleb128_u64_and_convert<T>(&mut self) -> anyhow::Result<T> + where + T: TryFrom<u64> + 'static, + T::Error: std::error::Error + Send + Sync, + { + let mut temp_rest = self.rest; + let raw_value: u64 = leb128::read::unsigned(&mut temp_rest)?; + let converted_value = T::try_from(raw_value)?; + + // Only update `self.rest` if the above steps succeeded, so that the + // parser position can be used for error reporting if desired. + self.rest = temp_rest; + Ok(converted_value) + } +} diff --git a/src/tools/coverage-dump/src/parser/tests.rs b/src/tools/coverage-dump/src/parser/tests.rs new file mode 100644 index 00000000000..a673606b9c4 --- /dev/null +++ b/src/tools/coverage-dump/src/parser/tests.rs @@ -0,0 +1,38 @@ +use super::unescape_llvm_string_contents; + +// WARNING: These tests don't necessarily run in CI, and were mainly used to +// help track down problems when originally developing this tool. +// (The tool is still tested indirectly by snapshot tests that rely on it.) + +// Tests for `unescape_llvm_string_contents`: + +#[test] +fn unescape_empty() { + assert_eq!(unescape_llvm_string_contents(""), &[]); +} + +#[test] +fn unescape_noop() { + let input = "The quick brown fox jumps over the lazy dog."; + assert_eq!(unescape_llvm_string_contents(input), input.as_bytes()); +} + +#[test] +fn unescape_backslash() { + let input = r"\\Hello\\world\\"; + assert_eq!(unescape_llvm_string_contents(input), r"\Hello\world\".as_bytes()); +} + +#[test] +fn unescape_hex() { + let input = r"\01\02\03\04\0a\0b\0C\0D\fd\fE\FF"; + let expected: &[u8] = &[0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d, 0xfd, 0xfe, 0xff]; + assert_eq!(unescape_llvm_string_contents(input), expected); +} + +#[test] +fn unescape_mixed() { + let input = r"\\01.\5c\5c"; + let expected: &[u8] = br"\01.\\"; + assert_eq!(unescape_llvm_string_contents(input), expected); +} diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs new file mode 100644 index 00000000000..d3f7b819e48 --- /dev/null +++ b/src/tools/coverage-dump/src/prf_names.rs @@ -0,0 +1,87 @@ +use crate::parser::{unescape_llvm_string_contents, Parser}; +use anyhow::{anyhow, ensure}; +use regex::Regex; +use std::collections::HashMap; +use std::sync::OnceLock; + +/// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names` +/// entries, decodes them, and creates a table that maps name hash values to +/// (demangled) function names. +pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap<u64, String>> { + fn prf_names_payload(line: &str) -> Option<&str> { + let re = { + // We cheat a little bit and match the variable name `@__llvm_prf_nm` + // rather than the section name, because the section name is harder + // to extract and differs across Linux/Windows/macOS. + static RE: OnceLock<Regex> = OnceLock::new(); + RE.get_or_init(|| { + Regex::new(r#"^@__llvm_prf_nm =.*\[[0-9]+ x i8\] c"([^"]*)".*$"#).unwrap() + }) + }; + + let payload = re.captures(line)?.get(1).unwrap().as_str(); + Some(payload) + } + + /// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to + /// 64 bits as a way to associate data stored in different tables/sections. + fn truncated_md5(bytes: &[u8]) -> u64 { + use md5::{Digest, Md5}; + let mut hasher = Md5::new(); + hasher.update(bytes); + let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap(); + // The truncated hash is explicitly little-endian, regardless of host + // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.) + u64::from_le_bytes(hash) + } + + fn demangle_if_able(symbol_name_bytes: &[u8]) -> anyhow::Result<String> { + // In practice, raw symbol names should always be ASCII. + let symbol_name_str = std::str::from_utf8(symbol_name_bytes)?; + match rustc_demangle::try_demangle(symbol_name_str) { + Ok(d) => Ok(format!("{d:#}")), + // If demangling failed, don't treat it as an error. This lets us + // run the dump tool against non-Rust coverage maps produced by + // `clang`, for testing purposes. + Err(_) => Ok(format!("(couldn't demangle) {symbol_name_str}")), + } + } + + let mut map = HashMap::new(); + + for payload in llvm_ir.lines().filter_map(prf_names_payload).map(unescape_llvm_string_contents) + { + let mut parser = Parser::new(&payload); + let uncompressed_len = parser.read_uleb128_usize()?; + let compressed_len = parser.read_uleb128_usize()?; + + let uncompressed_bytes_vec; + let uncompressed_bytes: &[u8] = if compressed_len == 0 { + // The symbol name bytes are uncompressed, so read them directly. + parser.read_n_bytes(uncompressed_len)? + } else { + // The symbol name bytes are compressed, so read and decompress them. + let compressed_bytes = parser.read_n_bytes(compressed_len)?; + + uncompressed_bytes_vec = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit( + compressed_bytes, + uncompressed_len, + ) + .map_err(|e| anyhow!("{e:?}"))?; + ensure!(uncompressed_bytes_vec.len() == uncompressed_len); + + &uncompressed_bytes_vec + }; + + // Symbol names in the payload are separated by `0x01` bytes. + for raw_name in uncompressed_bytes.split(|&b| b == 0x01) { + let hash = truncated_md5(raw_name); + let demangled = demangle_if_able(raw_name)?; + map.insert(hash, demangled); + } + + parser.ensure_empty()?; + } + + Ok(map) +} diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 06fe668354a..cedc558ebb8 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -156,7 +156,7 @@ program, no matter your host OS. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. You can also use this to test platforms with different properties than your host -platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` +platform. For example `cargo miri test --target s390x-unknown-linux-gnu` will run your test suite on a big-endian target, which is useful for testing endian-sensitive code. @@ -220,20 +220,18 @@ using `--target`! The following targets are tested on CI and thus should always work (to the degree documented below): -- The best-supported target is `x86_64-unknown-linux-gnu`. Miri releases are - blocked on things working with this target. Most other Linux targets should - also work well; we do run the test suite on `i686-unknown-linux-gnu` as a - 32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target, as - well as the ARM targets `aarch64-unknown-linux-gnu` and - `arm-unknown-linux-gnueabi`. -- `x86_64-apple-darwin` should work basically as well as Linux. We also test - `aarch64-apple-darwin`. However, we might ship Miri with a nightly even when - some features on these targets regress. -- `x86_64-pc-windows-msvc` works, but supports fewer features than the Linux and - Apple targets. For example, file system access and concurrency are not - supported on Windows. We also test `i686-pc-windows-msvc`, with the same - reduced feature set. We might ship Miri with a nightly even when some features - on these targets regress. +- All Rust [Tier 1 targets](https://doc.rust-lang.org/rustc/platform-support.html) are supported by + Miri. They are all checked on Miri's CI, and some (at least one per OS) are even checked on every + Rust PR, so the shipped Miri should always work on these targets. +- We also support `s390x-unknown-linux-gnu` as our "big-endian target of choice". +- For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we + make no promises. +- For targets on other operating systems, even basic operations such as printing to the standard + output might not work, and Miri might fail before even reaching the `main` function. + +However, even for targets that we do support, the degree of support for accessing platform APIs +(such as the file system) differs between targets: generally, Linux targets have the best support, +and macOS targets are usually on par. Windows is supported less well. ### Running tests in parallel diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index a3fc68e6758..9e7779e3513 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -116,7 +116,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file ;; x86_64-apple-darwin) - MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture + MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests ;; i686-pc-windows-msvc) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 2948219ad89..b7031d9a3ee 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -510,7 +510,7 @@ impl Command { let mut cmd = cmd!( e.sh, - "rustfmt +{toolchain} --edition=2021 --config-path {config_path} {flags...}" + "rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}" ); eprintln!("$ {cmd} ..."); diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f173cc37e85..b40e7f83f4f 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -dca2d1ff00bf96d244b1bb9a2117a92ec50ac71d +a989e25f1b87949a886eab3da10324d14189fe95 diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 0351f586872..a54bd32cd40 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -615,7 +615,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' ) -> InterpResult<'tcx, Option<Provenance>> { let this = self.eval_context_mut(); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access_align(place.ptr, size, Align::ONE, CheckInAllocMsg::InboundsTest)?; + this.check_ptr_access_align(place.ptr(), size, Align::ONE, CheckInAllocMsg::InboundsTest)?; // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriInterpCx<'mir, 'tcx>, @@ -682,7 +682,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' trace!( "reborrow of size 0: reference {:?} derived from {:?} (pointee {})", new_tag, - place.ptr, + place.ptr(), place.layout.ty, ); // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this @@ -692,7 +692,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' // attempt to use it for a non-zero-sized access. // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. - if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { + if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr()) { log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; // Still give it the new provenance, it got retagged after all. return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); @@ -700,11 +700,11 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' // This pointer doesn't come with an AllocId. :shrug: log_creation(this, None)?; // Provenance unchanged. - return Ok(place.ptr.provenance); + return Ok(place.ptr().provenance); } } - let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr())?; log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; trace!( diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 08b138c68ae..8dd925a0ad8 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -172,7 +172,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' let this = self.eval_context_mut(); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). this.check_ptr_access_align( - place.ptr, + place.ptr(), ptr_size, Align::ONE, CheckInAllocMsg::InboundsTest, @@ -197,7 +197,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' }; trace!("Reborrow of size {:?}", ptr_size); - let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr) { + let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr()) { Ok(data) => { // Unlike SB, we *do* a proper retag for size 0 if can identify the allocation. // After all, the pointer may be lazily initialized outside this initial range. @@ -210,18 +210,18 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' trace!( "reborrow of size 0: reference {:?} derived from {:?} (pointee {})", new_tag, - place.ptr, + place.ptr(), place.layout.ty, ); log_creation(this, None)?; // Keep original provenance. - return Ok(place.ptr.provenance); + return Ok(place.ptr().provenance); } }; log_creation(this, Some((alloc_id, base_offset, parent_prov)))?; let orig_tag = match parent_prov { - ProvenanceExtra::Wildcard => return Ok(place.ptr.provenance), // TODO: handle wildcard pointers + ProvenanceExtra::Wildcard => return Ok(place.ptr().provenance), // TODO: handle wildcard pointers ProvenanceExtra::Concrete(tag) => tag, }; diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 37125337d6f..513cec1f6c3 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -1018,7 +1018,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.check_ptr_access_align( - place.ptr, + place.ptr(), place.layout.size, align, CheckInAllocMsg::MemoryAccessTest, @@ -1031,7 +1031,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual // access will happen later. let (alloc_id, _offset, _prov) = - this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); + this.ptr_try_get_alloc_id(place.ptr()).expect("there are no zero-sized atomic accesses"); if this.get_alloc_mutability(alloc_id)? == Mutability::Not { // FIXME: make this prettier, once these messages have separate title/span/help messages. throw_ub_format!( @@ -1135,7 +1135,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { if let Some(data_race) = &this.machine.data_race { if data_race.race_detecting() { let size = place.layout.size; - let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr())?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); @@ -1143,7 +1143,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { "Atomic op({}) with ordering {:?} on {:?} (size={})", description, &atomic, - place.ptr, + place.ptr(), size.bytes() ); @@ -1186,7 +1186,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { { log::trace!( "Updated atomic memory({:?}, size={}) to {:#?}", - place.ptr, + place.ptr(), size.bytes(), mem_clocks.atomic_ops ); diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 9c11ad85aef..295d86fd240 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -8,6 +8,7 @@ use std::task::Poll; use std::time::{Duration, SystemTime}; use log::trace; +use either::Either; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; @@ -259,8 +260,15 @@ impl VisitTags for Frame<'_, '_, Provenance, FrameExtra<'_>> { return_place.visit_tags(visit); // Locals. for local in locals.iter() { - if let LocalValue::Live(value) = &local.value { - value.visit_tags(visit); + match local.as_mplace_or_imm() { + None => {} + Some(Either::Left((ptr, meta))) => { + ptr.visit_tags(visit); + meta.visit_tags(visit); + } + Some(Either::Right(imm)) => { + imm.visit_tags(visit); + } } } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index c1395468fee..6781b1f6dd3 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -481,7 +481,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: place: &MPlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; if let crate::AllocExtra { weak_memory: Some(alloc_buffers), data_race: Some(alloc_clocks), @@ -512,7 +512,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: init: Scalar<Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; if let ( crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, crate::MiriMachine { data_race: Some(global), threads, .. }, @@ -539,7 +539,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: ) -> InterpResult<'tcx, Scalar<Provenance>> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { if atomic == AtomicReadOrd::SeqCst { global.sc_read(&this.machine.threads); @@ -577,7 +577,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: init: Scalar<Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr())?; if let ( crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, crate::MiriMachine { data_race: Some(global), threads, .. }, @@ -627,7 +627,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_read(&this.machine.threads); } let size = place.layout.size; - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { let buffer = alloc_buffers .get_or_create_store_buffer(alloc_range(base_offset, size), init)?; diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 298c5367522..4f249acda1d 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -376,9 +376,9 @@ pub fn report_error<'tcx, 'mir>( for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); - trace!(" return: {:?}", *frame.return_place); + trace!(" return: {:?}", frame.return_place); for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); + trace!(" local {}: {:?}", i, local); } } diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 88e7d5386db..beb13ebdfe6 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -242,10 +242,7 @@ impl MainThreadState { }, Done => { // Figure out exit code. - let ret_place = MPlaceTy::from_aligned_ptr( - this.machine.main_fn_ret_place.unwrap().ptr, - this.machine.layouts.isize, - ); + let ret_place = this.machine.main_fn_ret_place.clone().unwrap(); let exit_code = this.read_target_isize(&ret_place)?; // Need to call this ourselves since we are not going to return to the scheduler // loop, and we want the main thread TLS to not show up as memory leaks. @@ -308,7 +305,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let arg_type = Ty::new_array(tcx, tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; - ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; + ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr(), size)?; ecx.mark_immutable(&arg_place); argvs.push(arg_place.to_ref(&ecx)); } @@ -332,7 +329,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place)?; ecx.mark_immutable(&argc_place); - ecx.machine.argc = Some(*argc_place); + ecx.machine.argc = Some(argc_place.ptr()); let argv_place = ecx.allocate( ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?, @@ -340,7 +337,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( )?; ecx.write_immediate(argv, &argv_place)?; ecx.mark_immutable(&argv_place); - ecx.machine.argv = Some(*argv_place); + ecx.machine.argv = Some(argv_place.ptr()); } // Store command line as UTF-16 for Windows `GetCommandLineW`. { @@ -351,7 +348,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ty::new_array(tcx, tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; - ecx.machine.cmd_line = Some(*cmd_place); + ecx.machine.cmd_line = Some(cmd_place.ptr()); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { let place = ecx.project_field(&cmd_place, idx)?; @@ -364,7 +361,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; - ecx.machine.main_fn_ret_place = Some(*ret_place); + ecx.machine.main_fn_ret_place = Some(ret_place.clone()); // Call start function. match entry_type { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 844827889a7..0c7e8278147 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -381,7 +381,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let start_addr = place.ptr.addr(); + let start_addr = place.ptr().addr(); let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. @@ -413,7 +413,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let mut visitor = UnsafeCellVisitor { ecx: this, unsafe_cell_action: |place| { - trace!("unsafe_cell_action on {:?}", place.ptr); + trace!("unsafe_cell_action on {:?}", place.ptr()); // We need a size to go on. let unsafe_cell_size = this .size_and_align_of_mplace(place)? @@ -422,7 +422,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .unwrap_or_else(|| place.layout.size); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { - unsafe_cell_action(&place.ptr, unsafe_cell_size) + unsafe_cell_action(&place.ptr(), unsafe_cell_size) } else { Ok(()) } @@ -432,7 +432,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(&place.ptr.offset(size, this)?, Size::ZERO)?; + unsafe_cell_action(&place.ptr().offset(size, this)?, Size::ZERO)?; // Done! return Ok(()); @@ -994,10 +994,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } /// Mark a machine allocation that was just created as immutable. - fn mark_immutable(&mut self, mplace: &MemPlace<Provenance>) { + fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx, Provenance>) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. - let provenance = mplace.ptr.into_pointer_or_addr().unwrap().provenance; + let provenance = mplace.ptr().into_pointer_or_addr().unwrap().provenance; this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap(); } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 03dd9037808..816055cc4fe 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -8,7 +8,6 @@ #![feature(yeet_expr)] #![feature(nonzero_ops)] #![feature(round_ties_even)] -#![feature(os_str_bytes)] #![feature(lint_reasons)] #![feature(trait_upcasting)] // Configure clippy and other lints diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 9d01a04bf4a..80f83180448 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -396,14 +396,14 @@ pub struct MiriMachine<'mir, 'tcx> { pub(crate) env_vars: EnvVars<'tcx>, /// Return place of the main function. - pub(crate) main_fn_ret_place: Option<MemPlace<Provenance>>, + pub(crate) main_fn_ret_place: Option<MPlaceTy<'tcx, Provenance>>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option<MemPlace<Provenance>>, - pub(crate) argv: Option<MemPlace<Provenance>>, - pub(crate) cmd_line: Option<MemPlace<Provenance>>, + pub(crate) argc: Option<Pointer<Option<Provenance>>>, + pub(crate) argv: Option<Pointer<Option<Provenance>>>, + pub(crate) cmd_line: Option<Pointer<Option<Provenance>>>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -670,7 +670,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { ) -> InterpResult<'tcx> { let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; this.write_immediate(*val, &place)?; - Self::add_extern_static(this, name, place.ptr); + Self::add_extern_static(this, name, place.ptr()); Ok(()) } @@ -686,7 +686,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { Self::add_extern_static( this, "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr, + this.machine.env_vars.environ.as_ref().unwrap().ptr(), ); // A couple zero-initialized pointer-sized extern statics. // Most of them are for weak symbols, which we all set to null (indicating that the @@ -703,7 +703,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { Self::add_extern_static( this, "environ", - this.machine.env_vars.environ.as_ref().unwrap().ptr, + this.machine.env_vars.environ.as_ref().unwrap().ptr(), ); } "android" => { @@ -1415,7 +1415,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { local: mir::Local, mplace: &MPlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { - let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr.provenance else { + let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else { panic!("after_local_allocated should only be called on fresh allocations"); }; let local_decl = &ecx.active_thread_stack()[frame].body.local_decls[local]; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index a3297bf819f..c4c9f77fab7 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -89,7 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } this.write_immediate( - Immediate::new_slice(Scalar::from_maybe_pointer(alloc.ptr, this), len, this), + Immediate::new_slice(Scalar::from_maybe_pointer(alloc.ptr(), this), len, this), dest, )?; } diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 3694ea51da6..154a7f69833 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let place = this.project_field(&vars_place, idx)?; this.write_pointer(var, &place)?; } - this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.clone().unwrap())?; + this.write_pointer(vars_place.ptr(), &this.machine.env_vars.environ.clone().unwrap())?; Ok(()) } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 7996e72615f..47cbd4419f3 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -324,7 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Second: functions that return immediately. match this.emulate_foreign_item_by_name(link_name, abi, args, dest)? { EmulateByNameResult::NeedsJumping => { - trace!("{:?}", this.dump_place(**dest)); + trace!("{:?}", this.dump_place(dest)); this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index 8a84b4f51b7..ef9d0710448 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -62,7 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The rest jumps to `ret` immediately. this.emulate_intrinsic_by_name(intrinsic_name, args, dest)?; - trace!("{:?}", this.dump_place(**dest)); + trace!("{:?}", this.dump_place(dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index f08f0aad5e7..f6e76545a4d 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -24,7 +24,7 @@ pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> { } #[cfg(not(unix))] pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> { - // We cannot use `from_os_str_bytes_unchecked` here since we can't trust `bytes`. + // We cannot use `from_encoded_bytes_unchecked` here since we can't trust `bytes`. let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(OsStr::new(s)) @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ptr: Pointer<Option<Provenance>>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let bytes = os_str.as_os_str_bytes(); + let bytes = os_str.as_encoded_bytes(); self.eval_context_mut().write_c_str(bytes, ptr, size) } @@ -143,9 +143,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; - let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); + let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr(), size).unwrap(); assert!(written); - Ok(arg_place.ptr) + Ok(arg_place.ptr()) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. @@ -160,9 +160,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = - self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap(); + self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false).unwrap(); assert!(written); - Ok(arg_place.ptr) + Ok(arg_place.ptr()) } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. diff --git a/src/tools/miri/src/shims/unix/android/dlsym.rs b/src/tools/miri/src/shims/unix/android/dlsym.rs index b0c9d729c9d..451bc0bd5e1 100644 --- a/src/tools/miri/src/shims/unix/android/dlsym.rs +++ b/src/tools/miri/src/shims/unix/android/dlsym.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - log::trace!("{:?}", this.dump_place(**dest)); + log::trace!("{:?}", this.dump_place(dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 3a480190535..865f01931f7 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -597,7 +597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_pointer(buf, &pw_dir)?; if written { - this.write_pointer(pwd.ptr, &result)?; + this.write_pointer(pwd.ptr(), &result)?; this.write_null(dest)?; } else { this.write_null(&result)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index beaef22075b..8963dfb97a6 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1344,7 +1344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let mut name = dir_entry.file_name(); // not a Path as there are no separators! name.push("\0"); // Add a NUL terminator - let name_bytes = name.as_os_str_bytes(); + let name_bytes = name.as_encoded_bytes(); let name_len = u64::try_from(name_bytes.len()).unwrap(); let dirent64_layout = this.libc_ty_layout("dirent64"); @@ -1439,7 +1439,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str( &file_name, - name_place.ptr, + name_place.ptr(), name_place.layout.size.bytes(), )?; let file_name_len = file_name_buf_len.checked_sub(1).unwrap(); @@ -1698,7 +1698,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget, ); - let mut path_bytes = resolved.as_os_str_bytes(); + let mut path_bytes = resolved.as_encoded_bytes(); let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { path_bytes = &path_bytes[..bufsize] diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 0474c9fd90a..7d15abfbfb2 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -35,7 +35,7 @@ pub fn futex<'tcx>( let thread = this.get_active_thread(); // This is a vararg function so we have to bring our own type for this pointer. let addr = MPlaceTy::from_aligned_ptr(addr, this.machine.layouts.i32); - let addr_usize = addr.ptr.addr().bytes(); + let addr_usize = addr.ptr().addr().bytes(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG"); let futex_wait = this.eval_libc_i32("FUTEX_WAIT"); @@ -90,7 +90,7 @@ pub fn futex<'tcx>( &this.read_immediate(&args[3])?, this.libc_ty_layout("timespec"), )?; - let timeout_time = if this.ptr_is_null(timeout.ptr)? { + let timeout_time = if this.ptr_is_null(timeout.ptr())? { None } else { let realtime = op & futex_realtime == futex_realtime; diff --git a/src/tools/miri/src/shims/unix/macos/dlsym.rs b/src/tools/miri/src/shims/unix/macos/dlsym.rs index 9177ecefe12..63ad680de60 100644 --- a/src/tools/miri/src/shims/unix/macos/dlsym.rs +++ b/src/tools/miri/src/shims/unix/macos/dlsym.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - trace!("{:?}", this.dump_place(**dest)); + trace!("{:?}", this.dump_place(dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index f073daab8ed..3524fd70bcf 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -91,7 +91,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .environ .as_ref() .expect("machine must be initialized") - .ptr, + .ptr(), dest, )?; } @@ -113,14 +113,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "_NSGetArgc" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( - this.machine.argc.expect("machine must be initialized").ptr, + this.machine.argc.expect("machine must be initialized"), dest, )?; } "_NSGetArgv" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( - this.machine.argv.expect("machine must be initialized").ptr, + this.machine.argv.expect("machine must be initialized"), dest, )?; } diff --git a/src/tools/miri/src/shims/windows/dlsym.rs b/src/tools/miri/src/shims/windows/dlsym.rs index 7e2051fc98a..e5afee35905 100644 --- a/src/tools/miri/src/shims/windows/dlsym.rs +++ b/src/tools/miri/src/shims/windows/dlsym.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - trace!("{:?}", this.dump_place(**dest)); + trace!("{:?}", this.dump_place(dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index cb90ed57ffe..28999268ba0 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?; // Initialize with `0`. this.write_bytes_ptr( - system_info.ptr, + system_info.ptr(), iter::repeat(0u8).take(system_info.layout.size.bytes_usize()), )?; // Set selected fields. @@ -235,7 +235,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "GetCommandLineW" => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_pointer( - this.machine.cmd_line.expect("machine must be initialized").ptr, + this.machine.cmd_line.expect("machine must be initialized"), dest, )?; } diff --git a/src/tools/miri/src/tag_gc.rs b/src/tools/miri/src/tag_gc.rs index cefdcc2b5b8..3cccdd36353 100644 --- a/src/tools/miri/src/tag_gc.rs +++ b/src/tools/miri/src/tag_gc.rs @@ -1,3 +1,5 @@ +use either::Either; + use rustc_data_structures::fx::FxHashSet; use crate::*; @@ -81,46 +83,33 @@ impl VisitTags for MemPlaceMeta<Provenance> { } } -impl VisitTags for MemPlace<Provenance> { +impl VisitTags for ImmTy<'_, Provenance> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - let MemPlace { ptr, meta } = self; - ptr.visit_tags(visit); - meta.visit_tags(visit); + (**self).visit_tags(visit) } } impl VisitTags for MPlaceTy<'_, Provenance> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - (**self).visit_tags(visit) - } -} - -impl VisitTags for Place<Provenance> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self { - Place::Ptr(p) => p.visit_tags(visit), - Place::Local { .. } => { - // Will be visited as part of the stack frame. - } - } + self.ptr().visit_tags(visit); + self.meta().visit_tags(visit); } } impl VisitTags for PlaceTy<'_, Provenance> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - (**self).visit_tags(visit) + match self.as_mplace_or_local() { + Either::Left(mplace) => mplace.visit_tags(visit), + Either::Right(_) => (), + } } } -impl VisitTags for Operand<Provenance> { +impl VisitTags for OpTy<'_, Provenance> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self { - Operand::Immediate(imm) => { - imm.visit_tags(visit); - } - Operand::Indirect(p) => { - p.visit_tags(visit); - } + match self.as_mplace_or_imm() { + Either::Left(mplace) => mplace.visit_tags(visit), + Either::Right(imm) => imm.visit_tags(visit), } } } diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs index 6ab73569c63..6ab73569c63 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr index 133e4b2c16a..21e403b47f8 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr1.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr1.rs:LL:CC + --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC | LL | g(0usize as *const i32) | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | g(0usize as *const i32) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs new file mode 100644 index 00000000000..7cdc15c6094 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs @@ -0,0 +1,28 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that +// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer +// type. That way we never get an "invalid value constructed" error inside the function, it can +// only possibly be detected when the return value is passed to the caller. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn f() -> NonZeroU32 { + mir! { + { + let tmp = ptr::addr_of_mut!(RET); + let ptr = tmp as *mut u32; + *ptr = 0; + Return() + } + } +} + +fn main() { + let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) }; + // There's a NonZeroU32-to-u32 transmute happening here + f(); //~ERROR: expected something greater or equal to 1 +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr new file mode 100644 index 00000000000..ccfb8890939 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + | +LL | f(); + | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs new file mode 100644 index 00000000000..ee80186d4b5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -0,0 +1,34 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +fn f(c: u32) { + println!("{c}"); +} + +// Call that function in a bad way, with an invalid NonZeroU32, but without +// ever materializing this as a NonZeroU32 value outside the call itself. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn call(f: fn(NonZeroU32)) { + mir! { + let _res: (); + { + let c = 0; + let tmp = ptr::addr_of!(c); + let ptr = tmp as *const NonZeroU32; + // The call site now is a NonZeroU32-to-u32 transmute. + Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1 + } + retblock = { + Return() + } + } +} + +fn main() { + let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) }; + call(f); +} diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr new file mode 100644 index 00000000000..234c2804008 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | Call(_res = f(*ptr), retblock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC +note: inside `main` + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | call(f); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs index 64ddb563be5..64ddb563be5 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr index 21001f2b460..bd9866acbd4 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr2.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr2.rs:LL:CC + --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC | LL | let _x = g(); | ^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | let _x = g(); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + = note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index dc1e1f0ba8d..08be29115ca 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -1,9 +1,7 @@ -#![feature(portable_simd)] use std::mem; use std::num; -use std::simd; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] struct Zst; fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) { @@ -33,7 +31,7 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) { } /// Ensure that `T` is compatible with various repr(transparent) wrappers around `T`. -fn test_abi_newtype<T: Copy>(t: T) { +fn test_abi_newtype<T: Copy + Default>() { #[repr(transparent)] #[derive(Copy, Clone)] struct Wrapper1<T>(T); @@ -47,6 +45,7 @@ fn test_abi_newtype<T: Copy>(t: T) { #[derive(Copy, Clone)] struct Wrapper3<T>(Zst, T, [u8; 0]); + let t = T::default(); test_abi_compat(t, Wrapper1(t)); test_abi_compat(t, Wrapper2(t, ())); test_abi_compat(t, Wrapper2a((), t)); @@ -56,8 +55,7 @@ fn test_abi_newtype<T: Copy>(t: T) { fn main() { // Here we check: - // - unsigned vs signed integer is allowed - // - u32/i32 vs char is allowed + // - u32 vs char is allowed // - u32 vs NonZeroU32/Option<NonZeroU32> is allowed // - reference vs raw pointer is allowed // - references to things of the same size and alignment are allowed @@ -65,27 +63,24 @@ fn main() { // these would be stably guaranteed. Code that relies on this is equivalent to code that relies // on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields // of a struct (even with `repr(C)`) will not always be accepted by Miri. - test_abi_compat(0u32, 0i32); - test_abi_compat(simd::u32x8::splat(1), simd::i32x8::splat(1)); + // Note that `bool` and `u8` are *not* compatible, at least on x86-64! + // One of them has `arg_ext: Zext`, the other does not. + // Similarly, `i32` and `u32` are not compatible on s390x due to different `arg_ext`. test_abi_compat(0u32, 'x'); - test_abi_compat(0i32, 'x'); test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); test_abi_compat(&0u32, &0u32 as *const u32); test_abi_compat(&0u32, &([true; 4], [0u32; 0])); - // Note that `bool` and `u8` are *not* compatible, at least on x86-64! - // One of them has `arg_ext: Zext`, the other does not. // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible // with the wrapped field. - test_abi_newtype(()); - // FIXME: this still fails! test_abi_newtype(Zst); - test_abi_newtype(0u32); - test_abi_newtype(0f32); - test_abi_newtype((0u32, 1u32, 2u32)); - // FIXME: skipping the array tests on mips64 due to https://github.com/rust-lang/rust/issues/115404 - if !cfg!(target_arch = "mips64") { - test_abi_newtype([0u32, 1u32, 2u32]); - test_abi_newtype([0i32; 0]); - } + test_abi_newtype::<()>(); + test_abi_newtype::<Zst>(); + test_abi_newtype::<u32>(); + test_abi_newtype::<f32>(); + test_abi_newtype::<(u8, u16, f32)>(); + test_abi_newtype::<[u8; 0]>(); + test_abi_newtype::<[u32; 0]>(); + test_abi_newtype::<[u32; 2]>(); + test_abi_newtype::<[u32; 32]>(); } diff --git a/src/tools/miri/tests/utils/fs.rs b/src/tools/miri/tests/utils/fs.rs index 47904926b48..0242a228068 100644 --- a/src/tools/miri/tests/utils/fs.rs +++ b/src/tools/miri/tests/utils/fs.rs @@ -6,7 +6,7 @@ use super::miri_extern; pub fn host_to_target_path(path: OsString) -> PathBuf { use std::ffi::{CStr, CString}; - // Once into_os_str_bytes is stable we can use it here. + // Once into_encoded_bytes is stable we can use it here. // (Unstable features would need feature flags in each test...) let path = CString::new(path.into_string().unwrap()).unwrap(); let mut out = Vec::with_capacity(1024); diff --git a/src/tools/opt-dist/src/environment/windows.rs b/src/tools/opt-dist/src/environment/windows.rs index 8a9733d6496..79399391798 100644 --- a/src/tools/opt-dist/src/environment/windows.rs +++ b/src/tools/opt-dist/src/environment/windows.rs @@ -1,8 +1,10 @@ use crate::environment::Environment; use crate::exec::cmd; use crate::utils::io::move_directory; +use crate::utils::retry_action; use camino::Utf8PathBuf; use std::io::Cursor; +use std::time::Duration; use zip::ZipArchive; pub(super) struct WindowsEnvironment { @@ -42,8 +44,16 @@ impl Environment for WindowsEnvironment { // rustc-perf version from 2023-05-30 const PERF_COMMIT: &str = "8b2ac3042e1ff2c0074455a0a3618adef97156b1"; - let url = format!("https://github.com/rust-lang/rustc-perf/archive/{PERF_COMMIT}.zip"); - let response = reqwest::blocking::get(url)?.error_for_status()?.bytes()?.to_vec(); + let url = format!("https://ci-mirrors.rust-lang.org/rustc/rustc-perf-{PERF_COMMIT}.zip"); + let client = reqwest::blocking::Client::builder() + .timeout(Duration::from_secs(60 * 2)) + .connect_timeout(Duration::from_secs(60 * 2)) + .build()?; + let response = retry_action( + || Ok(client.get(&url).send()?.error_for_status()?.bytes()?.to_vec()), + "Download rustc-perf archive", + 5, + )?; let mut archive = ZipArchive::new(Cursor::new(response))?; archive.extract(self.rustc_perf_dir())?; diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs index 9a3df15e302..2af28077ed1 100644 --- a/src/tools/opt-dist/src/utils/mod.rs +++ b/src/tools/opt-dist/src/utils/mod.rs @@ -3,6 +3,7 @@ pub mod io; use crate::environment::Environment; use crate::utils::io::{delete_directory, get_files_from_dir}; use humansize::{format_size, BINARY}; +use std::time::Duration; use sysinfo::{DiskExt, RefreshKind, System, SystemExt}; pub fn format_env_variables() -> String { @@ -70,6 +71,24 @@ pub fn with_log_group<F: FnOnce() -> R, R>(group: &str, func: F) -> R { } } +#[allow(unused)] +pub fn retry_action<F: Fn() -> anyhow::Result<R>, R>( + action: F, + name: &str, + count: u64, +) -> anyhow::Result<R> { + for attempt in 0..count { + match action() { + Ok(result) => return Ok(result), + Err(error) => { + log::error!("Failed to perform action `{name}`, attempt #{attempt}: {error:?}"); + std::thread::sleep(Duration::from_secs(5)); + } + } + } + Err(anyhow::anyhow!("Failed to perform action `{name}` after {count} retries")) +} + fn is_in_ci() -> bool { std::env::var("GITHUB_ACTIONS").is_ok() } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index d815d69d6ba..3f94bb29933 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -268,7 +268,7 @@ impl ParseSess { let source_file = self.parse_sess.source_map().lookup_char_pos(span.lo()).file; SnippetProvider::new( source_file.start_pos, - source_file.end_pos, + source_file.end_position(), Lrc::clone(source_file.src.as_ref().unwrap()), ) } diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs new file mode 100644 index 00000000000..b1475ee7931 --- /dev/null +++ b/tests/codegen/debuginfo-inline-callsite-location.rs @@ -0,0 +1,28 @@ +// compile-flags: -g -O + +// Check that each inline call site for the same function uses the same "sub-program" so that LLVM +// can correctly merge the debug info if it merges the inlined code (e.g., for merging of tail +// calls to panic. + +// CHECK: tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E +// CHECK-SAME: !dbg ![[#first_dbg:]] +// CHECK: tail call void @_ZN4core9panicking5panic17h{{([0-9a-z]{16})}}E +// CHECK-SAME: !dbg ![[#second_dbg:]] + +// CHECK-DAG: ![[#func_dbg:]] = distinct !DISubprogram(name: "unwrap<i32>" +// CHECK-DAG: ![[#first_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]], +// CHECK: ![[#second_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]], +// CHECK: ![[#first_dbg]] = !DILocation(line: [[#]] +// CHECK-SAME: scope: ![[#first_scope]], inlinedAt: ![[#]]) +// CHECK: ![[#second_dbg]] = !DILocation(line: [[#]] +// CHECK-SAME: scope: ![[#second_scope]], inlinedAt: ![[#]]) + +#![crate_type = "lib"] + +#[no_mangle] +extern "C" fn add_numbers(x: &Option<i32>, y: &Option<i32>) -> i32 { + let x1 = x.unwrap(); + let y1 = y.unwrap(); + + x1 + y1 +} diff --git a/tests/codegen/lib-optimizations/iter-sum.rs b/tests/codegen/lib-optimizations/iter-sum.rs new file mode 100644 index 00000000000..ff7ca6ef6c1 --- /dev/null +++ b/tests/codegen/lib-optimizations/iter-sum.rs @@ -0,0 +1,15 @@ +// ignore-debug: the debug assertions get in the way +// compile-flags: -O +// only-x86_64 (vectorization varies between architectures) +#![crate_type = "lib"] + + +// Ensure that slice + take + sum gets vectorized. +// Currently this relies on the slice::Iter::try_fold implementation +// CHECK-LABEL: @slice_take_sum +#[no_mangle] +pub fn slice_take_sum(s: &[u64], l: usize) -> u64 { + // CHECK: vector.body: + // CHECK: ret + s.iter().take(l).sum() +} diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs index b140fc719da..c5974248bb3 100644 --- a/tests/codegen/repr/transparent.rs +++ b/tests/codegen/repr/transparent.rs @@ -43,7 +43,6 @@ pub extern "C" fn test_WithZst(_: WithZst) -> WithZst { loop {} } #[repr(transparent)] pub struct WithZeroSizedArray(*const f32, [i8; 0]); -// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever. // CHECK: define{{.*}}ptr @test_WithZeroSizedArray(ptr noundef %_1) #[no_mangle] pub extern "C" fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} } diff --git a/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs new file mode 100644 index 00000000000..a70ef7751b6 --- /dev/null +++ b/tests/codegen/sanitizer/address-sanitizer-globals-tracking.rs @@ -0,0 +1,43 @@ +// Verifies that AddressSanitizer symbols show up as expected in LLVM IR with `-Zsanitizer`. +// This is a regression test for https://github.com/rust-lang/rust/issues/113404 +// +// Notes about the `compile-flags` below: +// +// * The original issue only reproed with LTO - this is why this angle has +// extra test coverage via different `revisions` +// * To observe the failure/repro at LLVM-IR level we need to use `staticlib` +// which necessitates `-C prefer-dynamic=false` - without the latter flag, +// we would have run into "cannot prefer dynamic linking when performing LTO". +// +// The test is restricted to `only-linux`, because the sanitizer-related instrumentation is target +// specific. In particular, `___asan_globals_registered` is only used in the +// `InstrumentGlobalsELF` and `InstrumentGlobalsMachO` code paths. The `only-linux` filter is +// narrower than really needed (i.e. narrower than ELF-or-MachO), but this seems ok - having a +// linux-only regression test should be sufficient here. +// +// needs-sanitizer-address +// only-linux +// +// revisions:ASAN ASAN-FAT-LTO +//[ASAN] compile-flags: -Zsanitizer=address +//[ASAN-FAT-LTO] compile-flags: -Zsanitizer=address -Cprefer-dynamic=false -Clto=fat + +#![crate_type="staticlib"] + +// The test below mimics `CACHED_POW10` from `library/core/src/num/flt2dec/strategy/grisu.rs` which +// (because of incorrect handling of `___asan_globals_registered` during LTO) was incorrectly +// reported as an ODR violation in https://crbug.com/1459233#c1. Before this bug was fixed, +// `___asan_globals_registered` would show up as `internal global i64` rather than `common hidden +// global i64`. (The test expectations ignore the exact type because on `arm-android` the type +// is `i32` rather than `i64`.) +// +// CHECK: @___asan_globals_registered = common hidden global +// CHECK: @__start_asan_globals = extern_weak hidden global +// CHECK: @__stop_asan_globals = extern_weak hidden global +#[no_mangle] +pub static CACHED_POW10: [(u64, i16, i16); 4] = [ + (0xe61acf033d1a45df, -1087, -308), + (0xab70fe17c79ac6ca, -1060, -300), + (0xff77b1fcbebcdc4f, -1034, -292), + (0xbe5691ef416bd60c, -1007, -284), +]; diff --git a/tests/coverage-map/README.md b/tests/coverage-map/README.md new file mode 100644 index 00000000000..60d1352cd64 --- /dev/null +++ b/tests/coverage-map/README.md @@ -0,0 +1,13 @@ +The tests in `./status-quo` were copied from `tests/run-coverage` in order to +capture the current behavior of the instrumentor on non-trivial programs. +The actual mappings have not been closely inspected. + +## Maintenance note + +These tests can be sensitive to small changes in MIR spans or MIR control flow, +especially in HIR-to-MIR lowering or MIR optimizations. + +If you haven't touched the coverage code directly, and the `run-coverage` test +suite still works, then it should usually be OK to just `--bless` these +coverage mapping tests as necessary, without worrying too much about the exact +changes. diff --git a/tests/coverage-map/if.cov-map b/tests/coverage-map/if.cov-map new file mode 100644 index 00000000000..3cedb5ffbec --- /dev/null +++ b/tests/coverage-map/if.cov-map @@ -0,0 +1,15 @@ +Function name: if::main +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) +- Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 1, 2) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage-map/if.rs b/tests/coverage-map/if.rs new file mode 100644 index 00000000000..ed3f69bdc98 --- /dev/null +++ b/tests/coverage-map/if.rs @@ -0,0 +1,9 @@ +// compile-flags: --edition=2021 + +fn main() { + let cond = std::env::args().len() == 1; + if cond { + println!("true"); + } + println!("done"); +} diff --git a/tests/coverage-map/long_and_wide.cov-map b/tests/coverage-map/long_and_wide.cov-map new file mode 100644 index 00000000000..97aebf9b18a --- /dev/null +++ b/tests/coverage-map/long_and_wide.cov-map @@ -0,0 +1,32 @@ +Function name: long_and_wide::far_function +Raw bytes (10): 0x[01, 01, 00, 01, 01, 96, 01, 01, 00, 15] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 150, 1) to (start + 0, 21) + +Function name: long_and_wide::long_function +Raw bytes (10): 0x[01, 01, 00, 01, 01, 10, 01, 84, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 16, 1) to (start + 132, 2) + +Function name: long_and_wide::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 7, 1) to (start + 4, 2) + +Function name: long_and_wide::wide_function +Raw bytes (10): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 8b, 01] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 139) + diff --git a/tests/coverage-map/long_and_wide.rs b/tests/coverage-map/long_and_wide.rs new file mode 100644 index 00000000000..a7cbcd48027 --- /dev/null +++ b/tests/coverage-map/long_and_wide.rs @@ -0,0 +1,150 @@ +// compile-flags: --edition=2021 +// ignore-tidy-linelength + +// This file deliberately contains line and column numbers larger than 127, +// to verify that `coverage-dump`'s ULEB128 parser can handle them. + +fn main() { + wide_function(); + long_function(); + far_function(); +} + +#[rustfmt::skip] +fn wide_function() { /* */ (); } + +fn long_function() { + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // +} + +fn far_function() {} diff --git a/tests/coverage-map/status-quo/abort.cov-map b/tests/coverage-map/status-quo/abort.cov-map new file mode 100644 index 00000000000..45d3795eff8 --- /dev/null +++ b/tests/coverage-map/status-quo/abort.cov-map @@ -0,0 +1,57 @@ +Function name: abort::main +Raw bytes (105): 0x[01, 01, 12, 01, 47, 05, 09, 03, 0d, 42, 11, 03, 0d, 11, 3e, 42, 11, 03, 0d, 3b, 15, 11, 3e, 42, 11, 03, 0d, 15, 36, 3b, 15, 11, 3e, 42, 11, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 42, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 3e, 02, 0a, 00, 0b, 3b, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 36, 00, 31, 00, 32, 33, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 47, 01, 09, 00, 17, 0d, 02, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 18 +- expression 0 operands: lhs = Counter(0), rhs = Expression(17, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Expression(16, Sub), rhs = Counter(4) +- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(4), rhs = Expression(15, Sub) +- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(4) +- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 8 operands: lhs = Expression(14, Add), rhs = Counter(5) +- expression 9 operands: lhs = Counter(4), rhs = Expression(15, Sub) +- expression 10 operands: lhs = Expression(16, Sub), rhs = Counter(4) +- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 12 operands: lhs = Counter(5), rhs = Expression(13, Sub) +- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(5) +- expression 14 operands: lhs = Counter(4), rhs = Expression(15, Sub) +- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(4) +- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 17 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24) + = (c0 + (c1 + c2)) +- Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25) + = ((c0 + (c1 + c2)) - c3) +- Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10) +- Code(Expression(15, Sub)) at (prev + 2, 10) to (start + 0, 11) + = (((c0 + (c1 + c2)) - c3) - c4) +- Code(Expression(14, Add)) at (prev + 2, 12) to (start + 0, 25) + = (c4 + (((c0 + (c1 + c2)) - c3) - c4)) +- Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49) +- Code(Expression(13, Sub)) at (prev + 0, 49) to (start + 0, 50) + = ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5) +- Code(Expression(12, Add)) at (prev + 4, 12) to (start + 0, 25) + = (c5 + ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5)) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49) +- Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50) +- Code(Expression(17, Add)) at (prev + 1, 9) to (start + 0, 23) + = (c1 + c2) +- Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2) + +Function name: abort::might_abort +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) +- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36) +- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) + = (c0 - c1) + diff --git a/tests/coverage-map/status-quo/abort.rs b/tests/coverage-map/status-quo/abort.rs new file mode 100644 index 00000000000..98264bdc1af --- /dev/null +++ b/tests/coverage-map/status-quo/abort.rs @@ -0,0 +1,66 @@ +#![feature(c_unwind)] +#![allow(unused_assignments)] + +extern "C" fn might_abort(should_abort: bool) { + if should_abort { + println!("aborting..."); + panic!("panics and aborts"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown < 5 { + might_abort(false); + } + // See discussion (below the `Notes` section) on coverage results for the closing brace. + if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + // For the following example, the closing brace is the last character on the line. + // This shows the character after the closing brace is highlighted, even if that next + // character is a newline. + if countdown < 5 { might_abort(false); } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests +// `panic_unwind.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. +// 3. The test does not invoke the abort. By executing to a successful completion, the coverage +// results show where the program did and did not execute. +// 4. If the program actually aborted, the coverage counters would not be saved (which "works as +// intended"). Coverage results would show no executed coverage regions. +// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status +// (on Linux at least). + +/* + +Expect the following coverage results: + +```text + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } +``` + +This is actually correct. + +The condition `countdown < 5` executed 10 times (10 loop iterations). + +It evaluated to `true` 4 times, and executed the `might_abort()` call. + +It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit +`else`, the coverage implementation injects a counter, at the character immediately after the `if`s +closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the +non-true condition. + +As another example of why this is important, say the condition was `countdown < 50`, which is always +`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. +The closing brace would have a count of `0`, highlighting the missed coverage. +*/ diff --git a/tests/coverage-map/status-quo/assert.cov-map b/tests/coverage-map/status-quo/assert.cov-map new file mode 100644 index 00000000000..dd413123de7 --- /dev/null +++ b/tests/coverage-map/status-quo/assert.cov-map @@ -0,0 +1,40 @@ +Function name: assert::main +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 8 +- expression 0 operands: lhs = Counter(0), rhs = Expression(6, Add) +- expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(4) +- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(1) +- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(4) +- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 27) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24) + = (c0 + (c1 + (c2 + c3))) +- Code(Expression(5, Sub)) at (prev + 1, 12) to (start + 0, 26) + = ((c0 + (c1 + (c2 + c3))) - c4) +- Code(Counter(1)) at (prev + 0, 27) to (start + 2, 10) +- Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32) + = (((c0 + (c1 + (c2 + c3))) - c4) - c1) +- Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10) +- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) + = (c1 + (c2 + c3)) +- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) + +Function name: assert::might_fail_assert +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 15) +- Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61) + = (c0 - c1) +- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) + diff --git a/tests/coverage-map/status-quo/assert.rs b/tests/coverage-map/status-quo/assert.rs new file mode 100644 index 00000000000..85e6662a6ad --- /dev/null +++ b/tests/coverage-map/status-quo/assert.rs @@ -0,0 +1,32 @@ +#![allow(unused_assignments)] +// failure-status: 101 + +fn might_fail_assert(one_plus_one: u32) { + println!("does 1 + 1 = {}?", one_plus_one); + assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_fail_assert(3); + } else if countdown < 5 { + might_fail_assert(2); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test +// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or +// related `assert_*!()` macro. +// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce +// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to +// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). +// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test +// (and in many other coverage tests). The `Assert` terminator is typically generated by the +// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/tests/coverage-map/status-quo/async.cov-map b/tests/coverage-map/status-quo/async.cov-map new file mode 100644 index 00000000000..5f28252ef80 --- /dev/null +++ b/tests/coverage-map/status-quo/async.cov-map @@ -0,0 +1,340 @@ +Function name: async::c +Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 25) + +Function name: async::c::{closure#0} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 05, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 5, 25) to (start + 1, 14) +- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: async::d +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0d, 01, 00, 14] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 20) + +Function name: async::d::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0d, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 13, 20) to (start + 0, 25) + +Function name: async::e (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 14] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 20) + +Function name: async::e::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 15, 20) to (start + 0, 25) + +Function name: async::executor::block_on::<core::pin::Pin<&mut async::i::{closure#0}>> +Raw bytes (44): 0x[01, 01, 05, 0b, 05, 01, 05, 01, 05, 02, 00, 02, 00, 06, 01, 6e, 05, 0a, 36, 02, 0d, 20, 00, 23, 0b, 00, 27, 00, 49, 0f, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 13, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 4 operands: lhs = Expression(0, Sub), rhs = Zero +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 110, 5) to (start + 10, 54) +- Code(Expression(0, Sub)) at (prev + 13, 32) to (start + 0, 35) + = ((c0 + c1) - c1) +- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73) + = (c0 + c1) +- Code(Expression(3, Add)) at (prev + 1, 23) to (start + 0, 26) + = (((c0 + c1) - c1) + Zero) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6) + = (((c0 + c1) - c1) + Zero) + +Function name: async::executor::block_on::VTABLE::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 72, 11, 00, 33] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 114, 17) to (start + 0, 51) + +Function name: async::executor::block_on::VTABLE::{closure#1} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 73, 11, 00, 33] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 115, 17) to (start + 0, 51) + +Function name: async::executor::block_on::VTABLE::{closure#2} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 74, 11, 00, 33] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 116, 17) to (start + 0, 51) + +Function name: async::executor::block_on::VTABLE::{closure#3} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 75, 11, 00, 13] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 117, 17) to (start + 0, 19) + +Function name: async::f +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 14] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 20) + +Function name: async::f::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 17, 20) to (start + 0, 25) + +Function name: async::foo (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 1e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 30) + +Function name: async::foo::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 1e, 00, 2d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 19, 30) to (start + 0, 45) + +Function name: async::g +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 17] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 23) + +Function name: async::g::{closure#0} (unused) +Raw bytes (69): 0x[01, 01, 00, 0d, 00, 15, 17, 01, 0c, 00, 02, 09, 00, 0a, 01, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 13 +- Code(Zero) at (prev + 21, 23) to (start + 1, 12) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 23) +- Code(Zero) at (prev + 0, 27) to (start + 0, 28) +- Code(Zero) at (prev + 0, 32) to (start + 0, 34) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) +- Code(Zero) at (prev + 0, 14) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 23) +- Code(Zero) at (prev + 0, 27) to (start + 0, 28) +- Code(Zero) at (prev + 0, 32) to (start + 0, 34) +- Code(Zero) at (prev + 1, 14) to (start + 0, 16) +- Code(Zero) at (prev + 2, 1) to (start + 0, 2) + +Function name: async::h +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 16] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 22) + +Function name: async::h::{closure#0} (unused) +Raw bytes (44): 0x[01, 01, 00, 08, 00, 1d, 16, 03, 0c, 00, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 00, 00, 14, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 8 +- Code(Zero) at (prev + 29, 22) to (start + 3, 12) +- Code(Zero) at (prev + 4, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) +- Code(Zero) at (prev + 0, 20) to (start + 0, 25) +- Code(Zero) at (prev + 0, 26) to (start + 0, 27) +- Code(Zero) at (prev + 0, 32) to (start + 0, 34) +- Code(Zero) at (prev + 1, 14) to (start + 0, 16) +- Code(Zero) at (prev + 2, 1) to (start + 0, 2) + +Function name: async::i +Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 01, 00, 13] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 38, 1) to (start + 0, 19) + +Function name: async::i::{closure#0} +Raw bytes (84): 0x[01, 01, 05, 01, 00, 0d, 00, 1d, 00, 19, 13, 1d, 21, 0e, 01, 26, 13, 04, 0c, 0d, 05, 09, 00, 0a, 03, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 07, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 0b, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 0f, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Zero +- expression 1 operands: lhs = Counter(3), rhs = Zero +- expression 2 operands: lhs = Counter(7), rhs = Zero +- expression 3 operands: lhs = Counter(6), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(7), rhs = Counter(8) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 38, 19) to (start + 4, 12) +- Code(Counter(3)) at (prev + 5, 9) to (start + 0, 10) +- Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 18) + = (c0 + Zero) +- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24) +- Code(Counter(2)) at (prev + 0, 28) to (start + 0, 33) +- Code(Expression(1, Add)) at (prev + 0, 39) to (start + 0, 42) + = (c3 + Zero) +- Code(Counter(5)) at (prev + 0, 43) to (start + 0, 48) +- Code(Counter(7)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(9)) at (prev + 0, 18) to (start + 0, 23) +- Code(Counter(10)) at (prev + 0, 27) to (start + 0, 32) +- Code(Expression(2, Add)) at (prev + 0, 36) to (start + 0, 38) + = (c7 + Zero) +- Code(Counter(8)) at (prev + 1, 14) to (start + 0, 16) +- Code(Expression(3, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c6 + (c7 + c8)) + +Function name: async::j +Raw bytes (59): 0x[01, 01, 05, 01, 00, 05, 00, 09, 00, 05, 13, 09, 0d, 09, 01, 31, 01, 13, 0c, 05, 14, 09, 00, 0a, 03, 00, 0e, 00, 1b, 07, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 0b, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 0f, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Zero +- expression 1 operands: lhs = Counter(1), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 49, 1) to (start + 19, 12) +- Code(Counter(1)) at (prev + 20, 9) to (start + 0, 10) +- Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 27) + = (c0 + Zero) +- Code(Expression(1, Add)) at (prev + 0, 31) to (start + 0, 39) + = (c1 + Zero) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 26) +- Code(Expression(2, Add)) at (prev + 0, 30) to (start + 0, 32) + = (c2 + Zero) +- Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16) +- Code(Expression(3, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c1 + (c2 + c3)) + +Function name: async::j::c +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 33, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 51, 5) to (start + 1, 18) +- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 10, 13) to (start + 0, 14) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6) + = (c1 + (c0 - c1)) + +Function name: async::j::d +Raw bytes (9): 0x[01, 01, 00, 01, 01, 42, 05, 00, 17] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 66, 5) to (start + 0, 23) + +Function name: async::j::f +Raw bytes (9): 0x[01, 01, 00, 01, 01, 43, 05, 00, 17] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 67, 5) to (start + 0, 23) + +Function name: async::k (unused) +Raw bytes (29): 0x[01, 01, 00, 05, 01, 4b, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 75, 1) to (start + 1, 12) +- Code(Zero) at (prev + 2, 14) to (start + 0, 16) +- Code(Zero) at (prev + 1, 14) to (start + 0, 16) +- Code(Zero) at (prev + 1, 14) to (start + 0, 16) +- Code(Zero) at (prev + 2, 1) to (start + 0, 2) + +Function name: async::l +Raw bytes (37): 0x[01, 01, 04, 01, 07, 09, 05, 09, 0f, 05, 02, 05, 01, 53, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) +- expression 1 operands: lhs = Counter(2), rhs = Counter(1) +- expression 2 operands: lhs = Counter(2), rhs = Expression(3, Add) +- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 83, 1) to (start + 1, 12) +- Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16) + = (c0 - (c2 + c1)) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16) +- Code(Counter(2)) at (prev + 1, 14) to (start + 0, 16) +- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c2 + (c1 + (c0 - (c2 + c1)))) + +Function name: async::m +Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 91, 1) to (start + 0, 25) + +Function name: async::m::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 19, 00, 22] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 91, 25) to (start + 0, 34) + +Function name: async::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 5d, 01, 08, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 93, 1) to (start + 8, 2) + diff --git a/tests/coverage-map/status-quo/async.rs b/tests/coverage-map/status-quo/async.rs new file mode 100644 index 00000000000..efd9e62d64e --- /dev/null +++ b/tests/coverage-map/status-quo/async.rs @@ -0,0 +1,128 @@ +#![allow(unused_assignments, dead_code)] + +// compile-flags: --edition=2018 -C opt-level=1 + +async fn c(x: u8) -> u8 { + if x == 8 { + 1 + } else { + 0 + } +} + +async fn d() -> u8 { 1 } + +async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + +async fn f() -> u8 { 1 } + +async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` + +pub async fn g(x: u8) { + match x { + y if e().await == y => (), + y if f().await == y => (), + _ => (), + } +} + +async fn h(x: usize) { // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). + match x { + y if foo().await[y] => (), + _ => (), + } +} + +async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. + match x { + y if c(x).await == y + 1 => { d().await; } + y if f().await == y + 1 => (), + _ => (), + } +} + +fn j(x: u8) { + // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + fn c(x: u8) -> u8 { + if x == 8 { + 1 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the function body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + 0 + } + } + fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed + fn f() -> u8 { 1 } + match x { + y if c(x) == y + 1 => { d(); } + y if f() == y + 1 => (), + _ => (), + } +} + +fn k(x: u8) { // unused function + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +fn l(x: u8) { + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +async fn m(x: u8) -> u8 { x - 1 } + +fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + let _ = m(5); + executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unsafe { unreachable_unchecked() }, // clone + |_| unsafe { unreachable_unchecked() }, // wake + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/coverage-map/status-quo/async2.cov-map b/tests/coverage-map/status-quo/async2.cov-map new file mode 100644 index 00000000000..fe74dcd8840 --- /dev/null +++ b/tests/coverage-map/status-quo/async2.cov-map @@ -0,0 +1,136 @@ +Function name: async2::async_func +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 17] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 23) + +Function name: async2::async_func::{closure#0} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 17, 03, 09, 05, 03, 0a, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 11, 23) to (start + 3, 9) +- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: async2::async_func_just_println +Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 24] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 36) + +Function name: async2::async_func_just_println::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 24, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 19, 36) to (start + 2, 2) + +Function name: async2::executor::block_on::<async2::async_func::{closure#0}> +Raw bytes (44): 0x[01, 01, 05, 0b, 05, 01, 05, 01, 05, 02, 00, 02, 00, 06, 01, 27, 05, 0a, 36, 02, 0d, 20, 00, 23, 0b, 00, 27, 00, 49, 0f, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 13, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 4 operands: lhs = Expression(0, Sub), rhs = Zero +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 39, 5) to (start + 10, 54) +- Code(Expression(0, Sub)) at (prev + 13, 32) to (start + 0, 35) + = ((c0 + c1) - c1) +- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73) + = (c0 + c1) +- Code(Expression(3, Add)) at (prev + 1, 23) to (start + 0, 26) + = (((c0 + c1) - c1) + Zero) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6) + = (((c0 + c1) - c1) + Zero) + +Function name: async2::executor::block_on::<async2::async_func_just_println::{closure#0}> +Raw bytes (44): 0x[01, 01, 05, 0b, 05, 01, 05, 01, 05, 02, 00, 02, 00, 06, 01, 27, 05, 0a, 36, 02, 0d, 20, 00, 23, 0b, 00, 27, 00, 49, 0f, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 13, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 4 operands: lhs = Expression(0, Sub), rhs = Zero +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 39, 5) to (start + 10, 54) +- Code(Expression(0, Sub)) at (prev + 13, 32) to (start + 0, 35) + = ((c0 + c1) - c1) +- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73) + = (c0 + c1) +- Code(Expression(3, Add)) at (prev + 1, 23) to (start + 0, 26) + = (((c0 + c1) - c1) + Zero) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6) + = (((c0 + c1) - c1) + Zero) + +Function name: async2::executor::block_on::VTABLE::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2b, 11, 00, 33] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 43, 17) to (start + 0, 51) + +Function name: async2::executor::block_on::VTABLE::{closure#1} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 11, 00, 33] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 44, 17) to (start + 0, 51) + +Function name: async2::executor::block_on::VTABLE::{closure#2} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2d, 11, 00, 33] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 45, 17) to (start + 0, 51) + +Function name: async2::executor::block_on::VTABLE::{closure#3} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2e, 11, 00, 13] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 46, 17) to (start + 0, 19) + +Function name: async2::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 07, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 23, 1) to (start + 7, 2) + +Function name: async2::non_async_func +Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 03, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(1), rhs = Zero +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 3, 1) to (start + 3, 9) +- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + Zero) + diff --git a/tests/coverage-map/status-quo/async2.rs b/tests/coverage-map/status-quo/async2.rs new file mode 100644 index 00000000000..2884ff297af --- /dev/null +++ b/tests/coverage-map/status-quo/async2.rs @@ -0,0 +1,57 @@ +// compile-flags: --edition=2018 + +fn non_async_func() { + println!("non_async_func was covered"); + let b = true; + if b { + println!("non_async_func println in block"); + } +} + +async fn async_func() { + println!("async_func was covered"); + let b = true; + if b { + println!("async_func println in block"); + } +} + +async fn async_func_just_println() { + println!("async_func_just_println was covered"); +} + +fn main() { + println!("codecovsample::main"); + + non_async_func(); + + executor::block_on(async_func()); + executor::block_on(async_func_just_println()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unsafe { unreachable_unchecked() }, // clone + |_| unsafe { unreachable_unchecked() }, // wake + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/coverage-map/status-quo/closure.cov-map b/tests/coverage-map/status-quo/closure.cov-map new file mode 100644 index 00000000000..f3a32f091a9 --- /dev/null +++ b/tests/coverage-map/status-quo/closure.cov-map @@ -0,0 +1,324 @@ +Function name: closure::main +Raw bytes (170): 0x[01, 01, 17, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 05, 05, 5a, 01, 05, 18, 01, 08, 01, 0f, 0d, 03, 16, 0e, 06, 0a, 07, 10, 05, 13, 0d, 0b, 1a, 0e, 08, 09, 0f, 10, 05, 0e, 09, 13, 16, 05, 0d, 18, 17, 19, 09, 01, 21, 1b, 04, 09, 00, 29, 1f, 01, 09, 00, 2d, 23, 01, 09, 00, 24, 27, 05, 09, 00, 24, 2b, 02, 09, 00, 21, 2f, 04, 09, 00, 21, 33, 04, 09, 00, 28, 37, 09, 09, 00, 32, 3b, 04, 09, 00, 33, 3f, 07, 09, 00, 4b, 43, 08, 09, 01, 09, 47, 0a, 09, 01, 09, 4b, 08, 09, 01, 09, 4f, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 5a, 04, 06, 00, 07, 57, 01, 05, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 23 +- expression 0 operands: lhs = Counter(0), rhs = Zero +- expression 1 operands: lhs = Counter(0), rhs = Zero +- expression 2 operands: lhs = Counter(0), rhs = Zero +- expression 3 operands: lhs = Counter(0), rhs = Zero +- expression 4 operands: lhs = Counter(0), rhs = Zero +- expression 5 operands: lhs = Counter(0), rhs = Zero +- expression 6 operands: lhs = Counter(0), rhs = Zero +- expression 7 operands: lhs = Counter(0), rhs = Zero +- expression 8 operands: lhs = Counter(0), rhs = Zero +- expression 9 operands: lhs = Counter(0), rhs = Zero +- expression 10 operands: lhs = Counter(0), rhs = Zero +- expression 11 operands: lhs = Counter(0), rhs = Zero +- expression 12 operands: lhs = Counter(0), rhs = Zero +- expression 13 operands: lhs = Counter(0), rhs = Zero +- expression 14 operands: lhs = Counter(0), rhs = Zero +- expression 15 operands: lhs = Counter(0), rhs = Zero +- expression 16 operands: lhs = Counter(0), rhs = Zero +- expression 17 operands: lhs = Counter(0), rhs = Zero +- expression 18 operands: lhs = Counter(0), rhs = Zero +- expression 19 operands: lhs = Counter(0), rhs = Zero +- expression 20 operands: lhs = Counter(0), rhs = Counter(1) +- expression 21 operands: lhs = Counter(1), rhs = Expression(22, Sub) +- expression 22 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 24 +- Code(Counter(0)) at (prev + 8, 1) to (start + 15, 13) +- Code(Expression(0, Add)) at (prev + 22, 14) to (start + 6, 10) + = (c0 + Zero) +- Code(Expression(1, Add)) at (prev + 16, 5) to (start + 19, 13) + = (c0 + Zero) +- Code(Expression(2, Add)) at (prev + 26, 14) to (start + 8, 9) + = (c0 + Zero) +- Code(Expression(3, Add)) at (prev + 16, 5) to (start + 14, 9) + = (c0 + Zero) +- Code(Expression(4, Add)) at (prev + 22, 5) to (start + 13, 24) + = (c0 + Zero) +- Code(Expression(5, Add)) at (prev + 25, 9) to (start + 1, 33) + = (c0 + Zero) +- Code(Expression(6, Add)) at (prev + 4, 9) to (start + 0, 41) + = (c0 + Zero) +- Code(Expression(7, Add)) at (prev + 1, 9) to (start + 0, 45) + = (c0 + Zero) +- Code(Expression(8, Add)) at (prev + 1, 9) to (start + 0, 36) + = (c0 + Zero) +- Code(Expression(9, Add)) at (prev + 5, 9) to (start + 0, 36) + = (c0 + Zero) +- Code(Expression(10, Add)) at (prev + 2, 9) to (start + 0, 33) + = (c0 + Zero) +- Code(Expression(11, Add)) at (prev + 4, 9) to (start + 0, 33) + = (c0 + Zero) +- Code(Expression(12, Add)) at (prev + 4, 9) to (start + 0, 40) + = (c0 + Zero) +- Code(Expression(13, Add)) at (prev + 9, 9) to (start + 0, 50) + = (c0 + Zero) +- Code(Expression(14, Add)) at (prev + 4, 9) to (start + 0, 51) + = (c0 + Zero) +- Code(Expression(15, Add)) at (prev + 7, 9) to (start + 0, 75) + = (c0 + Zero) +- Code(Expression(16, Add)) at (prev + 8, 9) to (start + 1, 9) + = (c0 + Zero) +- Code(Expression(17, Add)) at (prev + 10, 9) to (start + 1, 9) + = (c0 + Zero) +- Code(Expression(18, Add)) at (prev + 8, 9) to (start + 1, 9) + = (c0 + Zero) +- Code(Expression(19, Add)) at (prev + 10, 8) to (start + 0, 16) + = (c0 + Zero) +- Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6) +- Code(Expression(22, Sub)) at (prev + 4, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(21, Add)) at (prev + 1, 5) to (start + 3, 2) + = (c1 + (c0 - c1)) + +Function name: closure::main::{closure#0} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 27, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 39, 5) to (start + 2, 20) +- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6) + = (c1 + (c0 - c1)) + +Function name: closure::main::{closure#10} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, 9a, 01, 07, 00, 21] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 154, 7) to (start + 0, 33) + +Function name: closure::main::{closure#11} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, 9e, 01, 07, 00, 21] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 158, 7) to (start + 0, 33) + +Function name: closure::main::{closure#12} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, a6, 01, 01, 00, 17] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 166, 1) to (start + 0, 23) + +Function name: closure::main::{closure#13} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, ab, 01, 0d, 02, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 171, 13) to (start + 2, 14) + +Function name: closure::main::{closure#14} +Raw bytes (38): 0x[01, 01, 04, 05, 0a, 01, 05, 01, 05, 03, 00, 05, 03, b2, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 0f, 01, 0d, 00, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Expression(0, Add), rhs = Zero +Number of file 0 mappings: 5 +- Code(Expression(0, Add)) at (prev + 178, 13) to (start + 0, 21) + = (c1 + (c0 - c1)) +- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) +- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51) + = (c0 - c1) +- Code(Expression(3, Add)) at (prev + 1, 13) to (start + 0, 14) + = ((c1 + (c0 - c1)) + Zero) + +Function name: closure::main::{closure#15} +Raw bytes (45): 0x[01, 01, 05, 05, 0e, 01, 05, 01, 00, 01, 05, 03, 00, 06, 01, ba, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 0b, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0e, 00, 2f, 00, 33, 13, 02, 09, 00, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(1), rhs = Expression(3, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Zero +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +- expression 4 operands: lhs = Expression(0, Add), rhs = Zero +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 186, 9) to (start + 0, 10) +- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21) + = (c1 + (c0 - c1)) +- Code(Expression(2, Add)) at (prev + 1, 17) to (start + 1, 27) + = (c0 + Zero) +- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Expression(3, Sub)) at (prev + 0, 47) to (start + 0, 51) + = (c0 - c1) +- Code(Expression(4, Add)) at (prev + 2, 9) to (start + 0, 10) + = ((c1 + (c0 - c1)) + Zero) + +Function name: closure::main::{closure#16} +Raw bytes (38): 0x[01, 01, 04, 05, 0a, 01, 05, 01, 05, 03, 00, 05, 03, c4, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 0f, 01, 0d, 00, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Expression(0, Add), rhs = Zero +Number of file 0 mappings: 5 +- Code(Expression(0, Add)) at (prev + 196, 13) to (start + 0, 21) + = (c1 + (c0 - c1)) +- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) +- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51) + = (c0 - c1) +- Code(Expression(3, Add)) at (prev + 1, 13) to (start + 0, 14) + = ((c1 + (c0 - c1)) + Zero) + +Function name: closure::main::{closure#17} +Raw bytes (45): 0x[01, 01, 05, 05, 0e, 01, 05, 01, 00, 01, 05, 03, 00, 06, 01, cc, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 0b, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0e, 00, 2f, 00, 33, 13, 02, 09, 00, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(1), rhs = Expression(3, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(0), rhs = Zero +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +- expression 4 operands: lhs = Expression(0, Add), rhs = Zero +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 204, 9) to (start + 0, 10) +- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21) + = (c1 + (c0 - c1)) +- Code(Expression(2, Add)) at (prev + 1, 17) to (start + 1, 27) + = (c0 + Zero) +- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Expression(3, Sub)) at (prev + 0, 47) to (start + 0, 51) + = (c0 - c1) +- Code(Expression(4, Add)) at (prev + 2, 9) to (start + 0, 10) + = ((c1 + (c0 - c1)) + Zero) + +Function name: closure::main::{closure#18} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 24, 13) to (start + 2, 28) +- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +- Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 17) to (start + 1, 14) + = (c1 + (c0 - c1)) + +Function name: closure::main::{closure#19} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 42, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 66, 13) to (start + 2, 28) +- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +- Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 17) to (start + 1, 14) + = (c1 + (c0 - c1)) + +Function name: closure::main::{closure#1} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 51, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 81, 5) to (start + 2, 20) +- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6) + = (c1 + (c0 - c1)) + +Function name: closure::main::{closure#2} +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 67, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 103, 5) to (start + 2, 20) +- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6) + = (c1 + (c0 - c1)) + +Function name: closure::main::{closure#3} (unused) +Raw bytes (25): 0x[01, 01, 00, 04, 01, 80, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 128, 5) to (start + 1, 20) +- Code(Zero) at (prev + 1, 21) to (start + 2, 10) +- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Zero) at (prev + 1, 9) to (start + 1, 6) + +Function name: closure::main::{closure#4} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, 88, 01, 35, 00, 43] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 136, 53) to (start + 0, 67) + +Function name: closure::main::{closure#5} +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8b, 01, 3d, 00, 4f] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 139, 61) to (start + 0, 79) + +Function name: closure::main::{closure#6} +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 41, 00, 57] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 140, 65) to (start + 0, 87) + +Function name: closure::main::{closure#7} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 3b, 00, 51] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 141, 59) to (start + 0, 81) + +Function name: closure::main::{closure#8} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, 92, 01, 3b, 00, 55] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 146, 59) to (start + 0, 85) + +Function name: closure::main::{closure#9} (unused) +Raw bytes (10): 0x[01, 01, 00, 01, 01, 94, 01, 38, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 148, 56) to (start + 2, 6) + diff --git a/tests/coverage-map/status-quo/closure.rs b/tests/coverage-map/status-quo/closure.rs new file mode 100644 index 00000000000..16a2c4e33bd --- /dev/null +++ b/tests/coverage-map/status-quo/closure.rs @@ -0,0 +1,220 @@ +#![allow(unused_assignments, unused_variables)] +// compile-flags: -C opt-level=2 + +// This test used to be sensitive to certain coverage-specific hacks in +// `rustc_middle/mir/mono.rs`, but those hacks were later cleaned up by +// <https://github.com/rust-lang/rust/pull/83666>. + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let is_false = !is_true; + + let mut some_string = Some(String::from("the string content")); + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 1".to_owned() + } + ) + ); + + some_string = Some(String::from("the string content")); + let + a + = + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 2".to_owned() + }; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + some_string = None; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 3".to_owned() + } + ) + ); + + some_string = None; + let + a + = + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 4".to_owned() + }; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + let + quote_closure + = + |val| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + format!("'{}'", val) + }; + println!( + "Repeated, quoted string: {:?}" + , + std::iter::repeat("repeat me") + .take(5) + .map + ( + quote_closure + ) + .collect::<Vec<_>>() + ); + + let + _unused_closure + = + | + mut countdown + | + { + if is_false { + countdown = 10; + } + "closure should be unused".to_owned() + }; + + let mut countdown = 10; + let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + + + let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); + let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); + let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); + + + + + let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + + let _shortish_unused_closure = | _unused_arg: u8 | { + println!("not called") + }; + + let _as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") }; + + let _almost_as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") } + ; + + + + + + let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | +println!("not called") + ; + + let _short_unused_closure_line_break_no_block2 = + | _unused_arg: u8 | + println!( + "not called" + ) + ; + + let short_used_not_covered_closure_line_break_no_block_embedded_branch = + | _unused_arg: u8 | + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + ; + + let short_used_not_covered_closure_line_break_block_embedded_branch = + | _unused_arg: u8 | + { + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + } + ; + + let short_used_covered_closure_line_break_no_block_embedded_branch = + | _unused_arg: u8 | + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + ; + + let short_used_covered_closure_line_break_block_embedded_branch = + | _unused_arg: u8 | + { + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + } + ; + + if is_false { + short_used_not_covered_closure_macro(0); + short_used_not_covered_closure_line_break_no_block_embedded_branch(0); + short_used_not_covered_closure_line_break_block_embedded_branch(0); + } + short_used_covered_closure_macro(0); + short_used_covered_closure_line_break_no_block_embedded_branch(0); + short_used_covered_closure_line_break_block_embedded_branch(0); +} diff --git a/tests/coverage-map/status-quo/closure_macro.cov-map b/tests/coverage-map/status-quo/closure_macro.cov-map new file mode 100644 index 00000000000..ac017eb4468 --- /dev/null +++ b/tests/coverage-map/status-quo/closure_macro.cov-map @@ -0,0 +1,40 @@ +Function name: closure_macro::load_configuration_files +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) + +Function name: closure_macro::main +Raw bytes (49): 0x[01, 01, 05, 01, 05, 02, 00, 05, 00, 02, 00, 05, 02, 07, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 07, 00, 12, 00, 13, 0b, 00, 54, 00, 55, 0f, 02, 09, 02, 0b, 13, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 2 operands: lhs = Counter(1), rhs = Zero +- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) + = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(1, Add)) at (prev + 0, 18) to (start + 0, 19) + = ((c0 - c1) + Zero) +- Code(Expression(2, Add)) at (prev + 0, 84) to (start + 0, 85) + = (c1 + Zero) +- Code(Expression(3, Add)) at (prev + 2, 9) to (start + 2, 11) + = ((c0 - c1) + Zero) +- Code(Expression(4, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: closure_macro::main::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 12, 00, 54] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 35, 18) to (start + 0, 84) + diff --git a/tests/coverage-map/status-quo/closure_macro.rs b/tests/coverage-map/status-quo/closure_macro.rs new file mode 100644 index 00000000000..5e3b00d1ef5 --- /dev/null +++ b/tests/coverage-map/status-quo/closure_macro.rs @@ -0,0 +1,40 @@ +// compile-flags: --edition=2018 +#![feature(no_coverage)] + +macro_rules! bail { + ($msg:literal $(,)?) => { + if $msg.len() > 0 { + println!("no msg"); + } else { + println!($msg); + } + return Err(String::from($msg)); + }; +} + +macro_rules! on_error { + ($value:expr, $error_message:expr) => { + $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + let message = format!($error_message, e); + if message.len() > 0 { + println!("{}", message); + Ok(String::from("ok")) + } else { + bail!("error"); + } + }) + }; +} + +fn load_configuration_files() -> Result<String, String> { + Ok(String::from("config")) +} + +pub fn main() -> Result<(), String> { + println!("Starting service"); + let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + + let startup_delay_duration = String::from("arg"); + let _ = (config, startup_delay_duration); + Ok(()) +} diff --git a/tests/coverage-map/status-quo/closure_macro_async.cov-map b/tests/coverage-map/status-quo/closure_macro_async.cov-map new file mode 100644 index 00000000000..c9a142e5aeb --- /dev/null +++ b/tests/coverage-map/status-quo/closure_macro_async.cov-map @@ -0,0 +1,48 @@ +Function name: closure_macro_async::load_configuration_files +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) + +Function name: closure_macro_async::test +Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 00, 2b] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 43) + +Function name: closure_macro_async::test::{closure#0} +Raw bytes (49): 0x[01, 01, 05, 01, 05, 02, 00, 05, 00, 02, 00, 05, 02, 07, 01, 21, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 07, 00, 12, 00, 13, 0b, 00, 54, 00, 55, 0f, 02, 09, 02, 0b, 13, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 2 operands: lhs = Counter(1), rhs = Zero +- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero +- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 33, 43) to (start + 1, 33) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) + = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(1, Add)) at (prev + 0, 18) to (start + 0, 19) + = ((c0 - c1) + Zero) +- Code(Expression(2, Add)) at (prev + 0, 84) to (start + 0, 85) + = (c1 + Zero) +- Code(Expression(3, Add)) at (prev + 2, 9) to (start + 2, 11) + = ((c0 - c1) + Zero) +- Code(Expression(4, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: closure_macro_async::test::{closure#0}::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 12, 00, 54] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 35, 18) to (start + 0, 84) + diff --git a/tests/coverage-map/status-quo/closure_macro_async.rs b/tests/coverage-map/status-quo/closure_macro_async.rs new file mode 100644 index 00000000000..3d6bdb38a2a --- /dev/null +++ b/tests/coverage-map/status-quo/closure_macro_async.rs @@ -0,0 +1,77 @@ +// compile-flags: --edition=2018 +#![feature(no_coverage)] + +macro_rules! bail { + ($msg:literal $(,)?) => { + if $msg.len() > 0 { + println!("no msg"); + } else { + println!($msg); + } + return Err(String::from($msg)); + }; +} + +macro_rules! on_error { + ($value:expr, $error_message:expr) => { + $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + let message = format!($error_message, e); + if message.len() > 0 { + println!("{}", message); + Ok(String::from("ok")) + } else { + bail!("error"); + } + }) + }; +} + +fn load_configuration_files() -> Result<String, String> { + Ok(String::from("config")) +} + +pub async fn test() -> Result<(), String> { + println!("Starting service"); + let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + + let startup_delay_duration = String::from("arg"); + let _ = (config, startup_delay_duration); + Ok(()) +} + +#[no_coverage] +fn main() { + executor::block_on(test()).unwrap(); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + #[no_coverage] + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // clone + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // wake + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + #[no_coverage] + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/coverage-map/status-quo/conditions.cov-map b/tests/coverage-map/status-quo/conditions.cov-map new file mode 100644 index 00000000000..d82b8389b4d --- /dev/null +++ b/tests/coverage-map/status-quo/conditions.cov-map @@ -0,0 +1,261 @@ +Function name: conditions::main +Raw bytes (793): 0x[01, 01, 90, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, bf, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, ba, 04, 0d, bf, 04, 09, 05, 00, 03, 00, 45, 00, 87, 01, 49, 45, 00, 82, 01, 31, 87, 01, 49, 45, 00, 7e, 4d, 82, 01, 31, 87, 01, 49, 45, 00, 7a, 51, 7e, 4d, 82, 01, 31, 87, 01, 49, 45, 00, ab, 01, 55, 4d, 51, a7, 01, 59, ab, 01, 55, 4d, 51, 49, a3, 01, a7, 01, 59, ab, 01, 55, 4d, 51, 61, 00, e7, 01, 65, 61, 00, e2, 01, 2d, e7, 01, 65, 61, 00, de, 01, 69, e2, 01, 2d, e7, 01, 65, 61, 00, da, 01, 6d, de, 01, 69, e2, 01, 2d, e7, 01, 65, 61, 00, 8f, 02, 71, 69, 6d, 8b, 02, 75, 8f, 02, 71, 69, 6d, 83, 02, 00, 65, 87, 02, 8b, 02, 75, 8f, 02, 71, 69, 6d, 7d, f3, 03, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, 79, 00, db, 02, 7d, 79, 00, d6, 02, 29, db, 02, 7d, 79, 00, d2, 02, 81, 01, d6, 02, 29, db, 02, 7d, 79, 00, ce, 02, 85, 01, d2, 02, 81, 01, d6, 02, 29, db, 02, 7d, 79, 00, fb, 03, 89, 01, 81, 01, 85, 01, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, 11, 9b, 04, 9f, 04, 21, a3, 04, 1d, 15, 19, ef, 03, 00, 7d, f3, 03, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, ef, 03, 11, 7d, f3, 03, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, ea, 03, 25, ef, 03, 11, 7d, f3, 03, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, e6, 03, 15, ea, 03, 25, ef, 03, 11, 7d, f3, 03, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, e2, 03, 19, e6, 03, 15, ea, 03, 25, ef, 03, 11, 7d, f3, 03, f7, 03, 8d, 01, fb, 03, 89, 01, 81, 01, 85, 01, a3, 04, 1d, 15, 19, 9f, 04, 21, a3, 04, 1d, 15, 19, 97, 04, a7, 04, 11, 9b, 04, 9f, 04, 21, a3, 04, 1d, 15, 19, ab, 04, b6, 04, af, 04, b3, 04, 25, 29, 2d, 31, ba, 04, 0d, bf, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, bf, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ba, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, b6, 04, 03, 09, 00, 0f, 4b, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 87, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 82, 01, 02, 0f, 00, 1c, 7e, 01, 0c, 00, 19, 7a, 00, 1d, 00, 2a, 76, 00, 2e, 00, 3c, a7, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, a3, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9f, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e7, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, e2, 01, 03, 11, 00, 1e, de, 01, 01, 10, 00, 1d, da, 01, 00, 21, 00, 2e, d6, 01, 00, 32, 00, 40, 8b, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 87, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, ff, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, ef, 03, 02, 09, 00, 0a, db, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d6, 02, 02, 0f, 00, 1c, d2, 02, 01, 0c, 00, 19, ce, 02, 00, 1d, 00, 2a, ca, 02, 00, 2e, 00, 3c, f7, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, f3, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 97, 04, 05, 09, 00, 0a, 83, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, ea, 03, 02, 0f, 00, 1c, e6, 03, 01, 0c, 00, 19, e2, 03, 00, 1d, 00, 2a, de, 03, 00, 2e, 00, 3c, 9f, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 9b, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 93, 04, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 144 +- expression 0 operands: lhs = Counter(2), rhs = Expression(12, Add) +- expression 1 operands: lhs = Expression(13, Add), rhs = Counter(16) +- expression 2 operands: lhs = Expression(14, Add), rhs = Counter(15) +- expression 3 operands: lhs = Counter(13), rhs = Counter(14) +- expression 4 operands: lhs = Counter(1), rhs = Zero +- expression 5 operands: lhs = Expression(143, Add), rhs = Counter(2) +- expression 6 operands: lhs = Counter(1), rhs = Zero +- expression 7 operands: lhs = Counter(3), rhs = Counter(13) +- expression 8 operands: lhs = Expression(9, Sub), rhs = Counter(14) +- expression 9 operands: lhs = Counter(3), rhs = Counter(13) +- expression 10 operands: lhs = Expression(14, Add), rhs = Counter(15) +- expression 11 operands: lhs = Counter(13), rhs = Counter(14) +- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(16) +- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(15) +- expression 14 operands: lhs = Counter(13), rhs = Counter(14) +- expression 15 operands: lhs = Expression(142, Sub), rhs = Counter(3) +- expression 16 operands: lhs = Expression(143, Add), rhs = Counter(2) +- expression 17 operands: lhs = Counter(1), rhs = Zero +- expression 18 operands: lhs = Expression(0, Add), rhs = Zero +- expression 19 operands: lhs = Counter(17), rhs = Zero +- expression 20 operands: lhs = Expression(33, Add), rhs = Counter(18) +- expression 21 operands: lhs = Counter(17), rhs = Zero +- expression 22 operands: lhs = Expression(32, Sub), rhs = Counter(12) +- expression 23 operands: lhs = Expression(33, Add), rhs = Counter(18) +- expression 24 operands: lhs = Counter(17), rhs = Zero +- expression 25 operands: lhs = Expression(31, Sub), rhs = Counter(19) +- expression 26 operands: lhs = Expression(32, Sub), rhs = Counter(12) +- expression 27 operands: lhs = Expression(33, Add), rhs = Counter(18) +- expression 28 operands: lhs = Counter(17), rhs = Zero +- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(20) +- expression 30 operands: lhs = Expression(31, Sub), rhs = Counter(19) +- expression 31 operands: lhs = Expression(32, Sub), rhs = Counter(12) +- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(18) +- expression 33 operands: lhs = Counter(17), rhs = Zero +- expression 34 operands: lhs = Expression(42, Add), rhs = Counter(21) +- expression 35 operands: lhs = Counter(19), rhs = Counter(20) +- expression 36 operands: lhs = Expression(41, Add), rhs = Counter(22) +- expression 37 operands: lhs = Expression(42, Add), rhs = Counter(21) +- expression 38 operands: lhs = Counter(19), rhs = Counter(20) +- expression 39 operands: lhs = Counter(18), rhs = Expression(40, Add) +- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(22) +- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(21) +- expression 42 operands: lhs = Counter(19), rhs = Counter(20) +- expression 43 operands: lhs = Counter(24), rhs = Zero +- expression 44 operands: lhs = Expression(57, Add), rhs = Counter(25) +- expression 45 operands: lhs = Counter(24), rhs = Zero +- expression 46 operands: lhs = Expression(56, Sub), rhs = Counter(11) +- expression 47 operands: lhs = Expression(57, Add), rhs = Counter(25) +- expression 48 operands: lhs = Counter(24), rhs = Zero +- expression 49 operands: lhs = Expression(55, Sub), rhs = Counter(26) +- expression 50 operands: lhs = Expression(56, Sub), rhs = Counter(11) +- expression 51 operands: lhs = Expression(57, Add), rhs = Counter(25) +- expression 52 operands: lhs = Counter(24), rhs = Zero +- expression 53 operands: lhs = Expression(54, Sub), rhs = Counter(27) +- expression 54 operands: lhs = Expression(55, Sub), rhs = Counter(26) +- expression 55 operands: lhs = Expression(56, Sub), rhs = Counter(11) +- expression 56 operands: lhs = Expression(57, Add), rhs = Counter(25) +- expression 57 operands: lhs = Counter(24), rhs = Zero +- expression 58 operands: lhs = Expression(67, Add), rhs = Counter(28) +- expression 59 operands: lhs = Counter(26), rhs = Counter(27) +- expression 60 operands: lhs = Expression(66, Add), rhs = Counter(29) +- expression 61 operands: lhs = Expression(67, Add), rhs = Counter(28) +- expression 62 operands: lhs = Counter(26), rhs = Counter(27) +- expression 63 operands: lhs = Expression(64, Add), rhs = Zero +- expression 64 operands: lhs = Counter(25), rhs = Expression(65, Add) +- expression 65 operands: lhs = Expression(66, Add), rhs = Counter(29) +- expression 66 operands: lhs = Expression(67, Add), rhs = Counter(28) +- expression 67 operands: lhs = Counter(26), rhs = Counter(27) +- expression 68 operands: lhs = Counter(31), rhs = Expression(124, Add) +- expression 69 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 70 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 71 operands: lhs = Counter(32), rhs = Counter(33) +- expression 72 operands: lhs = Counter(30), rhs = Zero +- expression 73 operands: lhs = Expression(86, Add), rhs = Counter(31) +- expression 74 operands: lhs = Counter(30), rhs = Zero +- expression 75 operands: lhs = Expression(85, Sub), rhs = Counter(10) +- expression 76 operands: lhs = Expression(86, Add), rhs = Counter(31) +- expression 77 operands: lhs = Counter(30), rhs = Zero +- expression 78 operands: lhs = Expression(84, Sub), rhs = Counter(32) +- expression 79 operands: lhs = Expression(85, Sub), rhs = Counter(10) +- expression 80 operands: lhs = Expression(86, Add), rhs = Counter(31) +- expression 81 operands: lhs = Counter(30), rhs = Zero +- expression 82 operands: lhs = Expression(83, Sub), rhs = Counter(33) +- expression 83 operands: lhs = Expression(84, Sub), rhs = Counter(32) +- expression 84 operands: lhs = Expression(85, Sub), rhs = Counter(10) +- expression 85 operands: lhs = Expression(86, Add), rhs = Counter(31) +- expression 86 operands: lhs = Counter(30), rhs = Zero +- expression 87 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 88 operands: lhs = Counter(32), rhs = Counter(33) +- expression 89 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 90 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 91 operands: lhs = Counter(32), rhs = Counter(33) +- expression 92 operands: lhs = Counter(4), rhs = Expression(134, Add) +- expression 93 operands: lhs = Expression(135, Add), rhs = Counter(8) +- expression 94 operands: lhs = Expression(136, Add), rhs = Counter(7) +- expression 95 operands: lhs = Counter(5), rhs = Counter(6) +- expression 96 operands: lhs = Expression(123, Add), rhs = Zero +- expression 97 operands: lhs = Counter(31), rhs = Expression(124, Add) +- expression 98 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 99 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 100 operands: lhs = Counter(32), rhs = Counter(33) +- expression 101 operands: lhs = Expression(123, Add), rhs = Counter(4) +- expression 102 operands: lhs = Counter(31), rhs = Expression(124, Add) +- expression 103 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 104 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 105 operands: lhs = Counter(32), rhs = Counter(33) +- expression 106 operands: lhs = Expression(122, Sub), rhs = Counter(9) +- expression 107 operands: lhs = Expression(123, Add), rhs = Counter(4) +- expression 108 operands: lhs = Counter(31), rhs = Expression(124, Add) +- expression 109 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 110 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 111 operands: lhs = Counter(32), rhs = Counter(33) +- expression 112 operands: lhs = Expression(121, Sub), rhs = Counter(5) +- expression 113 operands: lhs = Expression(122, Sub), rhs = Counter(9) +- expression 114 operands: lhs = Expression(123, Add), rhs = Counter(4) +- expression 115 operands: lhs = Counter(31), rhs = Expression(124, Add) +- expression 116 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 117 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 118 operands: lhs = Counter(32), rhs = Counter(33) +- expression 119 operands: lhs = Expression(120, Sub), rhs = Counter(6) +- expression 120 operands: lhs = Expression(121, Sub), rhs = Counter(5) +- expression 121 operands: lhs = Expression(122, Sub), rhs = Counter(9) +- expression 122 operands: lhs = Expression(123, Add), rhs = Counter(4) +- expression 123 operands: lhs = Counter(31), rhs = Expression(124, Add) +- expression 124 operands: lhs = Expression(125, Add), rhs = Counter(35) +- expression 125 operands: lhs = Expression(126, Add), rhs = Counter(34) +- expression 126 operands: lhs = Counter(32), rhs = Counter(33) +- expression 127 operands: lhs = Expression(136, Add), rhs = Counter(7) +- expression 128 operands: lhs = Counter(5), rhs = Counter(6) +- expression 129 operands: lhs = Expression(135, Add), rhs = Counter(8) +- expression 130 operands: lhs = Expression(136, Add), rhs = Counter(7) +- expression 131 operands: lhs = Counter(5), rhs = Counter(6) +- expression 132 operands: lhs = Expression(133, Add), rhs = Expression(137, Add) +- expression 133 operands: lhs = Counter(4), rhs = Expression(134, Add) +- expression 134 operands: lhs = Expression(135, Add), rhs = Counter(8) +- expression 135 operands: lhs = Expression(136, Add), rhs = Counter(7) +- expression 136 operands: lhs = Counter(5), rhs = Counter(6) +- expression 137 operands: lhs = Expression(138, Add), rhs = Expression(141, Sub) +- expression 138 operands: lhs = Expression(139, Add), rhs = Expression(140, Add) +- expression 139 operands: lhs = Counter(9), rhs = Counter(10) +- expression 140 operands: lhs = Counter(11), rhs = Counter(12) +- expression 141 operands: lhs = Expression(142, Sub), rhs = Counter(3) +- expression 142 operands: lhs = Expression(143, Add), rhs = Counter(2) +- expression 143 operands: lhs = Counter(1), rhs = Zero +Number of file 0 mappings: 68 +- Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) +- Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10) + = (c2 + (((c13 + c14) + c15) + c16)) +- Code(Expression(143, Add)) at (prev + 0, 16) to (start + 0, 29) + = (c1 + Zero) +- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 10) +- Code(Expression(142, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((c1 + Zero) - c2) +- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 25) +- Code(Expression(9, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c3 - c13) +- Code(Expression(8, Sub)) at (prev + 0, 46) to (start + 0, 60) + = ((c3 - c13) - c14) +- Code(Expression(13, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c13 + c14) + c15) +- Code(Counter(16)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 1, 18) + = (((c13 + c14) + c15) + c16) +- Code(Expression(141, Sub)) at (prev + 3, 9) to (start + 0, 15) + = (((c1 + Zero) - c2) - c3) +- Code(Expression(18, Add)) at (prev + 3, 9) to (start + 1, 12) + = ((c2 + (((c13 + c14) + c15) + c16)) + Zero) +- Code(Counter(17)) at (prev + 1, 13) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(33, Add)) at (prev + 2, 8) to (start + 0, 21) + = (c17 + Zero) +- Code(Counter(18)) at (prev + 0, 22) to (start + 2, 6) +- Code(Expression(32, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((c17 + Zero) - c18) +- Code(Expression(31, Sub)) at (prev + 1, 12) to (start + 0, 25) + = (((c17 + Zero) - c18) - c12) +- Code(Expression(30, Sub)) at (prev + 0, 29) to (start + 0, 42) + = ((((c17 + Zero) - c18) - c12) - c19) +- Code(Expression(29, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (((((c17 + Zero) - c18) - c12) - c19) - c20) +- Code(Expression(41, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c19 + c20) + c21) +- Code(Counter(22)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(40, Add)) at (prev + 1, 9) to (start + 0, 23) + = (((c19 + c20) + c21) + c22) +- Code(Counter(12)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(39, Add)) at (prev + 3, 8) to (start + 0, 12) + = (c18 + (((c19 + c20) + c21) + c22)) +- Code(Counter(23)) at (prev + 1, 13) to (start + 1, 16) +- Code(Counter(24)) at (prev + 1, 17) to (start + 2, 10) +- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(57, Add)) at (prev + 2, 12) to (start + 0, 25) + = (c24 + Zero) +- Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10) +- Code(Expression(56, Sub)) at (prev + 3, 17) to (start + 0, 30) + = ((c24 + Zero) - c25) +- Code(Expression(55, Sub)) at (prev + 1, 16) to (start + 0, 29) + = (((c24 + Zero) - c25) - c11) +- Code(Expression(54, Sub)) at (prev + 0, 33) to (start + 0, 46) + = ((((c24 + Zero) - c25) - c11) - c26) +- Code(Expression(53, Sub)) at (prev + 0, 50) to (start + 0, 64) + = (((((c24 + Zero) - c25) - c11) - c26) - c27) +- Code(Expression(66, Add)) at (prev + 0, 65) to (start + 2, 14) + = ((c26 + c27) + c28) +- Code(Counter(29)) at (prev + 2, 14) to (start + 0, 15) +- Code(Expression(65, Add)) at (prev + 1, 13) to (start + 0, 27) + = (((c26 + c27) + c28) + c29) +- Code(Counter(11)) at (prev + 2, 13) to (start + 0, 19) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(63, Add)) at (prev + 2, 9) to (start + 1, 12) + = ((c25 + (((c26 + c27) + c28) + c29)) + Zero) +- Code(Counter(30)) at (prev + 1, 13) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(123, Add)) at (prev + 2, 9) to (start + 0, 10) + = (c31 + (((c32 + c33) + c34) + c35)) +- Code(Expression(86, Add)) at (prev + 0, 16) to (start + 0, 29) + = (c30 + Zero) +- Code(Counter(31)) at (prev + 0, 30) to (start + 2, 6) +- Code(Expression(85, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((c30 + Zero) - c31) +- Code(Expression(84, Sub)) at (prev + 1, 12) to (start + 0, 25) + = (((c30 + Zero) - c31) - c10) +- Code(Expression(83, Sub)) at (prev + 0, 29) to (start + 0, 42) + = ((((c30 + Zero) - c31) - c10) - c32) +- Code(Expression(82, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (((((c30 + Zero) - c31) - c10) - c32) - c33) +- Code(Expression(125, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c32 + c33) + c34) +- Code(Counter(35)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(124, Add)) at (prev + 1, 9) to (start + 0, 23) + = (((c32 + c33) + c34) + c35) +- Code(Counter(10)) at (prev + 2, 13) to (start + 2, 15) +- Code(Expression(133, Add)) at (prev + 5, 9) to (start + 0, 10) + = (c4 + (((c5 + c6) + c7) + c8)) +- Code(Expression(96, Add)) at (prev + 0, 16) to (start + 0, 29) + = ((c31 + (((c32 + c33) + c34) + c35)) + Zero) +- Code(Counter(4)) at (prev + 0, 30) to (start + 2, 6) +- Code(Expression(122, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((c31 + (((c32 + c33) + c34) + c35)) - c4) +- Code(Expression(121, Sub)) at (prev + 1, 12) to (start + 0, 25) + = (((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) +- Code(Expression(120, Sub)) at (prev + 0, 29) to (start + 0, 42) + = ((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) +- Code(Expression(119, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) - c6) +- Code(Expression(135, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c5 + c6) + c7) +- Code(Counter(8)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(134, Add)) at (prev + 1, 9) to (start + 0, 23) + = (((c5 + c6) + c7) + c8) +- Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(132, Add)) at (prev + 2, 1) to (start + 0, 2) + = ((c4 + (((c5 + c6) + c7) + c8)) + (((c9 + c10) + (c11 + c12)) + (((c1 + Zero) - c2) - c3))) + diff --git a/tests/coverage-map/status-quo/conditions.rs b/tests/coverage-map/status-quo/conditions.rs new file mode 100644 index 00000000000..fa7f2a116c2 --- /dev/null +++ b/tests/coverage-map/status-quo/conditions.rs @@ -0,0 +1,86 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let mut countdown = 0; + if true { + countdown = 10; + } + + const B: u32 = 100; + let x = if countdown > 7 { + countdown -= 4; + B + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + countdown + } else { + return; + }; + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + if true { + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } + else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + } + + let mut countdown = 0; + if true { + countdown = 1; + } + + let z = if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + let should_be_reachable = countdown; + println!("reached"); + return; + }; + + let w = if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + }; +} diff --git a/tests/coverage-map/status-quo/continue.cov-map b/tests/coverage-map/status-quo/continue.cov-map new file mode 100644 index 00000000000..c78cf293079 --- /dev/null +++ b/tests/coverage-map/status-quo/continue.cov-map @@ -0,0 +1,85 @@ +Function name: continue::main +Raw bytes (216): 0x[01, 01, 1f, 01, 07, 05, 09, 03, 0d, 0d, 1f, 11, 15, 1b, 19, 0d, 1f, 11, 15, 15, 00, 19, 37, 1d, 21, 33, 25, 19, 37, 1d, 21, 1d, 00, 25, 4f, 29, 2d, 4b, 31, 25, 4f, 29, 2d, 31, 67, 35, 39, 5f, 3d, 31, 67, 35, 39, 35, 39, 3d, 41, 73, 45, 3d, 41, 41, 00, 49, 45, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 23, 03, 09, 00, 0e, 33, 02, 0e, 00, 13, 2e, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 3b, 03, 09, 00, 0e, 4b, 02, 0e, 00, 13, 46, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 5f, 03, 0e, 00, 13, 5a, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 67, 04, 09, 00, 0e, 73, 02, 0e, 00, 13, 6e, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 49, 04, 11, 00, 16, 77, 03, 09, 00, 0e, 7b, 02, 0d, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 31 +- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(3), rhs = Expression(7, Add) +- expression 4 operands: lhs = Counter(4), rhs = Counter(5) +- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(6) +- expression 6 operands: lhs = Counter(3), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(4), rhs = Counter(5) +- expression 8 operands: lhs = Counter(5), rhs = Zero +- expression 9 operands: lhs = Counter(6), rhs = Expression(13, Add) +- expression 10 operands: lhs = Counter(7), rhs = Counter(8) +- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(9) +- expression 12 operands: lhs = Counter(6), rhs = Expression(13, Add) +- expression 13 operands: lhs = Counter(7), rhs = Counter(8) +- expression 14 operands: lhs = Counter(7), rhs = Zero +- expression 15 operands: lhs = Counter(9), rhs = Expression(19, Add) +- expression 16 operands: lhs = Counter(10), rhs = Counter(11) +- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(12) +- expression 18 operands: lhs = Counter(9), rhs = Expression(19, Add) +- expression 19 operands: lhs = Counter(10), rhs = Counter(11) +- expression 20 operands: lhs = Counter(12), rhs = Expression(25, Add) +- expression 21 operands: lhs = Counter(13), rhs = Counter(14) +- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(15) +- expression 23 operands: lhs = Counter(12), rhs = Expression(25, Add) +- expression 24 operands: lhs = Counter(13), rhs = Counter(14) +- expression 25 operands: lhs = Counter(13), rhs = Counter(14) +- expression 26 operands: lhs = Counter(15), rhs = Counter(16) +- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(17) +- expression 28 operands: lhs = Counter(15), rhs = Counter(16) +- expression 29 operands: lhs = Counter(16), rhs = Zero +- expression 30 operands: lhs = Counter(18), rhs = Counter(17) +Number of file 0 mappings: 30 +- Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18) +- Code(Expression(0, Add)) at (prev + 4, 14) to (start + 0, 19) + = (c0 + (c1 + c2)) +- Code(Expression(2, Sub)) at (prev + 1, 15) to (start + 0, 22) + = ((c0 + (c1 + c2)) - c3) +- Code(Counter(1)) at (prev + 2, 17) to (start + 0, 25) +- Code(Counter(2)) at (prev + 2, 18) to (start + 4, 14) +- Code(Expression(6, Add)) at (prev + 6, 14) to (start + 0, 19) + = (c3 + (c4 + c5)) +- Code(Expression(5, Sub)) at (prev + 1, 15) to (start + 0, 22) + = ((c3 + (c4 + c5)) - c6) +- Code(Counter(5)) at (prev + 1, 22) to (start + 2, 14) +- Code(Counter(4)) at (prev + 4, 17) to (start + 0, 25) +- Code(Expression(8, Add)) at (prev + 3, 9) to (start + 0, 14) + = (c5 + Zero) +- Code(Expression(12, Add)) at (prev + 2, 14) to (start + 0, 19) + = (c6 + (c7 + c8)) +- Code(Expression(11, Sub)) at (prev + 1, 15) to (start + 0, 22) + = ((c6 + (c7 + c8)) - c9) +- Code(Counter(7)) at (prev + 1, 21) to (start + 2, 14) +- Code(Counter(8)) at (prev + 4, 17) to (start + 0, 25) +- Code(Expression(14, Add)) at (prev + 3, 9) to (start + 0, 14) + = (c7 + Zero) +- Code(Expression(18, Add)) at (prev + 2, 14) to (start + 0, 19) + = (c9 + (c10 + c11)) +- Code(Expression(17, Sub)) at (prev + 1, 12) to (start + 0, 19) + = ((c9 + (c10 + c11)) - c12) +- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 21) +- Code(Counter(11)) at (prev + 1, 10) to (start + 1, 14) +- Code(Expression(23, Add)) at (prev + 3, 14) to (start + 0, 19) + = (c12 + (c13 + c14)) +- Code(Expression(22, Sub)) at (prev + 1, 15) to (start + 0, 22) + = ((c12 + (c13 + c14)) - c15) +- Code(Counter(14)) at (prev + 1, 22) to (start + 2, 14) +- Code(Counter(13)) at (prev + 3, 18) to (start + 2, 14) +- Code(Expression(25, Add)) at (prev + 4, 9) to (start + 0, 14) + = (c13 + c14) +- Code(Expression(28, Add)) at (prev + 2, 14) to (start + 0, 19) + = (c15 + c16) +- Code(Expression(27, Sub)) at (prev + 1, 15) to (start + 0, 22) + = ((c15 + c16) - c17) +- Code(Counter(16)) at (prev + 1, 22) to (start + 2, 14) +- Code(Counter(18)) at (prev + 4, 17) to (start + 0, 22) +- Code(Expression(29, Add)) at (prev + 3, 9) to (start + 0, 14) + = (c16 + Zero) +- Code(Expression(30, Add)) at (prev + 2, 13) to (start + 1, 2) + = (c18 + c17) + diff --git a/tests/coverage-map/status-quo/continue.rs b/tests/coverage-map/status-quo/continue.rs new file mode 100644 index 00000000000..624aa98341b --- /dev/null +++ b/tests/coverage-map/status-quo/continue.rs @@ -0,0 +1,69 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let is_true = std::env::args().len() == 1; + + let mut x = 0; + for _ in 0..10 { + match is_true { + true => { + continue; + } + _ => { + x = 1; + } + } + x = 3; + } + for _ in 0..10 { + match is_true { + false => { + x = 1; + } + _ => { + continue; + } + } + x = 3; + } + for _ in 0..10 { + match is_true { + true => { + x = 1; + } + _ => { + continue; + } + } + x = 3; + } + for _ in 0..10 { + if is_true { + continue; + } + x = 3; + } + for _ in 0..10 { + match is_true { + false => { + x = 1; + } + _ => { + let _ = x; + } + } + x = 3; + } + for _ in 0..10 { + match is_true { + false => { + x = 1; + } + _ => { + break; + } + } + x = 3; + } + let _ = x; +} diff --git a/tests/coverage-map/status-quo/dead_code.cov-map b/tests/coverage-map/status-quo/dead_code.cov-map new file mode 100644 index 00000000000..8d5f88e63ef --- /dev/null +++ b/tests/coverage-map/status-quo/dead_code.cov-map @@ -0,0 +1,37 @@ +Function name: dead_code::main +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15) +- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: dead_code::unused_fn (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 15, 1) to (start + 7, 15) +- Code(Zero) at (prev + 7, 16) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) + +Function name: dead_code::unused_pub_fn_not_in_library (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 01, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) +- Code(Zero) at (prev + 7, 16) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) + diff --git a/tests/coverage-map/status-quo/dead_code.rs b/tests/coverage-map/status-quo/dead_code.rs new file mode 100644 index 00000000000..3492712a6f9 --- /dev/null +++ b/tests/coverage-map/status-quo/dead_code.rs @@ -0,0 +1,37 @@ +#![allow(dead_code, unused_assignments, unused_variables)] + +pub fn unused_pub_fn_not_in_library() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn unused_fn() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} diff --git a/tests/coverage-map/status-quo/drop_trait.cov-map b/tests/coverage-map/status-quo/drop_trait.cov-map new file mode 100644 index 00000000000..203d1048b05 --- /dev/null +++ b/tests/coverage-map/status-quo/drop_trait.cov-map @@ -0,0 +1,21 @@ +Function name: <drop_trait::Firework as core::ops::drop::Drop>::drop +Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 05, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6) + +Function name: drop_trait::main +Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(1), rhs = Zero +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12) +- Code(Counter(1)) at (prev + 6, 9) to (start + 1, 22) +- Code(Zero) at (prev + 2, 6) to (start + 4, 11) +- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2) + = (c1 + Zero) + diff --git a/tests/coverage-map/status-quo/drop_trait.rs b/tests/coverage-map/status-quo/drop_trait.rs new file mode 100644 index 00000000000..7b062719c6b --- /dev/null +++ b/tests/coverage-map/status-quo/drop_trait.rs @@ -0,0 +1,33 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +struct Firework { + strength: i32, +} + +impl Drop for Firework { + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() -> Result<(), u8> { + let _firecracker = Firework { strength: 1 }; + + let _tnt = Firework { strength: 100 }; + + if true { + println!("Exiting with error..."); + return Err(1); + } + + let _ = Firework { strength: 1000 }; + + Ok(()) +} + +// Expected program output: +// Exiting with error... +// BOOM times 100!!! +// BOOM times 1!!! +// Error: 1 diff --git a/tests/coverage-map/status-quo/generator.cov-map b/tests/coverage-map/status-quo/generator.cov-map new file mode 100644 index 00000000000..6e10b58a941 --- /dev/null +++ b/tests/coverage-map/status-quo/generator.cov-map @@ -0,0 +1,58 @@ +Function name: generator::get_u32 +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 01, 01, 0b, 05, 01, 0e, 00, 13, 02, 00, 1d, 00, 3c, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 11, 1) to (start + 1, 11) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 29) to (start + 0, 60) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: generator::main +Raw bytes (71): 0x[01, 01, 0b, 01, 00, 05, 0b, 09, 0d, 11, 00, 11, 15, 2a, 19, 11, 15, 15, 19, 26, 00, 2a, 19, 11, 15, 09, 01, 0f, 01, 02, 19, 03, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 07, 01, 0e, 00, 35, 0f, 02, 0b, 00, 2e, 2a, 01, 22, 00, 27, 26, 00, 2c, 00, 2e, 1f, 01, 0e, 00, 35, 23, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 11 +- expression 0 operands: lhs = Counter(0), rhs = Zero +- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Counter(4), rhs = Zero +- expression 4 operands: lhs = Counter(4), rhs = Counter(5) +- expression 5 operands: lhs = Expression(10, Sub), rhs = Counter(6) +- expression 6 operands: lhs = Counter(4), rhs = Counter(5) +- expression 7 operands: lhs = Counter(5), rhs = Counter(6) +- expression 8 operands: lhs = Expression(9, Sub), rhs = Zero +- expression 9 operands: lhs = Expression(10, Sub), rhs = Counter(6) +- expression 10 operands: lhs = Counter(4), rhs = Counter(5) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 25) +- Code(Expression(0, Add)) at (prev + 7, 11) to (start + 0, 46) + = (c0 + Zero) +- Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45) +- Code(Expression(1, Add)) at (prev + 1, 14) to (start + 0, 53) + = (c1 + (c2 + c3)) +- Code(Expression(3, Add)) at (prev + 2, 11) to (start + 0, 46) + = (c4 + Zero) +- Code(Expression(10, Sub)) at (prev + 1, 34) to (start + 0, 39) + = (c4 - c5) +- Code(Expression(9, Sub)) at (prev + 0, 44) to (start + 0, 46) + = ((c4 - c5) - c6) +- Code(Expression(7, Add)) at (prev + 1, 14) to (start + 0, 53) + = (c5 + c6) +- Code(Expression(8, Add)) at (prev + 2, 1) to (start + 0, 2) + = (((c4 - c5) - c6) + Zero) + +Function name: generator::main::{closure#0} +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 1c, 01, 1f, 05, 02, 10, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 28) to (start + 1, 31) +- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) + diff --git a/tests/coverage-map/status-quo/generator.rs b/tests/coverage-map/status-quo/generator.rs new file mode 100644 index 00000000000..4319991021e --- /dev/null +++ b/tests/coverage-map/status-quo/generator.rs @@ -0,0 +1,30 @@ +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +// The following implementation of a function called from a `yield` statement +// (apparently requiring the Result and the `String` type or constructor) +// creates conditions where the `generator::StateTransform` MIR transform will +// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic +// to handle this condition, and still report dead block coverage. +fn get_u32(val: bool) -> Result<u32, String> { + if val { Ok(1) } else { Err(String::from("some error")) } +} + +fn main() { + let is_true = std::env::args().len() == 1; + let mut generator = || { + yield get_u32(is_true); + return "foo"; + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(Ok(1)) => {} + _ => panic!("unexpected return from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected return from resume"), + } +} diff --git a/tests/coverage-map/status-quo/generics.cov-map b/tests/coverage-map/status-quo/generics.cov-map new file mode 100644 index 00000000000..6079a433cd0 --- /dev/null +++ b/tests/coverage-map/status-quo/generics.cov-map @@ -0,0 +1,45 @@ +Function name: <generics::Firework<f64> as core::ops::drop::Drop>::drop +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) + +Function name: <generics::Firework<f64>>::set_strength +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) + +Function name: <generics::Firework<i32> as core::ops::drop::Drop>::drop +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) + +Function name: <generics::Firework<i32>>::set_strength +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) + +Function name: generics::main +Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(1), rhs = Zero +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12) +- Code(Counter(1)) at (prev + 9, 9) to (start + 1, 22) +- Code(Zero) at (prev + 2, 6) to (start + 4, 11) +- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2) + = (c1 + Zero) + diff --git a/tests/coverage-map/status-quo/generics.rs b/tests/coverage-map/status-quo/generics.rs new file mode 100644 index 00000000000..bf4c2d8d685 --- /dev/null +++ b/tests/coverage-map/status-quo/generics.rs @@ -0,0 +1,44 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +struct Firework<T> where T: Copy + std::fmt::Display { + strength: T, +} + +impl<T> Firework<T> where T: Copy + std::fmt::Display { + #[inline(always)] + fn set_strength(&mut self, new_strength: T) { + self.strength = new_strength; + } +} + +impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display { + #[inline(always)] + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() -> Result<(), u8> { + let mut firecracker = Firework { strength: 1 }; + firecracker.set_strength(2); + + let mut tnt = Firework { strength: 100.1 }; + tnt.set_strength(200.1); + tnt.set_strength(300.3); + + if true { + println!("Exiting with error..."); + return Err(1); + } + + let _ = Firework { strength: 1000 }; + + Ok(()) +} + +// Expected program output: +// Exiting with error... +// BOOM times 100!!! +// BOOM times 1!!! +// Error: 1 diff --git a/tests/coverage-map/status-quo/if.cov-map b/tests/coverage-map/status-quo/if.cov-map new file mode 100644 index 00000000000..391a69e0e82 --- /dev/null +++ b/tests/coverage-map/status-quo/if.cov-map @@ -0,0 +1,15 @@ +Function name: if::main +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 03, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 3, 1) to (start + 18, 16) +- Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6) +- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage-map/status-quo/if.rs b/tests/coverage-map/status-quo/if.rs new file mode 100644 index 00000000000..8ad5042ff7b --- /dev/null +++ b/tests/coverage-map/status-quo/if.rs @@ -0,0 +1,28 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let + is_true + = + std::env::args().len() + == + 1 + ; + let + mut + countdown + = + 0 + ; + if + is_true + { + countdown + = + 10 + ; + } +} diff --git a/tests/coverage-map/status-quo/if_else.cov-map b/tests/coverage-map/status-quo/if_else.cov-map new file mode 100644 index 00000000000..da692ca3aa2 --- /dev/null +++ b/tests/coverage-map/status-quo/if_else.cov-map @@ -0,0 +1,25 @@ +Function name: if_else::main +Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 1b, 06, 09, 00, 10, 09, 01, 05, 05, 06, 16, 07, 05, 05, 06, 13, 06, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 7 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2) +- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub) +- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2) +- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 3, 1) to (start + 8, 16) +- Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6) +- Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16) + = (c0 - c1) +- Code(Expression(6, Add)) at (prev + 6, 9) to (start + 0, 16) + = (c1 + (c0 - c1)) +- Code(Counter(2)) at (prev + 1, 5) to (start + 5, 6) +- Code(Expression(5, Sub)) at (prev + 7, 5) to (start + 5, 6) + = ((c1 + (c0 - c1)) - c2) +- Code(Expression(4, Add)) at (prev + 6, 1) to (start + 0, 2) + = (c2 + ((c1 + (c0 - c1)) - c2)) + diff --git a/tests/coverage-map/status-quo/if_else.rs b/tests/coverage-map/status-quo/if_else.rs new file mode 100644 index 00000000000..3244e1e3afd --- /dev/null +++ b/tests/coverage-map/status-quo/if_else.rs @@ -0,0 +1,40 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if + is_true + { + countdown + = + 10 + ; + } + else // Note coverage region difference without semicolon + { + countdown + = + 100 + } + + if + is_true + { + countdown + = + 10 + ; + } + else + { + countdown + = + 100 + ; + } +} diff --git a/tests/coverage-map/status-quo/inline-dead.cov-map b/tests/coverage-map/status-quo/inline-dead.cov-map new file mode 100644 index 00000000000..dec43d3e8bb --- /dev/null +++ b/tests/coverage-map/status-quo/inline-dead.cov-map @@ -0,0 +1,45 @@ +Function name: inline_dead::dead (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 19, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 25, 1) to (start + 2, 2) + +Function name: inline_dead::live::<false> +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 10, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 9) +- Code(Zero) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: inline_dead::main +Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 04, 01, 03, 0d, 03, 07, 06, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Zero +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 13) +- Code(Expression(0, Add)) at (prev + 7, 6) to (start + 2, 2) + = (c0 + Zero) + +Function name: inline_dead::main::{closure#0} +Raw bytes (16): 0x[01, 01, 01, 01, 05, 02, 00, 09, 0d, 00, 0e, 03, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 9, 13) to (start + 0, 14) +- Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6) + = (c0 + c1) + diff --git a/tests/coverage-map/status-quo/inline-dead.rs b/tests/coverage-map/status-quo/inline-dead.rs new file mode 100644 index 00000000000..854fa062967 --- /dev/null +++ b/tests/coverage-map/status-quo/inline-dead.rs @@ -0,0 +1,27 @@ +// Regression test for issue #98833. +// compile-flags: -Zinline-mir -Cdebug-assertions=off + +fn main() { + println!("{}", live::<false>()); + + let f = |x: bool| { + debug_assert!( + x + ); + }; + f(false); +} + +#[inline] +fn live<const B: bool>() -> u32 { + if B { + dead() + } else { + 0 + } +} + +#[inline] +fn dead() -> u32 { + 42 +} diff --git a/tests/coverage-map/status-quo/inline.cov-map b/tests/coverage-map/status-quo/inline.cov-map new file mode 100644 index 00000000000..57ae85623fb --- /dev/null +++ b/tests/coverage-map/status-quo/inline.cov-map @@ -0,0 +1,82 @@ +Function name: inline::display::<char> +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 00, 03, 05, 05, 01, 29, 01, 00, 22, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 10, 07, 00, 11, 02, 06, 0a, 03, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Zero +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(1) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 34) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) +- Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 16) + = (c0 + c1) +- Code(Expression(1, Add)) at (prev + 0, 17) to (start + 2, 6) + = (c1 + Zero) +- Code(Expression(2, Sub)) at (prev + 3, 5) to (start + 1, 2) + = ((c0 + c1) - c1) + +Function name: inline::error +Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2) + +Function name: inline::length::<char> +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2) + +Function name: inline::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 5, 1) to (start + 2, 2) + +Function name: inline::permutate::<char> +Raw bytes (54): 0x[01, 01, 05, 01, 05, 02, 0d, 11, 00, 05, 13, 09, 0d, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 06, 00, 12, 00, 16, 0b, 00, 17, 04, 0a, 0d, 05, 0c, 02, 06, 0f, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(3) +- expression 2 operands: lhs = Counter(4), rhs = Zero +- expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 14) +- Code(Counter(1)) at (prev + 2, 15) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 15) to (start + 0, 20) + = (c0 - c1) +- Code(Counter(4)) at (prev + 1, 13) to (start + 0, 14) +- Code(Expression(1, Sub)) at (prev + 0, 18) to (start + 0, 22) + = ((c0 - c1) - c3) +- Code(Expression(2, Add)) at (prev + 0, 23) to (start + 4, 10) + = (c4 + Zero) +- Code(Counter(3)) at (prev + 5, 12) to (start + 2, 6) +- Code(Expression(3, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c1 + (c2 + c3)) + +Function name: inline::permutations::<char> +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 1) to (start + 3, 2) + +Function name: inline::swap::<char> +Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 35, 1) to (start + 4, 2) + diff --git a/tests/coverage-map/status-quo/inline.rs b/tests/coverage-map/status-quo/inline.rs new file mode 100644 index 00000000000..9cfab9ddbad --- /dev/null +++ b/tests/coverage-map/status-quo/inline.rs @@ -0,0 +1,51 @@ +// compile-flags: -Zinline-mir + +use std::fmt::Display; + +fn main() { + permutations(&['a', 'b', 'c']); +} + +#[inline(always)] +fn permutations<T: Copy + Display>(xs: &[T]) { + let mut ys = xs.to_owned(); + permutate(&mut ys, 0); +} + +fn permutate<T: Copy + Display>(xs: &mut [T], k: usize) { + let n = length(xs); + if k == n { + display(xs); + } else if k < n { + for i in k..n { + swap(xs, i, k); + permutate(xs, k + 1); + swap(xs, i, k); + } + } else { + error(); + } +} + +fn length<T>(xs: &[T]) -> usize { + xs.len() +} + +#[inline] +fn swap<T: Copy>(xs: &mut [T], i: usize, j: usize) { + let t = xs[i]; + xs[i] = xs[j]; + xs[j] = t; +} + +fn display<T: Display>(xs: &[T]) { + for x in xs { + print!("{}", x); + } + println!(); +} + +#[inline(always)] +fn error() { + panic!("error"); +} diff --git a/tests/coverage-map/status-quo/inner_items.cov-map b/tests/coverage-map/status-quo/inner_items.cov-map new file mode 100644 index 00000000000..3f39d74efba --- /dev/null +++ b/tests/coverage-map/status-quo/inner_items.cov-map @@ -0,0 +1,49 @@ +Function name: <inner_items::main::InStruct as inner_items::main::InTrait>::default_trait_func +Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 09, 03, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 33, 9) to (start + 3, 10) + +Function name: <inner_items::main::InStruct as inner_items::main::InTrait>::trait_func +Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 09, 03, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10) + +Function name: inner_items::main +Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1b, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 16, 02, 06, 00, 07, 13, 02, 09, 05, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 7 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2) +- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub) +- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2) +- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) +- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(6, Add)) at (prev + 36, 8) to (start + 0, 15) + = (c1 + (c0 - c1)) +- Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6) +- Code(Expression(5, Sub)) at (prev + 2, 6) to (start + 0, 7) + = ((c1 + (c0 - c1)) - c2) +- Code(Expression(4, Add)) at (prev + 2, 9) to (start + 5, 2) + = (c2 + ((c1 + (c0 - c1)) - c2)) + +Function name: inner_items::main::in_func +Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 18, 5) to (start + 4, 6) + diff --git a/tests/coverage-map/status-quo/inner_items.rs b/tests/coverage-map/status-quo/inner_items.rs new file mode 100644 index 00000000000..bcb62b3031c --- /dev/null +++ b/tests/coverage-map/status-quo/inner_items.rs @@ -0,0 +1,57 @@ +#![allow(unused_assignments, unused_variables, dead_code)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } + + mod in_mod { + const IN_MOD_CONST: u32 = 1000; + } + + fn in_func(a: u32) { + let b = 1; + let c = a + b; + println!("c = {}", c) + } + + struct InStruct { + in_struct_field: u32, + } + + const IN_CONST: u32 = 1234; + + trait InTrait { + fn trait_func(&mut self, incr: u32); + + fn default_trait_func(&mut self) { + in_func(IN_CONST); + self.trait_func(IN_CONST); + } + } + + impl InTrait for InStruct { + fn trait_func(&mut self, incr: u32) { + self.in_struct_field += incr; + in_func(self.in_struct_field); + } + } + + type InType = String; + + if is_true { + in_func(countdown); + } + + let mut val = InStruct { + in_struct_field: 101, + }; + + val.default_trait_func(); +} diff --git a/tests/coverage-map/status-quo/issue-83601.cov-map b/tests/coverage-map/status-quo/issue-83601.cov-map new file mode 100644 index 00000000000..f5db3a89750 --- /dev/null +++ b/tests/coverage-map/status-quo/issue-83601.cov-map @@ -0,0 +1,28 @@ +Function name: <issue_83601::Foo as core::cmp::PartialEq>::eq +Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 11, 00, 1a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 3, 17) to (start + 0, 26) + +Function name: <issue_83601::Foo as core::fmt::Debug>::fmt +Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 0a, 00, 0f] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 3, 10) to (start + 0, 15) + +Function name: issue_83601::main +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28) +- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2) + = (c1 - c2) + diff --git a/tests/coverage-map/status-quo/issue-83601.rs b/tests/coverage-map/status-quo/issue-83601.rs new file mode 100644 index 00000000000..0b72a81947c --- /dev/null +++ b/tests/coverage-map/status-quo/issue-83601.rs @@ -0,0 +1,14 @@ +// Shows that rust-lang/rust/83601 is resolved + +#[derive(Debug, PartialEq, Eq)] +struct Foo(u32); + +fn main() { + let bar = Foo(1); + assert_eq!(bar, Foo(1)); + let baz = Foo(0); + assert_ne!(baz, Foo(1)); + println!("{:?}", Foo(1)); + println!("{:?}", bar); + println!("{:?}", baz); +} diff --git a/tests/coverage-map/status-quo/issue-84561.cov-map b/tests/coverage-map/status-quo/issue-84561.cov-map new file mode 100644 index 00000000000..fe098fd396c --- /dev/null +++ b/tests/coverage-map/status-quo/issue-84561.cov-map @@ -0,0 +1,233 @@ +Function name: <issue_84561::Foo as core::cmp::PartialEq>::eq +Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 0a, 00, 13, 00, 00, 0a, 00, 13] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19) +- Code(Zero) at (prev + 0, 10) to (start + 0, 19) + +Function name: <issue_84561::Foo as core::fmt::Debug>::fmt +Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 89, 01, 09, 00, 25, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 137, 9) to (start + 0, 37) +- Code(Counter(1)) at (prev + 0, 37) to (start + 0, 38) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6) + = (c1 + (c0 - c1)) + +Function name: issue_84561::main +Raw bytes (10): 0x[01, 01, 00, 01, 01, b2, 01, 01, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 178, 1) to (start + 4, 2) + +Function name: issue_84561::test1 +Raw bytes (78): 0x[01, 01, 0e, 05, 06, 01, 05, 09, 36, 03, 09, 0d, 2e, 33, 0d, 09, 36, 03, 09, 11, 26, 2b, 11, 0d, 2e, 33, 0d, 09, 36, 03, 09, 09, 01, 98, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 03, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 33, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 2b, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 23, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 14 +- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +- expression 2 operands: lhs = Counter(2), rhs = Expression(13, Sub) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 4 operands: lhs = Counter(3), rhs = Expression(11, Sub) +- expression 5 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 6 operands: lhs = Counter(2), rhs = Expression(13, Sub) +- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 8 operands: lhs = Counter(4), rhs = Expression(9, Sub) +- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(4) +- expression 10 operands: lhs = Counter(3), rhs = Expression(11, Sub) +- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 12 operands: lhs = Counter(2), rhs = Expression(13, Sub) +- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(2) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 152, 1) to (start + 1, 11) +- Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30) +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 11) + = (c1 + (c0 - c1)) +- Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30) +- Code(Expression(12, Add)) at (prev + 1, 13) to (start + 1, 11) + = (c2 + ((c1 + (c0 - c1)) - c2)) +- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30) +- Code(Expression(10, Add)) at (prev + 1, 5) to (start + 3, 11) + = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) +- Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30) +- Code(Expression(8, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) + +Function name: issue_84561::test2 +Raw bytes (24): 0x[01, 01, 02, 05, 06, 01, 05, 03, 01, ae, 01, 01, 01, 10, 05, 01, 11, 00, 23, 03, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 174, 1) to (start + 1, 16) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35) +- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: issue_84561::test2::call_print +Raw bytes (10): 0x[01, 01, 00, 01, 01, a5, 01, 09, 02, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 165, 9) to (start + 2, 10) + +Function name: issue_84561::test3 +Raw bytes (437): 0x[01, 01, 41, 05, 09, 0d, 11, 15, 19, 12, 1d, 15, 19, 21, 25, 1e, 29, 21, 25, 31, 39, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 4d, 3f, 51, 42, 49, 45, 4d, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 59, 92, 01, 55, 51, 59, 8f, 01, 5d, 92, 01, 55, 51, 59, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 59, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 59, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 71, fe, 01, 82, 02, 71, 69, 6d, 69, 6d, 82, 02, 71, 69, 6d, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, ee, 01, 81, 01, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 33, 01, 06, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 71, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 65 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(3), rhs = Counter(4) +- expression 2 operands: lhs = Counter(5), rhs = Counter(6) +- expression 3 operands: lhs = Expression(4, Sub), rhs = Counter(7) +- expression 4 operands: lhs = Counter(5), rhs = Counter(6) +- expression 5 operands: lhs = Counter(8), rhs = Counter(9) +- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(10) +- expression 7 operands: lhs = Counter(8), rhs = Counter(9) +- expression 8 operands: lhs = Counter(12), rhs = Counter(14) +- expression 9 operands: lhs = Counter(15), rhs = Counter(16) +- expression 10 operands: lhs = Expression(11, Sub), rhs = Counter(17) +- expression 11 operands: lhs = Counter(15), rhs = Counter(16) +- expression 12 operands: lhs = Expression(16, Sub), rhs = Counter(18) +- expression 13 operands: lhs = Counter(17), rhs = Counter(19) +- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(20) +- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(18) +- expression 16 operands: lhs = Counter(17), rhs = Counter(19) +- expression 17 operands: lhs = Counter(23), rhs = Expression(34, Sub) +- expression 18 operands: lhs = Expression(35, Add), rhs = Counter(23) +- expression 19 operands: lhs = Expression(36, Sub), rhs = Counter(21) +- expression 20 operands: lhs = Counter(20), rhs = Counter(22) +- expression 21 operands: lhs = Expression(36, Sub), rhs = Counter(21) +- expression 22 operands: lhs = Counter(20), rhs = Counter(22) +- expression 23 operands: lhs = Expression(35, Add), rhs = Counter(23) +- expression 24 operands: lhs = Expression(36, Sub), rhs = Counter(21) +- expression 25 operands: lhs = Counter(20), rhs = Counter(22) +- expression 26 operands: lhs = Expression(33, Add), rhs = Counter(24) +- expression 27 operands: lhs = Counter(23), rhs = Expression(34, Sub) +- expression 28 operands: lhs = Expression(35, Add), rhs = Counter(23) +- expression 29 operands: lhs = Expression(36, Sub), rhs = Counter(21) +- expression 30 operands: lhs = Counter(20), rhs = Counter(22) +- expression 31 operands: lhs = Expression(32, Sub), rhs = Counter(25) +- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(24) +- expression 33 operands: lhs = Counter(23), rhs = Expression(34, Sub) +- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(23) +- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(21) +- expression 36 operands: lhs = Counter(20), rhs = Counter(22) +- expression 37 operands: lhs = Counter(29), rhs = Expression(61, Sub) +- expression 38 operands: lhs = Expression(62, Add), rhs = Counter(30) +- expression 39 operands: lhs = Counter(28), rhs = Expression(63, Sub) +- expression 40 operands: lhs = Expression(64, Sub), rhs = Counter(28) +- expression 41 operands: lhs = Counter(26), rhs = Counter(27) +- expression 42 operands: lhs = Counter(28), rhs = Expression(63, Sub) +- expression 43 operands: lhs = Expression(64, Sub), rhs = Counter(28) +- expression 44 operands: lhs = Counter(26), rhs = Counter(27) +- expression 45 operands: lhs = Counter(26), rhs = Counter(27) +- expression 46 operands: lhs = Expression(64, Sub), rhs = Counter(28) +- expression 47 operands: lhs = Counter(26), rhs = Counter(27) +- expression 48 operands: lhs = Expression(62, Add), rhs = Counter(30) +- expression 49 operands: lhs = Counter(28), rhs = Expression(63, Sub) +- expression 50 operands: lhs = Expression(64, Sub), rhs = Counter(28) +- expression 51 operands: lhs = Counter(26), rhs = Counter(27) +- expression 52 operands: lhs = Expression(60, Add), rhs = Counter(31) +- expression 53 operands: lhs = Counter(29), rhs = Expression(61, Sub) +- expression 54 operands: lhs = Expression(62, Add), rhs = Counter(30) +- expression 55 operands: lhs = Counter(28), rhs = Expression(63, Sub) +- expression 56 operands: lhs = Expression(64, Sub), rhs = Counter(28) +- expression 57 operands: lhs = Counter(26), rhs = Counter(27) +- expression 58 operands: lhs = Expression(59, Sub), rhs = Counter(32) +- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(31) +- expression 60 operands: lhs = Counter(29), rhs = Expression(61, Sub) +- expression 61 operands: lhs = Expression(62, Add), rhs = Counter(30) +- expression 62 operands: lhs = Counter(28), rhs = Expression(63, Sub) +- expression 63 operands: lhs = Expression(64, Sub), rhs = Counter(28) +- expression 64 operands: lhs = Counter(26), rhs = Counter(27) +Number of file 0 mappings: 51 +- Code(Counter(0)) at (prev + 6, 1) to (start + 3, 28) +- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 4, 31) + = (c1 - c2) +- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 31) +- Code(Expression(1, Sub)) at (prev + 1, 5) to (start + 0, 31) + = (c3 - c4) +- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28) +- Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 31) + = (c5 - c6) +- Code(Expression(3, Sub)) at (prev + 1, 5) to (start + 0, 15) + = ((c5 - c6) - c7) +- Code(Zero) at (prev + 0, 32) to (start + 0, 48) +- Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15) +- Code(Zero) at (prev + 3, 32) to (start + 0, 48) +- Code(Zero) at (prev + 0, 51) to (start + 0, 65) +- Code(Zero) at (prev + 0, 75) to (start + 0, 90) +- Code(Expression(7, Sub)) at (prev + 1, 5) to (start + 0, 15) + = (c8 - c9) +- Code(Zero) at (prev + 5, 9) to (start + 3, 16) +- Code(Zero) at (prev + 5, 13) to (start + 0, 27) +- Code(Zero) at (prev + 2, 13) to (start + 0, 28) +- Code(Expression(6, Sub)) at (prev + 4, 9) to (start + 5, 6) + = ((c8 - c9) - c10) +- Code(Counter(12)) at (prev + 6, 5) to (start + 3, 6) +- Code(Expression(8, Sub)) at (prev + 4, 5) to (start + 3, 6) + = (c12 - c14) +- Code(Counter(15)) at (prev + 4, 9) to (start + 4, 6) +- Code(Expression(11, Sub)) at (prev + 5, 8) to (start + 0, 15) + = (c15 - c16) +- Code(Counter(17)) at (prev + 1, 9) to (start + 3, 10) +- Code(Expression(10, Sub)) at (prev + 5, 9) to (start + 3, 10) + = ((c15 - c16) - c17) +- Code(Expression(15, Add)) at (prev + 5, 8) to (start + 0, 15) + = ((c17 - c19) + c18) +- Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19) +- Code(Zero) at (prev + 3, 13) to (start + 0, 29) +- Code(Expression(14, Sub)) at (prev + 3, 9) to (start + 0, 19) + = (((c17 - c19) + c18) - c20) +- Code(Zero) at (prev + 3, 13) to (start + 0, 29) +- Code(Expression(33, Add)) at (prev + 3, 5) to (start + 0, 15) + = (c23 + (((c20 - c22) + c21) - c23)) +- Code(Expression(35, Add)) at (prev + 1, 12) to (start + 0, 19) + = ((c20 - c22) + c21) +- Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19) +- Code(Expression(34, Sub)) at (prev + 2, 13) to (start + 0, 19) + = (((c20 - c22) + c21) - c23) +- Code(Expression(32, Sub)) at (prev + 4, 5) to (start + 2, 19) + = ((c23 + (((c20 - c22) + c21) - c23)) - c24) +- Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19) +- Code(Expression(31, Sub)) at (prev + 2, 13) to (start + 0, 19) + = (((c23 + (((c20 - c22) + c21) - c23)) - c24) - c25) +- Code(Expression(60, Add)) at (prev + 3, 5) to (start + 0, 15) + = (c29 + ((c28 + ((c26 - c27) - c28)) - c30)) +- Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19) +- Code(Counter(27)) at (prev + 1, 13) to (start + 3, 14) +- Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19) +- Code(Expression(62, Add)) at (prev + 2, 13) to (start + 0, 23) + = (c28 + ((c26 - c27) - c28)) +- Code(Expression(64, Sub)) at (prev + 1, 20) to (start + 0, 27) + = (c26 - c27) +- Code(Counter(28)) at (prev + 1, 21) to (start + 0, 27) +- Code(Expression(63, Sub)) at (prev + 2, 21) to (start + 0, 27) + = ((c26 - c27) - c28) +- Code(Expression(61, Sub)) at (prev + 4, 13) to (start + 0, 19) + = ((c28 + ((c26 - c27) - c28)) - c30) +- Code(Counter(31)) at (prev + 3, 9) to (start + 0, 25) +- Code(Expression(59, Sub)) at (prev + 2, 5) to (start + 0, 15) + = ((c29 + ((c28 + ((c26 - c27) - c28)) - c30)) - c31) +- Code(Expression(58, Sub)) at (prev + 3, 9) to (start + 0, 34) + = (((c29 + ((c28 + ((c26 - c27) - c28)) - c30)) - c31) - c32) +- Code(Zero) at (prev + 2, 5) to (start + 0, 15) +- Code(Zero) at (prev + 3, 9) to (start + 0, 44) +- Code(Zero) at (prev + 2, 1) to (start + 0, 2) + diff --git a/tests/coverage-map/status-quo/issue-84561.rs b/tests/coverage-map/status-quo/issue-84561.rs new file mode 100644 index 00000000000..facf5b5b4cf --- /dev/null +++ b/tests/coverage-map/status-quo/issue-84561.rs @@ -0,0 +1,182 @@ +// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. + +// failure-status: 101 +#[derive(PartialEq, Eq)] +struct Foo(u32); +fn test3() { + let is_true = std::env::args().len() == 1; + let bar = Foo(1); + assert_eq!(bar, Foo(1)); + let baz = Foo(0); + assert_ne!(baz, Foo(1)); + println!("{:?}", Foo(1)); + println!("{:?}", bar); + println!("{:?}", baz); + + assert_eq!(Foo(1), Foo(1)); + assert_ne!(Foo(0), Foo(1)); + assert_eq!(Foo(2), Foo(2)); + let bar = Foo(0); + assert_ne!(bar, Foo(3)); + assert_ne!(Foo(0), Foo(4)); + assert_eq!(Foo(3), Foo(3), "with a message"); + println!("{:?}", bar); + println!("{:?}", Foo(1)); + + assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); + assert_ne!( + Foo(0) + , + Foo(5) + , + "{}" + , + if + is_true + { + "true message" + } else { + "false message" + } + ); + + let is_true = std::env::args().len() == 1; + + assert_eq!( + Foo(1), + Foo(1) + ); + assert_ne!( + Foo(0), + Foo(1) + ); + assert_eq!( + Foo(2), + Foo(2) + ); + let bar = Foo(1); + assert_ne!( + bar, + Foo(3) + ); + if is_true { + assert_ne!( + Foo(0), + Foo(4) + ); + } else { + assert_eq!( + Foo(3), + Foo(3) + ); + } + if is_true { + assert_ne!( + Foo(0), + Foo(4), + "with a message" + ); + } else { + assert_eq!( + Foo(3), + Foo(3), + "with a message" + ); + } + assert_ne!( + if is_true { + Foo(0) + } else { + Foo(1) + }, + Foo(5) + ); + assert_ne!( + Foo(5), + if is_true { + Foo(0) + } else { + Foo(1) + } + ); + assert_ne!( + if is_true { + assert_eq!( + Foo(3), + Foo(3) + ); + Foo(0) + } else { + assert_ne!( + if is_true { + Foo(0) + } else { + Foo(1) + }, + Foo(5) + ); + Foo(1) + }, + Foo(5), + "with a message" + ); + assert_eq!( + Foo(1), + Foo(3), + "this assert should fail" + ); + assert_eq!( + Foo(3), + Foo(3), + "this assert should not be reached" + ); +} + +impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "try and succeed")?; + Ok(()) + } +} + +static mut DEBUG_LEVEL_ENABLED: bool = false; + +macro_rules! debug { + ($($arg:tt)+) => ( + if unsafe { DEBUG_LEVEL_ENABLED } { + println!($($arg)+); + } + ); +} + +fn test1() { + debug!("debug is enabled"); + debug!("debug is enabled"); + let _ = 0; + debug!("debug is enabled"); + unsafe { + DEBUG_LEVEL_ENABLED = true; + } + debug!("debug is enabled"); +} + +macro_rules! call_debug { + ($($arg:tt)+) => ( + fn call_print(s: &str) { + print!("{}", s); + } + + call_print("called from call_debug: "); + debug!($($arg)+); + ); +} + +fn test2() { + call_debug!("debug is enabled"); +} + +fn main() { + test1(); + test2(); + test3(); +} diff --git a/tests/coverage-map/status-quo/issue-93054.cov-map b/tests/coverage-map/status-quo/issue-93054.cov-map new file mode 100644 index 00000000000..52fe7f58d15 --- /dev/null +++ b/tests/coverage-map/status-quo/issue-93054.cov-map @@ -0,0 +1,24 @@ +Function name: issue_93054::foo2 (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 01, 00, 1d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 29) + +Function name: issue_93054::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 00, 0d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 13) + +Function name: issue_93054::make (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 2) + diff --git a/tests/coverage-map/status-quo/issue-93054.rs b/tests/coverage-map/status-quo/issue-93054.rs new file mode 100644 index 00000000000..da546cfeef8 --- /dev/null +++ b/tests/coverage-map/status-quo/issue-93054.rs @@ -0,0 +1,30 @@ +#![allow(dead_code, unreachable_code)] + +// Regression test for #93054: Functions using uninhabited types often only have a single, +// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. +// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. + +// compile-flags: --edition=2021 + +enum Never {} + +impl Never { + fn foo(self) { + match self {} + make().map(|never| match never {}); + } + + fn bar(&self) { + match *self {} + } +} + +async fn foo2(never: Never) { + match never {} +} + +fn make() -> Option<Never> { + None +} + +fn main() {} diff --git a/tests/coverage-map/status-quo/lazy_boolean.cov-map b/tests/coverage-map/status-quo/lazy_boolean.cov-map new file mode 100644 index 00000000000..b18a9640433 --- /dev/null +++ b/tests/coverage-map/status-quo/lazy_boolean.cov-map @@ -0,0 +1,223 @@ +Function name: lazy_boolean::main +Raw bytes (646): 0x[01, 01, a8, 01, 01, 05, 09, 9a, 05, 9f, 05, 09, 05, 02, 05, 02, 9f, 05, 09, 05, 02, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 97, 05, 00, 09, 9a, 05, 9f, 05, 09, 05, 02, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 8f, 05, 00, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 87, 05, 00, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, ff, 04, 00, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, f7, 04, 1d, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 1d, f2, 04, f7, 04, 1d, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, ef, 04, 21, 1d, f2, 04, f7, 04, 1d, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 21, ea, 04, ef, 04, 21, 1d, f2, 04, f7, 04, 1d, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, e7, 04, 25, 21, ea, 04, ef, 04, 21, 1d, f2, 04, f7, 04, 1d, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 25, e2, 04, e7, 04, 25, 21, ea, 04, ef, 04, 21, 1d, f2, 04, f7, 04, 1d, 19, fa, 04, ff, 04, 19, 15, 82, 05, 87, 05, 15, 11, 8a, 05, 8f, 05, 11, 0d, 92, 05, 97, 05, 0d, 09, 9a, 05, 9f, 05, 09, 05, 02, 1c, 01, 03, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 97, 05, 02, 09, 00, 11, 9f, 05, 02, 0d, 00, 12, 9a, 05, 02, 0d, 00, 12, 8f, 05, 03, 09, 00, 11, 33, 02, 0d, 00, 12, 92, 05, 02, 0d, 00, 12, 87, 05, 02, 09, 00, 11, 6f, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ff, 04, 01, 09, 00, 11, ab, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, cb, 01, 04, 09, 00, 10, fa, 04, 01, 05, 03, 06, 19, 03, 06, 00, 07, f7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, f2, 04, 05, 05, 03, 06, ef, 04, 05, 09, 00, 10, ea, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, e7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, e2, 04, 02, 0c, 02, 06, df, 04, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 168 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 2 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 5 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 7 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 8 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 9 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 10 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 11 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 12 operands: lhs = Expression(165, Add), rhs = Zero +- expression 13 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 14 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 15 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 16 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 17 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 18 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 19 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 20 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 21 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 22 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 23 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 24 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 25 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 26 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 27 operands: lhs = Expression(163, Add), rhs = Zero +- expression 28 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 29 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 30 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 31 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 32 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 33 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 34 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 35 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 36 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 37 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 38 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 39 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 40 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 41 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 42 operands: lhs = Expression(161, Add), rhs = Zero +- expression 43 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 44 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 45 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 46 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 47 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 48 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 49 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 50 operands: lhs = Expression(159, Add), rhs = Zero +- expression 51 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 52 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 53 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 54 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 55 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 56 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 57 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 58 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 59 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 60 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 61 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 62 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 63 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 64 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 65 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 66 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 67 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 68 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 69 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 70 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 71 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 72 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 73 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 74 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 75 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 76 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 77 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 78 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 79 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 80 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 81 operands: lhs = Expression(157, Add), rhs = Counter(7) +- expression 82 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 83 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 84 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 85 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 86 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 87 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 88 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 89 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 90 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 91 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 92 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 93 operands: lhs = Counter(7), rhs = Expression(156, Sub) +- expression 94 operands: lhs = Expression(157, Add), rhs = Counter(7) +- expression 95 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 96 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 97 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 98 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 99 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 100 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 101 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 102 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 103 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 104 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 105 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 106 operands: lhs = Expression(155, Add), rhs = Counter(8) +- expression 107 operands: lhs = Counter(7), rhs = Expression(156, Sub) +- expression 108 operands: lhs = Expression(157, Add), rhs = Counter(7) +- expression 109 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 110 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 111 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 112 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 113 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 114 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 115 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 116 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 117 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 118 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 119 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 120 operands: lhs = Counter(8), rhs = Expression(154, Sub) +- expression 121 operands: lhs = Expression(155, Add), rhs = Counter(8) +- expression 122 operands: lhs = Counter(7), rhs = Expression(156, Sub) +- expression 123 operands: lhs = Expression(157, Add), rhs = Counter(7) +- expression 124 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 125 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 126 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 127 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 128 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 129 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 130 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 131 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 132 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 133 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 134 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 135 operands: lhs = Expression(153, Add), rhs = Counter(9) +- expression 136 operands: lhs = Counter(8), rhs = Expression(154, Sub) +- expression 137 operands: lhs = Expression(155, Add), rhs = Counter(8) +- expression 138 operands: lhs = Counter(7), rhs = Expression(156, Sub) +- expression 139 operands: lhs = Expression(157, Add), rhs = Counter(7) +- expression 140 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 141 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 142 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 143 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 144 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 145 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 146 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 147 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 148 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 149 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 150 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 151 operands: lhs = Counter(9), rhs = Expression(152, Sub) +- expression 152 operands: lhs = Expression(153, Add), rhs = Counter(9) +- expression 153 operands: lhs = Counter(8), rhs = Expression(154, Sub) +- expression 154 operands: lhs = Expression(155, Add), rhs = Counter(8) +- expression 155 operands: lhs = Counter(7), rhs = Expression(156, Sub) +- expression 156 operands: lhs = Expression(157, Add), rhs = Counter(7) +- expression 157 operands: lhs = Counter(6), rhs = Expression(158, Sub) +- expression 158 operands: lhs = Expression(159, Add), rhs = Counter(6) +- expression 159 operands: lhs = Counter(5), rhs = Expression(160, Sub) +- expression 160 operands: lhs = Expression(161, Add), rhs = Counter(5) +- expression 161 operands: lhs = Counter(4), rhs = Expression(162, Sub) +- expression 162 operands: lhs = Expression(163, Add), rhs = Counter(4) +- expression 163 operands: lhs = Counter(3), rhs = Expression(164, Sub) +- expression 164 operands: lhs = Expression(165, Add), rhs = Counter(3) +- expression 165 operands: lhs = Counter(2), rhs = Expression(166, Sub) +- expression 166 operands: lhs = Expression(167, Add), rhs = Counter(2) +- expression 167 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 28 +- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) +- Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6) +- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(165, Add)) at (prev + 2, 9) to (start + 0, 17) + = (c2 + ((c1 + (c0 - c1)) - c2)) +- Code(Expression(167, Add)) at (prev + 2, 13) to (start + 0, 18) + = (c1 + (c0 - c1)) +- Code(Expression(166, Sub)) at (prev + 2, 13) to (start + 0, 18) + = ((c1 + (c0 - c1)) - c2) +- Code(Expression(163, Add)) at (prev + 3, 9) to (start + 0, 17) + = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) +- Code(Expression(12, Add)) at (prev + 2, 13) to (start + 0, 18) + = ((c2 + ((c1 + (c0 - c1)) - c2)) + Zero) +- Code(Expression(164, Sub)) at (prev + 2, 13) to (start + 0, 18) + = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3) +- Code(Expression(161, Add)) at (prev + 2, 9) to (start + 0, 17) + = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) +- Code(Expression(27, Add)) at (prev + 0, 20) to (start + 0, 25) + = ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) + Zero) +- Code(Counter(4)) at (prev + 0, 29) to (start + 0, 34) +- Code(Expression(159, Add)) at (prev + 1, 9) to (start + 0, 17) + = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) +- Code(Expression(42, Add)) at (prev + 0, 20) to (start + 0, 25) + = ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) + Zero) +- Code(Counter(5)) at (prev + 0, 29) to (start + 0, 34) +- Code(Expression(50, Add)) at (prev + 4, 9) to (start + 0, 16) + = ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) + Zero) +- Code(Expression(158, Sub)) at (prev + 1, 5) to (start + 3, 6) + = ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6) +- Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(157, Add)) at (prev + 3, 9) to (start + 0, 16) + = (c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) +- Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6) +- Code(Expression(156, Sub)) at (prev + 5, 5) to (start + 3, 6) + = ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7) +- Code(Expression(155, Add)) at (prev + 5, 9) to (start + 0, 16) + = (c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) +- Code(Expression(154, Sub)) at (prev + 0, 17) to (start + 2, 6) + = ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8) +- Code(Counter(8)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(153, Add)) at (prev + 2, 8) to (start + 0, 15) + = (c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) +- Code(Counter(9)) at (prev + 0, 16) to (start + 2, 6) +- Code(Expression(152, Sub)) at (prev + 2, 12) to (start + 2, 6) + = ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9) +- Code(Expression(151, Add)) at (prev + 3, 1) to (start + 0, 2) + = (c9 + ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9)) + diff --git a/tests/coverage-map/status-quo/lazy_boolean.rs b/tests/coverage-map/status-quo/lazy_boolean.rs new file mode 100644 index 00000000000..bb6219e851c --- /dev/null +++ b/tests/coverage-map/status-quo/lazy_boolean.rs @@ -0,0 +1,61 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let (mut a, mut b, mut c) = (0, 0, 0); + if is_true { + a = 1; + b = 10; + c = 100; + } + let + somebool + = + a < b + || + b < c + ; + let + somebool + = + b < a + || + b < c + ; + let somebool = a < b && b < c; + let somebool = b < a && b < c; + + if + ! + is_true + { + a = 2 + ; + } + + if + is_true + { + b = 30 + ; + } + else + { + c = 400 + ; + } + + if !is_true { + a = 2; + } + + if is_true { + b = 30; + } else { + c = 400; + } +} diff --git a/tests/coverage-map/status-quo/loop_break_value.cov-map b/tests/coverage-map/status-quo/loop_break_value.cov-map new file mode 100644 index 00000000000..75018442d07 --- /dev/null +++ b/tests/coverage-map/status-quo/loop_break_value.cov-map @@ -0,0 +1,8 @@ +Function name: loop_break_value::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 0a, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 3, 1) to (start + 10, 2) + diff --git a/tests/coverage-map/status-quo/loop_break_value.rs b/tests/coverage-map/status-quo/loop_break_value.rs new file mode 100644 index 00000000000..dbc4fad7a23 --- /dev/null +++ b/tests/coverage-map/status-quo/loop_break_value.rs @@ -0,0 +1,13 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let result + = + loop + { + break + 10 + ; + } + ; +} diff --git a/tests/coverage-map/status-quo/loops_branches.cov-map b/tests/coverage-map/status-quo/loops_branches.cov-map new file mode 100644 index 00000000000..56fafc0a67b --- /dev/null +++ b/tests/coverage-map/status-quo/loops_branches.cov-map @@ -0,0 +1,193 @@ +Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt +Raw bytes (262): 0x[01, 01, 36, 05, 09, 0a, 02, 00, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 00, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 25, b3, 01, b6, 01, 19, bb, 01, 11, be, 01, c2, 01, 00, 00, c6, 01, 1d, ca, 01, 15, cf, 01, 19, d3, 01, d7, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, ca, 01, 03, 0d, 00, 0e, cf, 01, 00, 12, 00, 17, 2b, 01, 10, 00, 14, c6, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c2, 01, 01, 12, 00, 13, bb, 01, 01, 11, 00, 22, b6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, af, 01, 01, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 54 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Expression(2, Sub), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Zero, rhs = Zero +- expression 3 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 4 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 5 operands: lhs = Counter(3), rhs = Zero +- expression 6 operands: lhs = Counter(4), rhs = Counter(5) +- expression 7 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 8 operands: lhs = Counter(3), rhs = Zero +- expression 9 operands: lhs = Counter(4), rhs = Counter(5) +- expression 10 operands: lhs = Expression(50, Sub), rhs = Zero +- expression 11 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 12 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 13 operands: lhs = Counter(3), rhs = Zero +- expression 14 operands: lhs = Counter(4), rhs = Counter(5) +- expression 15 operands: lhs = Expression(50, Sub), rhs = Counter(5) +- expression 16 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 17 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 18 operands: lhs = Counter(3), rhs = Zero +- expression 19 operands: lhs = Counter(4), rhs = Counter(5) +- expression 20 operands: lhs = Expression(49, Sub), rhs = Counter(7) +- expression 21 operands: lhs = Expression(50, Sub), rhs = Counter(5) +- expression 22 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 23 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 24 operands: lhs = Counter(3), rhs = Zero +- expression 25 operands: lhs = Counter(4), rhs = Counter(5) +- expression 26 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) +- expression 27 operands: lhs = Zero, rhs = Zero +- expression 28 operands: lhs = Expression(49, Sub), rhs = Counter(7) +- expression 29 operands: lhs = Expression(50, Sub), rhs = Counter(5) +- expression 30 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 31 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 32 operands: lhs = Counter(3), rhs = Zero +- expression 33 operands: lhs = Counter(4), rhs = Counter(5) +- expression 34 operands: lhs = Expression(46, Add), rhs = Counter(4) +- expression 35 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) +- expression 36 operands: lhs = Zero, rhs = Zero +- expression 37 operands: lhs = Expression(49, Sub), rhs = Counter(7) +- expression 38 operands: lhs = Expression(50, Sub), rhs = Counter(5) +- expression 39 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 40 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 41 operands: lhs = Counter(3), rhs = Zero +- expression 42 operands: lhs = Counter(4), rhs = Counter(5) +- expression 43 operands: lhs = Counter(9), rhs = Expression(44, Add) +- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(6) +- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(4) +- expression 46 operands: lhs = Expression(47, Sub), rhs = Expression(48, Sub) +- expression 47 operands: lhs = Zero, rhs = Zero +- expression 48 operands: lhs = Expression(49, Sub), rhs = Counter(7) +- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(5) +- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(6) +- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) +- expression 52 operands: lhs = Counter(3), rhs = Zero +- expression 53 operands: lhs = Counter(4), rhs = Counter(5) +Number of file 0 mappings: 20 +- Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16) +- Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21) +- Code(Zero) at (prev + 1, 23) to (start + 0, 27) +- Code(Zero) at (prev + 0, 28) to (start + 0, 30) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15) + = (c1 - c2) +- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30) + = ((Zero - Zero) + (c1 - c2)) +- Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) +- Code(Zero) at (prev + 1, 16) to (start + 1, 10) +- Code(Expression(50, Sub)) at (prev + 3, 13) to (start + 0, 14) + = (((c3 + Zero) + (c4 + c5)) - c6) +- Code(Expression(51, Add)) at (prev + 0, 18) to (start + 0, 23) + = ((c3 + Zero) + (c4 + c5)) +- Code(Expression(10, Add)) at (prev + 1, 16) to (start + 0, 20) + = ((((c3 + Zero) + (c4 + c5)) - c6) + Zero) +- Code(Expression(49, Sub)) at (prev + 1, 20) to (start + 0, 25) + = ((((c3 + Zero) + (c4 + c5)) - c6) - c5) +- Code(Zero) at (prev + 1, 27) to (start + 0, 31) +- Code(Zero) at (prev + 0, 32) to (start + 0, 34) +- Code(Expression(48, Sub)) at (prev + 1, 18) to (start + 0, 19) + = (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7) +- Code(Expression(46, Add)) at (prev + 1, 17) to (start + 0, 34) + = ((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) +- Code(Expression(45, Sub)) at (prev + 0, 34) to (start + 0, 35) + = (((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) +- Code(Zero) at (prev + 1, 20) to (start + 1, 14) +- Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) +- Code(Expression(43, Add)) at (prev + 1, 5) to (start + 0, 6) + = (c9 + ((((Zero - Zero) + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6)) + +Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt +Raw bytes (266): 0x[01, 01, 38, 01, 05, 02, 09, 0e, 12, 00, 00, 02, 09, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 00, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, ba, 01, df, 01, bf, 01, 15, c2, 01, c6, 01, 00, 00, ca, 01, 1d, ce, 01, 11, d3, 01, 19, d7, 01, db, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 12, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ce, 01, 02, 0d, 00, 0e, d3, 01, 00, 12, 00, 17, 33, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ca, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, c6, 01, 01, 12, 00, 13, bf, 01, 01, 11, 00, 22, ba, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, b7, 01, 01, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 56 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(2) +- expression 2 operands: lhs = Expression(3, Sub), rhs = Expression(4, Sub) +- expression 3 operands: lhs = Zero, rhs = Zero +- expression 4 operands: lhs = Expression(0, Sub), rhs = Counter(2) +- expression 5 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 6 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 7 operands: lhs = Counter(1), rhs = Counter(3) +- expression 8 operands: lhs = Counter(4), rhs = Counter(5) +- expression 9 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 10 operands: lhs = Counter(1), rhs = Counter(3) +- expression 11 operands: lhs = Counter(4), rhs = Counter(5) +- expression 12 operands: lhs = Expression(51, Sub), rhs = Zero +- expression 13 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 14 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 15 operands: lhs = Counter(1), rhs = Counter(3) +- expression 16 operands: lhs = Counter(4), rhs = Counter(5) +- expression 17 operands: lhs = Expression(51, Sub), rhs = Counter(4) +- expression 18 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 19 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 20 operands: lhs = Counter(1), rhs = Counter(3) +- expression 21 operands: lhs = Counter(4), rhs = Counter(5) +- expression 22 operands: lhs = Expression(50, Sub), rhs = Counter(7) +- expression 23 operands: lhs = Expression(51, Sub), rhs = Counter(4) +- expression 24 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 25 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 26 operands: lhs = Counter(1), rhs = Counter(3) +- expression 27 operands: lhs = Counter(4), rhs = Counter(5) +- expression 28 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) +- expression 29 operands: lhs = Zero, rhs = Zero +- expression 30 operands: lhs = Expression(50, Sub), rhs = Counter(7) +- expression 31 operands: lhs = Expression(51, Sub), rhs = Counter(4) +- expression 32 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 33 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 34 operands: lhs = Counter(1), rhs = Counter(3) +- expression 35 operands: lhs = Counter(4), rhs = Counter(5) +- expression 36 operands: lhs = Expression(47, Add), rhs = Counter(5) +- expression 37 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) +- expression 38 operands: lhs = Zero, rhs = Zero +- expression 39 operands: lhs = Expression(50, Sub), rhs = Counter(7) +- expression 40 operands: lhs = Expression(51, Sub), rhs = Counter(4) +- expression 41 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 42 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 43 operands: lhs = Counter(1), rhs = Counter(3) +- expression 44 operands: lhs = Counter(4), rhs = Counter(5) +- expression 45 operands: lhs = Expression(46, Sub), rhs = Expression(55, Add) +- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(5) +- expression 47 operands: lhs = Expression(48, Sub), rhs = Expression(49, Sub) +- expression 48 operands: lhs = Zero, rhs = Zero +- expression 49 operands: lhs = Expression(50, Sub), rhs = Counter(7) +- expression 50 operands: lhs = Expression(51, Sub), rhs = Counter(4) +- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(6) +- expression 52 operands: lhs = Expression(53, Add), rhs = Expression(54, Add) +- expression 53 operands: lhs = Counter(1), rhs = Counter(3) +- expression 54 operands: lhs = Counter(4), rhs = Counter(5) +- expression 55 operands: lhs = Counter(6), rhs = Counter(9) +Number of file 0 mappings: 20 +- Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) +- Code(Zero) at (prev + 1, 18) to (start + 1, 10) +- Code(Expression(0, Sub)) at (prev + 2, 16) to (start + 0, 21) + = (c0 - c1) +- Code(Zero) at (prev + 1, 23) to (start + 0, 27) +- Code(Zero) at (prev + 0, 28) to (start + 0, 30) +- Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 15) + = ((c0 - c1) - c2) +- Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30) + = ((Zero - Zero) + ((c0 - c1) - c2)) +- Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) +- Code(Expression(51, Sub)) at (prev + 2, 13) to (start + 0, 14) + = (((c1 + c3) + (c4 + c5)) - c6) +- Code(Expression(52, Add)) at (prev + 0, 18) to (start + 0, 23) + = ((c1 + c3) + (c4 + c5)) +- Code(Expression(12, Add)) at (prev + 1, 16) to (start + 0, 21) + = ((((c1 + c3) + (c4 + c5)) - c6) + Zero) +- Code(Zero) at (prev + 0, 22) to (start + 1, 14) +- Code(Expression(50, Sub)) at (prev + 2, 20) to (start + 0, 25) + = ((((c1 + c3) + (c4 + c5)) - c6) - c4) +- Code(Zero) at (prev + 1, 27) to (start + 0, 31) +- Code(Zero) at (prev + 0, 32) to (start + 0, 34) +- Code(Expression(49, Sub)) at (prev + 1, 18) to (start + 0, 19) + = (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7) +- Code(Expression(47, Add)) at (prev + 1, 17) to (start + 0, 34) + = ((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) +- Code(Expression(46, Sub)) at (prev + 0, 34) to (start + 0, 35) + = (((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) +- Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) +- Code(Expression(45, Add)) at (prev + 1, 5) to (start + 0, 6) + = ((((Zero - Zero) + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9)) + +Function name: loops_branches::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 55, 1) to (start + 5, 2) + diff --git a/tests/coverage-map/status-quo/loops_branches.rs b/tests/coverage-map/status-quo/loops_branches.rs new file mode 100644 index 00000000000..f3a343bcc1f --- /dev/null +++ b/tests/coverage-map/status-quo/loops_branches.rs @@ -0,0 +1,60 @@ +#![allow(unused_assignments, unused_variables, while_true)] + +// This test confirms that (1) unexecuted infinite loops are handled correctly by the +// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. + +struct DebugTest; + +impl std::fmt::Debug for DebugTest { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if true { + if false { + while true {} + } + write!(f, "cool")?; + } else { + } + + for i in 0..10 { + if true { + if false { + while true {} + } + write!(f, "cool")?; + } else { + } + } + Ok(()) + } +} + +struct DisplayTest; + +impl std::fmt::Display for DisplayTest { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if false { + } else { + if false { + while true {} + } + write!(f, "cool")?; + } + for i in 0..10 { + if false { + } else { + if false { + while true {} + } + write!(f, "cool")?; + } + } + Ok(()) + } +} + +fn main() { + let debug_test = DebugTest; + println!("{:?}", debug_test); + let display_test = DisplayTest; + println!("{}", display_test); +} diff --git a/tests/coverage-map/status-quo/match_or_pattern.cov-map b/tests/coverage-map/status-quo/match_or_pattern.cov-map new file mode 100644 index 00000000000..d63407a99c3 --- /dev/null +++ b/tests/coverage-map/status-quo/match_or_pattern.cov-map @@ -0,0 +1,83 @@ +Function name: match_or_pattern::main +Raw bytes (202): 0x[01, 01, 23, 01, 05, 05, 02, 09, 0d, 2f, 11, 09, 0d, 2b, 15, 2f, 11, 09, 0d, 15, 26, 2b, 15, 2f, 11, 09, 0d, 19, 1d, 57, 21, 19, 1d, 53, 25, 57, 21, 19, 1d, 25, 4e, 53, 25, 57, 21, 19, 1d, 29, 2d, 7f, 31, 29, 2d, 7b, 35, 7f, 31, 29, 2d, 35, 76, 7b, 35, 7f, 31, 29, 2d, 39, 3d, 8b, 01, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 07, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 2f, 01, 0e, 00, 10, 2b, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 26, 03, 06, 00, 07, 23, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 57, 01, 0e, 00, 10, 53, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 4e, 03, 06, 00, 07, 4b, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 7f, 01, 0e, 00, 10, 7b, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 76, 03, 06, 00, 07, 73, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 8b, 01, 01, 0e, 00, 10, 87, 01, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 35 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(4) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +- expression 5 operands: lhs = Expression(10, Add), rhs = Counter(5) +- expression 6 operands: lhs = Expression(11, Add), rhs = Counter(4) +- expression 7 operands: lhs = Counter(2), rhs = Counter(3) +- expression 8 operands: lhs = Counter(5), rhs = Expression(9, Sub) +- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5) +- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4) +- expression 11 operands: lhs = Counter(2), rhs = Counter(3) +- expression 12 operands: lhs = Counter(6), rhs = Counter(7) +- expression 13 operands: lhs = Expression(21, Add), rhs = Counter(8) +- expression 14 operands: lhs = Counter(6), rhs = Counter(7) +- expression 15 operands: lhs = Expression(20, Add), rhs = Counter(9) +- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(8) +- expression 17 operands: lhs = Counter(6), rhs = Counter(7) +- expression 18 operands: lhs = Counter(9), rhs = Expression(19, Sub) +- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(9) +- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(8) +- expression 21 operands: lhs = Counter(6), rhs = Counter(7) +- expression 22 operands: lhs = Counter(10), rhs = Counter(11) +- expression 23 operands: lhs = Expression(31, Add), rhs = Counter(12) +- expression 24 operands: lhs = Counter(10), rhs = Counter(11) +- expression 25 operands: lhs = Expression(30, Add), rhs = Counter(13) +- expression 26 operands: lhs = Expression(31, Add), rhs = Counter(12) +- expression 27 operands: lhs = Counter(10), rhs = Counter(11) +- expression 28 operands: lhs = Counter(13), rhs = Expression(29, Sub) +- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(13) +- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(12) +- expression 31 operands: lhs = Counter(10), rhs = Counter(11) +- expression 32 operands: lhs = Counter(14), rhs = Counter(15) +- expression 33 operands: lhs = Expression(34, Add), rhs = Counter(16) +- expression 34 operands: lhs = Counter(14), rhs = Counter(15) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15) +- Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6) +- Code(Expression(0, Sub)) at (prev + 3, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 11) to (start + 0, 17) + = (c1 + (c0 - c1)) +- Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29) +- Code(Expression(11, Add)) at (prev + 1, 14) to (start + 0, 16) + = (c2 + c3) +- Code(Expression(10, Add)) at (prev + 2, 8) to (start + 0, 15) + = ((c2 + c3) + c4) +- Code(Counter(5)) at (prev + 0, 16) to (start + 3, 6) +- Code(Expression(9, Sub)) at (prev + 3, 6) to (start + 0, 7) + = (((c2 + c3) + c4) - c5) +- Code(Expression(8, Add)) at (prev + 1, 11) to (start + 0, 17) + = (c5 + (((c2 + c3) + c4) - c5)) +- Code(Counter(8)) at (prev + 1, 27) to (start + 0, 29) +- Code(Expression(21, Add)) at (prev + 1, 14) to (start + 0, 16) + = (c6 + c7) +- Code(Expression(20, Add)) at (prev + 2, 8) to (start + 0, 15) + = ((c6 + c7) + c8) +- Code(Counter(9)) at (prev + 0, 16) to (start + 3, 6) +- Code(Expression(19, Sub)) at (prev + 3, 6) to (start + 0, 7) + = (((c6 + c7) + c8) - c9) +- Code(Expression(18, Add)) at (prev + 1, 11) to (start + 0, 17) + = (c9 + (((c6 + c7) + c8) - c9)) +- Code(Counter(12)) at (prev + 1, 27) to (start + 0, 29) +- Code(Expression(31, Add)) at (prev + 1, 14) to (start + 0, 16) + = (c10 + c11) +- Code(Expression(30, Add)) at (prev + 2, 8) to (start + 0, 15) + = ((c10 + c11) + c12) +- Code(Counter(13)) at (prev + 0, 16) to (start + 3, 6) +- Code(Expression(29, Sub)) at (prev + 3, 6) to (start + 0, 7) + = (((c10 + c11) + c12) - c13) +- Code(Expression(28, Add)) at (prev + 1, 11) to (start + 0, 17) + = (c13 + (((c10 + c11) + c12) - c13)) +- Code(Counter(16)) at (prev + 1, 27) to (start + 0, 29) +- Code(Expression(34, Add)) at (prev + 1, 14) to (start + 0, 16) + = (c14 + c15) +- Code(Expression(33, Add)) at (prev + 2, 1) to (start + 0, 2) + = ((c14 + c15) + c16) + diff --git a/tests/coverage-map/status-quo/match_or_pattern.rs b/tests/coverage-map/status-quo/match_or_pattern.rs new file mode 100644 index 00000000000..ab7aee51d1b --- /dev/null +++ b/tests/coverage-map/status-quo/match_or_pattern.rs @@ -0,0 +1,43 @@ +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut a: u8 = 0; + let mut b: u8 = 0; + if is_true { + a = 2; + b = 0; + } + match (a, b) { + // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + // This test confirms a fix for Issue #79569. + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 0; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 2; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } +} diff --git a/tests/coverage-map/status-quo/nested_loops.cov-map b/tests/coverage-map/status-quo/nested_loops.cov-map new file mode 100644 index 00000000000..35d92594e75 --- /dev/null +++ b/tests/coverage-map/status-quo/nested_loops.cov-map @@ -0,0 +1,51 @@ +Function name: nested_loops::main +Raw bytes (115): 0x[01, 01, 17, 01, 57, 05, 09, 03, 0d, 4e, 53, 03, 0d, 15, 19, 4b, 09, 4e, 53, 03, 0d, 15, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 42, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 05, 09, 11, 0d, 0d, 01, 01, 01, 02, 1b, 03, 04, 13, 00, 20, 4e, 01, 0d, 01, 18, 4b, 02, 12, 00, 17, 46, 01, 10, 00, 16, 05, 01, 11, 00, 16, 42, 01, 0e, 03, 16, 3e, 04, 11, 01, 1b, 11, 02, 15, 00, 21, 15, 01, 18, 02, 12, 19, 03, 0e, 00, 0f, 57, 02, 09, 00, 17, 5b, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 23 +- expression 0 operands: lhs = Counter(0), rhs = Expression(21, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add) +- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(5), rhs = Counter(6) +- expression 6 operands: lhs = Expression(18, Add), rhs = Counter(2) +- expression 7 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add) +- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 9 operands: lhs = Counter(5), rhs = Counter(6) +- expression 10 operands: lhs = Expression(17, Sub), rhs = Counter(1) +- expression 11 operands: lhs = Expression(18, Add), rhs = Counter(2) +- expression 12 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add) +- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 14 operands: lhs = Counter(5), rhs = Counter(6) +- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(6) +- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(1) +- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(2) +- expression 18 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add) +- expression 19 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 20 operands: lhs = Counter(5), rhs = Counter(6) +- expression 21 operands: lhs = Counter(1), rhs = Counter(2) +- expression 22 operands: lhs = Counter(4), rhs = Counter(3) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 1, 1) to (start + 2, 27) +- Code(Expression(0, Add)) at (prev + 4, 19) to (start + 0, 32) + = (c0 + (c1 + c2)) +- Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 1, 24) + = ((c0 + (c1 + c2)) - c3) +- Code(Expression(18, Add)) at (prev + 2, 18) to (start + 0, 23) + = (((c0 + (c1 + c2)) - c3) + (c5 + c6)) +- Code(Expression(17, Sub)) at (prev + 1, 16) to (start + 0, 22) + = ((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 22) +- Code(Expression(16, Sub)) at (prev + 1, 14) to (start + 3, 22) + = (((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) - c1) +- Code(Expression(15, Sub)) at (prev + 4, 17) to (start + 1, 27) + = ((((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) - c1) - c6) +- Code(Counter(4)) at (prev + 2, 21) to (start + 0, 33) +- Code(Counter(5)) at (prev + 1, 24) to (start + 2, 18) +- Code(Counter(6)) at (prev + 3, 14) to (start + 0, 15) +- Code(Expression(21, Add)) at (prev + 2, 9) to (start + 0, 23) + = (c1 + c2) +- Code(Expression(22, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c4 + c3) + diff --git a/tests/coverage-map/status-quo/nested_loops.rs b/tests/coverage-map/status-quo/nested_loops.rs new file mode 100644 index 00000000000..4c7c7842796 --- /dev/null +++ b/tests/coverage-map/status-quo/nested_loops.rs @@ -0,0 +1,25 @@ +fn main() { + let is_true = std::env::args().len() == 1; + let mut countdown = 10; + + 'outer: while countdown > 0 { + let mut a = 100; + let mut b = 100; + for _ in 0..50 { + if a < 30 { + break; + } + a -= 5; + b -= 5; + if b < 90 { + a -= 10; + if is_true { + break 'outer; + } else { + a -= 2; + } + } + } + countdown -= 1; + } +} diff --git a/tests/coverage-map/status-quo/no_cov_crate.cov-map b/tests/coverage-map/status-quo/no_cov_crate.cov-map new file mode 100644 index 00000000000..7ab5995dc28 --- /dev/null +++ b/tests/coverage-map/status-quo/no_cov_crate.cov-map @@ -0,0 +1,78 @@ +Function name: no_cov_crate::add_coverage_1 +Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 2) + +Function name: no_cov_crate::add_coverage_2 +Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) + +Function name: no_cov_crate::add_coverage_not_called (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) + +Function name: no_cov_crate::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 4d, 01, 0b, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 77, 1) to (start + 11, 2) + +Function name: no_cov_crate::nested_fns::outer +Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 05, 0c, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 49, 5) to (start + 12, 6) + +Function name: no_cov_crate::nested_fns::outer_both_covered +Raw bytes (9): 0x[01, 01, 00, 01, 01, 3f, 05, 0b, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 63, 5) to (start + 11, 6) + +Function name: no_cov_crate::nested_fns::outer_both_covered::inner +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 67, 9) to (start + 1, 23) +- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) +- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10) + = (c1 + (c0 - c1)) + +Function name: no_cov_crate::nested_fns::outer_not_covered::inner +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 38, 9) to (start + 1, 23) +- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) +- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage-map/status-quo/no_cov_crate.rs b/tests/coverage-map/status-quo/no_cov_crate.rs new file mode 100644 index 00000000000..5b748aeefb7 --- /dev/null +++ b/tests/coverage-map/status-quo/no_cov_crate.rs @@ -0,0 +1,88 @@ +// Enables `no_coverage` on the entire crate +#![feature(no_coverage)] + +#[no_coverage] +fn do_not_add_coverage_1() { + println!("called but not covered"); +} + +fn do_not_add_coverage_2() { + #![no_coverage] + println!("called but not covered"); +} + +#[no_coverage] +#[allow(dead_code)] +fn do_not_add_coverage_not_called() { + println!("not called and not covered"); +} + +fn add_coverage_1() { + println!("called and covered"); +} + +fn add_coverage_2() { + println!("called and covered"); +} + +#[allow(dead_code)] +fn add_coverage_not_called() { + println!("not called but covered"); +} + +// FIXME: These test-cases illustrate confusing results of nested functions. +// See https://github.com/rust-lang/rust/issues/93319 +mod nested_fns { + #[no_coverage] + pub fn outer_not_covered(is_true: bool) { + fn inner(is_true: bool) { + if is_true { + println!("called and covered"); + } else { + println!("absolutely not covered"); + } + } + println!("called but not covered"); + inner(is_true); + } + + pub fn outer(is_true: bool) { + println!("called and covered"); + inner_not_covered(is_true); + + #[no_coverage] + fn inner_not_covered(is_true: bool) { + if is_true { + println!("called but not covered"); + } else { + println!("absolutely not covered"); + } + } + } + + pub fn outer_both_covered(is_true: bool) { + println!("called and covered"); + inner(is_true); + + fn inner(is_true: bool) { + if is_true { + println!("called and covered"); + } else { + println!("absolutely not covered"); + } + } + } +} + +fn main() { + let is_true = std::env::args().len() == 1; + + do_not_add_coverage_1(); + do_not_add_coverage_2(); + add_coverage_1(); + add_coverage_2(); + + nested_fns::outer_not_covered(is_true); + nested_fns::outer(is_true); + nested_fns::outer_both_covered(is_true); +} diff --git a/tests/coverage-map/status-quo/overflow.cov-map b/tests/coverage-map/status-quo/overflow.cov-map new file mode 100644 index 00000000000..bfffd9b2ab5 --- /dev/null +++ b/tests/coverage-map/status-quo/overflow.cov-map @@ -0,0 +1,43 @@ +Function name: overflow::main +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0f, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 03, 0a, 12, 03, 13, 00, 20, 09, 00, 21, 03, 0a, 0d, 03, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 8 +- expression 0 operands: lhs = Counter(0), rhs = Expression(6, Add) +- expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(4) +- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(1) +- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(4) +- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 15, 1) to (start + 1, 27) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24) + = (c0 + (c1 + (c2 + c3))) +- Code(Expression(5, Sub)) at (prev + 1, 12) to (start + 0, 26) + = ((c0 + (c1 + (c2 + c3))) - c4) +- Code(Counter(1)) at (prev + 0, 27) to (start + 3, 10) +- Code(Expression(4, Sub)) at (prev + 3, 19) to (start + 0, 32) + = (((c0 + (c1 + (c2 + c3))) - c4) - c1) +- Code(Counter(2)) at (prev + 0, 33) to (start + 3, 10) +- Code(Counter(3)) at (prev + 3, 10) to (start + 0, 11) +- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) + = (c1 + (c2 + c3)) +- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) + +Function name: overflow::might_overflow +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 07, 01, 09, 05, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 18) +- Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 5, 2) + = (c1 + (c0 - c1)) + diff --git a/tests/coverage-map/status-quo/overflow.rs b/tests/coverage-map/status-quo/overflow.rs new file mode 100644 index 00000000000..bbb65c1b35d --- /dev/null +++ b/tests/coverage-map/status-quo/overflow.rs @@ -0,0 +1,63 @@ +#![allow(unused_assignments)] +// failure-status: 101 + +fn might_overflow(to_add: u32) -> u32 { + if to_add > 5 { + println!("this will probably overflow"); + } + let add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + let result = might_overflow(10); + println!("Result: {}", result); + } else if countdown < 5 { + let result = might_overflow(1); + println!("Result: {}", result); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, +// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails a +// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). +// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, +// compiler-generated assertion failures are assumed to be a symptom of a program bug, not +// expected behavior. To simplify the coverage graphs and keep instrumented programs as +// small and fast as possible, `Assert` terminators are assumed to always succeed, and +// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not +// get its own coverage counter. +// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. +// In this test, the final count for the statements after the `if` block in `might_overflow()` +// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending +// on the MIR graph and the structure of the code, this count could have been 3 (which might +// have been valid for the overflowed add `+`, but should have been 4 for the lines before +// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented +// via StatementKind::Counter at the end of the block, but (as in the case in this test), +// a CounterKind::Expression is always evaluated. In this case, the expression was based on +// a `Counter` incremented as part of the evaluation of the `if` expression, which was +// executed, and counted, 4 times, before reaching the overflow add. + +// If the program did not overflow, the coverage for `might_overflow()` would look like this: +// +// 4| |fn might_overflow(to_add: u32) -> u32 { +// 5| 4| if to_add > 5 { +// 6| 0| println!("this will probably overflow"); +// 7| 4| } +// 8| 4| let add_to = u32::MAX - 5; +// 9| 4| println!("does {} + {} overflow?", add_to, to_add); +// 10| 4| let result = to_add + add_to; +// 11| 4| println!("continuing after overflow check"); +// 12| 4| result +// 13| 4|} diff --git a/tests/coverage-map/status-quo/panic_unwind.cov-map b/tests/coverage-map/status-quo/panic_unwind.cov-map new file mode 100644 index 00000000000..f6089ce55ae --- /dev/null +++ b/tests/coverage-map/status-quo/panic_unwind.cov-map @@ -0,0 +1,40 @@ +Function name: panic_unwind::main +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 8 +- expression 0 operands: lhs = Counter(0), rhs = Expression(6, Add) +- expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(4) +- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(1) +- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(4) +- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24) + = (c0 + (c1 + (c2 + c3))) +- Code(Expression(5, Sub)) at (prev + 1, 12) to (start + 0, 26) + = ((c0 + (c1 + (c2 + c3))) - c4) +- Code(Counter(1)) at (prev + 0, 27) to (start + 2, 10) +- Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32) + = (((c0 + (c1 + (c2 + c3))) - c4) - c1) +- Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10) +- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) + = (c1 + (c2 + c3)) +- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) + +Function name: panic_unwind::might_panic +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 19, 02, 02, 0c, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) +- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 25) +- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) + = (c0 - c1) + diff --git a/tests/coverage-map/status-quo/panic_unwind.rs b/tests/coverage-map/status-quo/panic_unwind.rs new file mode 100644 index 00000000000..638d2eb6aaa --- /dev/null +++ b/tests/coverage-map/status-quo/panic_unwind.rs @@ -0,0 +1,31 @@ +#![allow(unused_assignments)] +// failure-status: 101 + +fn might_panic(should_panic: bool) { + if should_panic { + println!("panicking..."); + panic!("panics"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_panic(true); + } else if countdown < 5 { + might_panic(false); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and +// `try_error_result.rs`. +// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the +// normal program exit cleanup, including writing out the current values of the coverage +// counters. diff --git a/tests/coverage-map/status-quo/partial_eq.cov-map b/tests/coverage-map/status-quo/partial_eq.cov-map new file mode 100644 index 00000000000..dd61cd77ab6 --- /dev/null +++ b/tests/coverage-map/status-quo/partial_eq.cov-map @@ -0,0 +1,64 @@ +Function name: <partial_eq::Version as core::clone::Clone>::clone (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 0a, 00, 0f] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 4, 10) to (start + 0, 15) + +Function name: <partial_eq::Version as core::cmp::Ord>::cmp (unused) +Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 33, 00, 34, 00, 00, 35, 00, 36] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 4, 51) to (start + 0, 52) +- Code(Zero) at (prev + 0, 53) to (start + 0, 54) + +Function name: <partial_eq::Version as core::cmp::PartialEq>::eq (unused) +Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 18, 00, 19, 00, 00, 20, 00, 21] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 4, 24) to (start + 0, 25) +- Code(Zero) at (prev + 0, 32) to (start + 0, 33) + +Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp +Raw bytes (22): 0x[01, 01, 04, 07, 0b, 05, 09, 0f, 15, 0d, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) +- expression 3 operands: lhs = Counter(3), rhs = Counter(4) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40) +- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49) + = ((c1 + c2) + ((c3 + c4) + c5)) + +Function name: <partial_eq::Version as core::fmt::Debug>::fmt +Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 4, 17) to (start + 0, 22) + +Function name: <partial_eq::Version>::new +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 12, 5) to (start + 6, 6) + +Function name: partial_eq::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 05, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 21, 1) to (start + 5, 2) + diff --git a/tests/coverage-map/status-quo/partial_eq.rs b/tests/coverage-map/status-quo/partial_eq.rs new file mode 100644 index 00000000000..dd8b42c18ce --- /dev/null +++ b/tests/coverage-map/status-quo/partial_eq.rs @@ -0,0 +1,46 @@ +// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the +// structure of this test. + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + major: usize, + minor: usize, + patch: usize, +} + +impl Version { + pub fn new(major: usize, minor: usize, patch: usize) -> Self { + Self { + major, + minor, + patch, + } + } +} + +fn main() { + let version_3_2_1 = Version::new(3, 2, 1); + let version_3_3_0 = Version::new(3, 3, 0); + + println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); +} + +/* + +This test verifies a bug was fixed that otherwise generated this error: + +thread 'rustc' panicked at 'No counters provided the source_hash for function: + Instance { + def: Item(WithOptConstParam { + did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), + const_param_did: None + }), + args: [] + }' +The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage +without a code region associated with any `Counter`. Code regions were associated with at least +one expression, which is allowed, but the `function_source_hash` was only passed to the codegen +(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the +`function_source_hash` without a code region, if necessary. + +*/ diff --git a/tests/coverage-map/status-quo/simple_loop.cov-map b/tests/coverage-map/status-quo/simple_loop.cov-map new file mode 100644 index 00000000000..eb49c2324cc --- /dev/null +++ b/tests/coverage-map/status-quo/simple_loop.cov-map @@ -0,0 +1,28 @@ +Function name: simple_loop::main +Raw bytes (59): 0x[01, 01, 0a, 01, 05, 27, 09, 05, 02, 23, 09, 27, 09, 05, 02, 1e, 00, 23, 09, 27, 09, 05, 02, 07, 01, 03, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 23, 05, 0d, 02, 0e, 1e, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 1b, 06, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 10 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(9, Add), rhs = Counter(2) +- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 3 operands: lhs = Expression(8, Add), rhs = Counter(2) +- expression 4 operands: lhs = Expression(9, Add), rhs = Counter(2) +- expression 5 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 6 operands: lhs = Expression(7, Sub), rhs = Zero +- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(2) +- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(2) +- expression 9 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 3, 1) to (start + 9, 16) +- Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6) +- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(8, Add)) at (prev + 5, 13) to (start + 2, 14) + = ((c1 + (c0 - c1)) + c2) +- Code(Expression(7, Sub)) at (prev + 4, 13) to (start + 0, 18) + = (((c1 + (c0 - c1)) + c2) - c2) +- Code(Counter(2)) at (prev + 2, 10) to (start + 3, 10) +- Code(Expression(6, Add)) at (prev + 6, 1) to (start + 0, 2) + = ((((c1 + (c0 - c1)) + c2) - c2) + Zero) + diff --git a/tests/coverage-map/status-quo/simple_loop.rs b/tests/coverage-map/status-quo/simple_loop.rs new file mode 100644 index 00000000000..6f7f23475b8 --- /dev/null +++ b/tests/coverage-map/status-quo/simple_loop.rs @@ -0,0 +1,35 @@ +#![allow(unused_assignments)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + + if + is_true + { + countdown + = + 10 + ; + } + + loop + { + if + countdown + == + 0 + { + break + ; + } + countdown + -= + 1 + ; + } +} diff --git a/tests/coverage-map/status-quo/simple_match.cov-map b/tests/coverage-map/status-quo/simple_match.cov-map new file mode 100644 index 00000000000..d5389f04b26 --- /dev/null +++ b/tests/coverage-map/status-quo/simple_match.cov-map @@ -0,0 +1,36 @@ +Function name: simple_match::main +Raw bytes (82): 0x[01, 01, 0e, 01, 05, 2f, 33, 05, 02, 09, 0d, 2b, 11, 2f, 33, 05, 02, 09, 0d, 26, 00, 2b, 11, 2f, 33, 05, 02, 09, 0d, 09, 00, 0a, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 2b, 05, 09, 00, 0d, 26, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 23, 02, 11, 02, 12, 37, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 14 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(11, Add), rhs = Expression(12, Add) +- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 3 operands: lhs = Counter(2), rhs = Counter(3) +- expression 4 operands: lhs = Expression(10, Add), rhs = Counter(4) +- expression 5 operands: lhs = Expression(11, Add), rhs = Expression(12, Add) +- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 7 operands: lhs = Counter(2), rhs = Counter(3) +- expression 8 operands: lhs = Expression(9, Sub), rhs = Zero +- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(4) +- expression 10 operands: lhs = Expression(11, Add), rhs = Expression(12, Add) +- expression 11 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 12 operands: lhs = Counter(2), rhs = Counter(3) +- expression 13 operands: lhs = Counter(2), rhs = Zero +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) +- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(10, Add)) at (prev + 5, 9) to (start + 0, 13) + = ((c1 + (c0 - c1)) + (c2 + c3)) +- Code(Expression(9, Sub)) at (prev + 5, 13) to (start + 0, 22) + = (((c1 + (c0 - c1)) + (c2 + c3)) - c4) +- Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(8, Add)) at (prev + 2, 17) to (start + 2, 18) + = ((((c1 + (c0 - c1)) + (c2 + c3)) - c4) + Zero) +- Code(Expression(13, Add)) at (prev + 4, 13) to (start + 7, 14) + = (c2 + Zero) +- Code(Counter(3)) at (prev + 10, 13) to (start + 0, 15) +- Code(Counter(4)) at (prev + 3, 1) to (start + 0, 2) + diff --git a/tests/coverage-map/status-quo/simple_match.rs b/tests/coverage-map/status-quo/simple_match.rs new file mode 100644 index 00000000000..be99e59a826 --- /dev/null +++ b/tests/coverage-map/status-quo/simple_match.rs @@ -0,0 +1,43 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 1; + if is_true { + countdown = 0; + } + + for + _ + in + 0..2 + { + let z + ; + match + countdown + { + x + if + x + < + 1 + => + { + z = countdown + ; + let y = countdown + ; + countdown = 10 + ; + } + _ + => + {} + } + } +} diff --git a/tests/coverage-map/status-quo/sort_groups.cov-map b/tests/coverage-map/status-quo/sort_groups.cov-map new file mode 100644 index 00000000000..7156a66cf89 --- /dev/null +++ b/tests/coverage-map/status-quo/sort_groups.cov-map @@ -0,0 +1,68 @@ +Function name: sort_groups::generic_fn::<&str> +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) +- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: sort_groups::generic_fn::<()> +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) +- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: sort_groups::generic_fn::<i32> +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) +- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: sort_groups::main +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 06, 01, 04, 0d, 00, 04, 0e, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 6, 1) to (start + 4, 13) +- Code(Zero) at (prev + 4, 14) to (start + 2, 6) +- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 2, 2) + = (c1 + (c0 - c1)) + +Function name: sort_groups::other_fn +Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 17) + diff --git a/tests/coverage-map/status-quo/sort_groups.rs b/tests/coverage-map/status-quo/sort_groups.rs new file mode 100644 index 00000000000..f89f9f3ec61 --- /dev/null +++ b/tests/coverage-map/status-quo/sort_groups.rs @@ -0,0 +1,23 @@ +// compile-flags: --edition=2021 + +// Demonstrate that `sort_subviews.py` can sort instantiation groups into a +// predictable order, while preserving their heterogeneous contents. + +fn main() { + let cond = std::env::args().len() > 1; + generic_fn::<()>(cond); + generic_fn::<&'static str>(!cond); + if false { + generic_fn::<char>(cond); + } + generic_fn::<i32>(cond); + other_fn(); +} + +fn generic_fn<T>(cond: bool) { + if cond { + println!("{}", std::any::type_name::<T>()); + } +} + +fn other_fn() {} diff --git a/tests/coverage-map/status-quo/test_harness.cov-map b/tests/coverage-map/status-quo/test_harness.cov-map new file mode 100644 index 00000000000..b0e955dd142 --- /dev/null +++ b/tests/coverage-map/status-quo/test_harness.cov-map @@ -0,0 +1,24 @@ +Function name: test_harness::my_test +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 00, 10] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16) + +Function name: test_harness::my_test::{closure#0} +Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 01, 00, 08] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 8) + +Function name: test_harness::unused (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 00, 0f] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 15) + diff --git a/tests/coverage-map/status-quo/test_harness.rs b/tests/coverage-map/status-quo/test_harness.rs new file mode 100644 index 00000000000..12a755734c1 --- /dev/null +++ b/tests/coverage-map/status-quo/test_harness.rs @@ -0,0 +1,10 @@ +// Verify that the entry point injected by the test harness doesn't cause +// weird artifacts in the coverage report (e.g. issue #10749). + +// compile-flags: --test + +#[allow(dead_code)] +fn unused() {} + +#[test] +fn my_test() {} diff --git a/tests/coverage-map/status-quo/tight_inf_loop.cov-map b/tests/coverage-map/status-quo/tight_inf_loop.cov-map new file mode 100644 index 00000000000..76884212c14 --- /dev/null +++ b/tests/coverage-map/status-quo/tight_inf_loop.cov-map @@ -0,0 +1,12 @@ +Function name: tight_inf_loop::main +Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 01, 01, 01, 0d, 00, 02, 09, 00, 10, 02, 01, 06, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 1, 1) to (start + 1, 13) +- Code(Zero) at (prev + 2, 9) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 1, 2) + = (c0 - c1) + diff --git a/tests/coverage-map/status-quo/tight_inf_loop.rs b/tests/coverage-map/status-quo/tight_inf_loop.rs new file mode 100644 index 00000000000..cef99027aaa --- /dev/null +++ b/tests/coverage-map/status-quo/tight_inf_loop.rs @@ -0,0 +1,5 @@ +fn main() { + if false { + loop {} + } +} diff --git a/tests/coverage-map/status-quo/try_error_result.cov-map b/tests/coverage-map/status-quo/try_error_result.cov-map new file mode 100644 index 00000000000..b52e78d1195 --- /dev/null +++ b/tests/coverage-map/status-quo/try_error_result.cov-map @@ -0,0 +1,226 @@ +Function name: <try_error_result::Thing1>::get_thing_2 +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 07, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 40, 5) to (start + 1, 24) +- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) +- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6) + = (c1 + (c0 - c1)) + +Function name: <try_error_result::Thing2>::call +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 33, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 07, 02, 05, 00, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 51, 5) to (start + 1, 24) +- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) +- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6) + = (c1 + (c0 - c1)) + +Function name: try_error_result::call +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 07, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) +- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: try_error_result::main +Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 70, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 112, 1) to (start + 2, 12) +- Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) + = (c0 - c1) +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c1 + (c0 - c1)) + +Function name: try_error_result::test1 +Raw bytes (77): 0x[01, 01, 09, 01, 07, 05, 09, 03, 0d, 1d, 11, 16, 1d, 03, 0d, 1f, 0d, 11, 23, 15, 19, 0b, 01, 0c, 01, 02, 17, 03, 07, 09, 00, 0e, 16, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 0e, 01, 0d, 00, 2a, 15, 00, 2a, 00, 2b, 12, 04, 0d, 00, 2a, 19, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 1b, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 9 +- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(7), rhs = Counter(4) +- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(7) +- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(3) +- expression 7 operands: lhs = Counter(4), rhs = Expression(8, Add) +- expression 8 operands: lhs = Counter(5), rhs = Counter(6) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 12, 1) to (start + 2, 23) +- Code(Expression(0, Add)) at (prev + 7, 9) to (start + 0, 14) + = (c0 + (c1 + c2)) +- Code(Expression(5, Sub)) at (prev + 2, 9) to (start + 4, 26) + = ((c0 + (c1 + c2)) - c3) +- Code(Counter(7)) at (prev + 6, 13) to (start + 0, 41) +- Code(Counter(4)) at (prev + 0, 41) to (start + 0, 42) +- Code(Expression(3, Sub)) at (prev + 1, 13) to (start + 0, 42) + = (c7 - c4) +- Code(Counter(5)) at (prev + 0, 42) to (start + 0, 43) +- Code(Expression(4, Sub)) at (prev + 4, 13) to (start + 0, 42) + = (((c0 + (c1 + c2)) - c3) - c7) +- Code(Counter(6)) at (prev + 0, 42) to (start + 0, 43) +- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) +- Code(Expression(6, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((c4 + (c5 + c6)) + c3) + +Function name: try_error_result::test2 +Raw bytes (373): 0x[01, 01, 41, 01, 07, 05, 09, 03, 0d, 41, 11, 52, 15, 41, 11, 4a, 1d, 4e, 19, 52, 15, 41, 11, 4e, 00, 52, 15, 41, 11, 4e, 19, 52, 15, 41, 11, 46, 00, 4a, 1d, 4e, 19, 52, 15, 41, 11, 6a, 25, 49, 21, 49, 21, 66, 00, 6a, 25, 49, 21, 9a, 01, 2d, 9e, 01, 29, a2, 01, 41, 03, 0d, a2, 01, 41, 03, 0d, 9e, 01, 29, a2, 01, 41, 03, 0d, 96, 01, 00, 9a, 01, 2d, 9e, 01, 29, a2, 01, 41, 03, 0d, ba, 01, 35, 45, 31, 45, 31, b6, 01, 00, ba, 01, 35, 45, 31, d2, 01, 3d, 4d, 39, 4d, 39, ce, 01, 00, d2, 01, 3d, 4d, 39, db, 01, 0d, 11, df, 01, e3, 01, f3, 01, 15, e7, 01, eb, 01, ef, 01, 19, 1d, 21, 25, f7, 01, fb, 01, 29, 2d, ff, 01, 83, 02, 31, 35, 39, 3d, 28, 01, 3c, 01, 03, 17, 03, 08, 09, 00, 0e, a2, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 52, 00, 31, 03, 35, 15, 04, 11, 00, 12, 4e, 02, 11, 04, 12, 46, 05, 11, 00, 14, 2b, 00, 17, 00, 41, 19, 00, 41, 00, 42, 4a, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 43, 01, 0d, 00, 20, 66, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 6a, 00, 43, 00, 60, 25, 00, 60, 00, 61, 63, 01, 0d, 00, 20, 96, 01, 04, 11, 00, 14, 9e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 9a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 93, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, ba, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, b3, 01, 01, 0d, 00, 20, ce, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, d2, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, cb, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, d7, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 65 +- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(16), rhs = Counter(4) +- expression 4 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 5 operands: lhs = Counter(16), rhs = Counter(4) +- expression 6 operands: lhs = Expression(18, Sub), rhs = Counter(7) +- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(6) +- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 9 operands: lhs = Counter(16), rhs = Counter(4) +- expression 10 operands: lhs = Expression(19, Sub), rhs = Zero +- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 12 operands: lhs = Counter(16), rhs = Counter(4) +- expression 13 operands: lhs = Expression(19, Sub), rhs = Counter(6) +- expression 14 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 15 operands: lhs = Counter(16), rhs = Counter(4) +- expression 16 operands: lhs = Expression(17, Sub), rhs = Zero +- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(7) +- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(6) +- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 20 operands: lhs = Counter(16), rhs = Counter(4) +- expression 21 operands: lhs = Expression(26, Sub), rhs = Counter(9) +- expression 22 operands: lhs = Counter(18), rhs = Counter(8) +- expression 23 operands: lhs = Counter(18), rhs = Counter(8) +- expression 24 operands: lhs = Expression(25, Sub), rhs = Zero +- expression 25 operands: lhs = Expression(26, Sub), rhs = Counter(9) +- expression 26 operands: lhs = Counter(18), rhs = Counter(8) +- expression 27 operands: lhs = Expression(38, Sub), rhs = Counter(11) +- expression 28 operands: lhs = Expression(39, Sub), rhs = Counter(10) +- expression 29 operands: lhs = Expression(40, Sub), rhs = Counter(16) +- expression 30 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 31 operands: lhs = Expression(40, Sub), rhs = Counter(16) +- expression 32 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 33 operands: lhs = Expression(39, Sub), rhs = Counter(10) +- expression 34 operands: lhs = Expression(40, Sub), rhs = Counter(16) +- expression 35 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 36 operands: lhs = Expression(37, Sub), rhs = Zero +- expression 37 operands: lhs = Expression(38, Sub), rhs = Counter(11) +- expression 38 operands: lhs = Expression(39, Sub), rhs = Counter(10) +- expression 39 operands: lhs = Expression(40, Sub), rhs = Counter(16) +- expression 40 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 41 operands: lhs = Expression(46, Sub), rhs = Counter(13) +- expression 42 operands: lhs = Counter(17), rhs = Counter(12) +- expression 43 operands: lhs = Counter(17), rhs = Counter(12) +- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero +- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(13) +- expression 46 operands: lhs = Counter(17), rhs = Counter(12) +- expression 47 operands: lhs = Expression(52, Sub), rhs = Counter(15) +- expression 48 operands: lhs = Counter(19), rhs = Counter(14) +- expression 49 operands: lhs = Counter(19), rhs = Counter(14) +- expression 50 operands: lhs = Expression(51, Sub), rhs = Zero +- expression 51 operands: lhs = Expression(52, Sub), rhs = Counter(15) +- expression 52 operands: lhs = Counter(19), rhs = Counter(14) +- expression 53 operands: lhs = Expression(54, Add), rhs = Counter(3) +- expression 54 operands: lhs = Counter(4), rhs = Expression(55, Add) +- expression 55 operands: lhs = Expression(56, Add), rhs = Expression(60, Add) +- expression 56 operands: lhs = Counter(5), rhs = Expression(57, Add) +- expression 57 operands: lhs = Expression(58, Add), rhs = Expression(59, Add) +- expression 58 operands: lhs = Counter(6), rhs = Counter(7) +- expression 59 operands: lhs = Counter(8), rhs = Counter(9) +- expression 60 operands: lhs = Expression(61, Add), rhs = Expression(62, Add) +- expression 61 operands: lhs = Counter(10), rhs = Counter(11) +- expression 62 operands: lhs = Expression(63, Add), rhs = Expression(64, Add) +- expression 63 operands: lhs = Counter(12), rhs = Counter(13) +- expression 64 operands: lhs = Counter(14), rhs = Counter(15) +Number of file 0 mappings: 40 +- Code(Counter(0)) at (prev + 60, 1) to (start + 3, 23) +- Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14) + = (c0 + (c1 + c2)) +- Code(Expression(40, Sub)) at (prev + 2, 9) to (start + 4, 26) + = ((c0 + (c1 + c2)) - c3) +- Code(Counter(16)) at (prev + 6, 13) to (start + 0, 47) +- Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(20, Sub)) at (prev + 0, 49) to (start + 3, 53) + = (c16 - c4) +- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18) +- Code(Expression(19, Sub)) at (prev + 2, 17) to (start + 4, 18) + = ((c16 - c4) - c5) +- Code(Expression(17, Sub)) at (prev + 5, 17) to (start + 0, 20) + = ((((c16 - c4) - c5) - c6) - c7) +- Code(Expression(10, Add)) at (prev + 0, 23) to (start + 0, 65) + = (((c16 - c4) - c5) + Zero) +- Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) +- Code(Expression(18, Sub)) at (prev + 0, 67) to (start + 0, 95) + = (((c16 - c4) - c5) - c6) +- Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) +- Code(Expression(16, Add)) at (prev + 1, 13) to (start + 0, 32) + = (((((c16 - c4) - c5) - c6) - c7) + Zero) +- Code(Expression(25, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c18 - c8) - c9) +- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 65) +- Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) +- Code(Expression(26, Sub)) at (prev + 0, 67) to (start + 0, 96) + = (c18 - c8) +- Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) +- Code(Expression(24, Add)) at (prev + 1, 13) to (start + 0, 32) + = (((c18 - c8) - c9) + Zero) +- Code(Expression(37, Sub)) at (prev + 4, 17) to (start + 0, 20) + = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11) +- Code(Expression(39, Sub)) at (prev + 0, 23) to (start + 0, 66) + = (((c0 + (c1 + c2)) - c3) - c16) +- Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) +- Code(Expression(38, Sub)) at (prev + 0, 68) to (start + 0, 97) + = ((((c0 + (c1 + c2)) - c3) - c16) - c10) +- Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) +- Code(Expression(36, Add)) at (prev + 1, 13) to (start + 0, 32) + = ((((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11) + Zero) +- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c17 - c12) - c13) +- Code(Counter(17)) at (prev + 0, 23) to (start + 1, 54) +- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55) +- Code(Expression(46, Sub)) at (prev + 1, 18) to (start + 0, 47) + = (c17 - c12) +- Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(44, Add)) at (prev + 1, 13) to (start + 0, 32) + = (((c17 - c12) - c13) + Zero) +- Code(Expression(51, Sub)) at (prev + 1, 17) to (start + 0, 20) + = ((c19 - c14) - c15) +- Code(Counter(19)) at (prev + 0, 23) to (start + 1, 54) +- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18) +- Code(Expression(52, Sub)) at (prev + 1, 18) to (start + 0, 47) + = (c19 - c14) +- Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(50, Add)) at (prev + 2, 13) to (start + 0, 32) + = (((c19 - c14) - c15) + Zero) +- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) +- Code(Expression(53, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((c4 + ((c5 + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15))))) + c3) + diff --git a/tests/coverage-map/status-quo/try_error_result.rs b/tests/coverage-map/status-quo/try_error_result.rs new file mode 100644 index 00000000000..557cbf22bfa --- /dev/null +++ b/tests/coverage-map/status-quo/try_error_result.rs @@ -0,0 +1,118 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +fn call(return_error: bool) -> Result<(), ()> { + if return_error { + Err(()) + } else { + Ok(()) + } +} + +fn test1() -> Result<(), ()> { + let mut + countdown = 10 + ; + for + _ + in + 0..10 + { + countdown + -= 1 + ; + if + countdown < 5 + { + call(/*return_error=*/ true)?; + call(/*return_error=*/ false)?; + } + else + { + call(/*return_error=*/ false)?; + } + } + Ok(()) +} + +struct Thing1; +impl Thing1 { + fn get_thing_2(&self, return_error: bool) -> Result<Thing2, ()> { + if return_error { + Err(()) + } else { + Ok(Thing2 {}) + } + } +} + +struct Thing2; +impl Thing2 { + fn call(&self, return_error: bool) -> Result<u32, ()> { + if return_error { + Err(()) + } else { + Ok(57) + } + } +} + +fn test2() -> Result<(), ()> { + let thing1 = Thing1{}; + let mut + countdown = 10 + ; + for + _ + in + 0..10 + { + countdown + -= 1 + ; + if + countdown < 5 + { + thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); + thing1 + . + get_thing_2(/*return_error=*/ false) + ? + . + call(/*return_error=*/ true) + . + expect_err( + "call should fail" + ); + let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; + assert_eq!(val, 57); + let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; + assert_eq!(val, 57); + } + else + { + let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; + assert_eq!(val, 57); + let val = thing1 + .get_thing_2(/*return_error=*/ false)? + .call(/*return_error=*/ false)?; + assert_eq!(val, 57); + let val = thing1 + .get_thing_2(/*return_error=*/ false) + ? + .call(/*return_error=*/ false) + ? + ; + assert_eq!(val, 57); + } + } + Ok(()) +} + +fn main() -> Result<(), ()> { + test1().expect_err("test1 should fail"); + test2() + ? + ; + Ok(()) +} diff --git a/tests/coverage-map/status-quo/unused.cov-map b/tests/coverage-map/status-quo/unused.cov-map new file mode 100644 index 00000000000..c8b8f195fbd --- /dev/null +++ b/tests/coverage-map/status-quo/unused.cov-map @@ -0,0 +1,94 @@ +Function name: unused::foo::<f32> +Raw bytes (42): 0x[01, 01, 04, 01, 0f, 05, 09, 03, 0d, 05, 09, 06, 01, 03, 01, 01, 12, 03, 02, 0b, 00, 11, 0a, 01, 09, 00, 0f, 09, 00, 13, 00, 19, 0f, 01, 09, 00, 0f, 0d, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(0), rhs = Expression(3, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 17) + = (c0 + (c1 + c2)) +- Code(Expression(2, Sub)) at (prev + 1, 9) to (start + 0, 15) + = ((c0 + (c1 + c2)) - c3) +- Code(Counter(2)) at (prev + 0, 19) to (start + 0, 25) +- Code(Expression(3, Add)) at (prev + 1, 9) to (start + 0, 15) + = (c1 + c2) +- Code(Counter(3)) at (prev + 2, 1) to (start + 0, 2) + +Function name: unused::foo::<u32> +Raw bytes (42): 0x[01, 01, 04, 01, 0f, 05, 09, 03, 0d, 05, 09, 06, 01, 03, 01, 01, 12, 03, 02, 0b, 00, 11, 0a, 01, 09, 00, 0f, 09, 00, 13, 00, 19, 0f, 01, 09, 00, 0f, 0d, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Counter(0), rhs = Expression(3, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 3 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 17) + = (c0 + (c1 + c2)) +- Code(Expression(2, Sub)) at (prev + 1, 9) to (start + 0, 15) + = ((c0 + (c1 + c2)) - c3) +- Code(Counter(2)) at (prev + 0, 19) to (start + 0, 25) +- Code(Expression(3, Add)) at (prev + 1, 9) to (start + 0, 15) + = (c1 + c2) +- Code(Counter(3)) at (prev + 2, 1) to (start + 0, 2) + +Function name: unused::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 04, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 37, 1) to (start + 4, 2) + +Function name: unused::unused_func (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 01, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 19, 1) to (start + 1, 14) +- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) + +Function name: unused::unused_func2 (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 01, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 25, 1) to (start + 1, 14) +- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) + +Function name: unused::unused_func3 (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 31, 1) to (start + 1, 14) +- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) + +Function name: unused::unused_template_func::<_> (unused) +Raw bytes (34): 0x[01, 01, 00, 06, 01, 0b, 01, 01, 12, 00, 02, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 11, 1) to (start + 1, 18) +- Code(Zero) at (prev + 2, 11) to (start + 0, 17) +- Code(Zero) at (prev + 1, 9) to (start + 0, 15) +- Code(Zero) at (prev + 0, 19) to (start + 0, 25) +- Code(Zero) at (prev + 1, 9) to (start + 0, 15) +- Code(Zero) at (prev + 2, 1) to (start + 0, 2) + diff --git a/tests/coverage-map/status-quo/unused.rs b/tests/coverage-map/status-quo/unused.rs new file mode 100644 index 00000000000..d985af13547 --- /dev/null +++ b/tests/coverage-map/status-quo/unused.rs @@ -0,0 +1,41 @@ +#![allow(dead_code, unused_assignments, unused_must_use, unused_variables)] + +fn foo<T>(x: T) { + let mut i = 0; + while i < 10 { + i != 0 || i != 0; + i += 1; + } +} + +fn unused_template_func<T>(x: T) { + let mut i = 0; + while i < 10 { + i != 0 || i != 0; + i += 1; + } +} + +fn unused_func(mut a: u32) { + if a != 0 { + a += 1; + } +} + +fn unused_func2(mut a: u32) { + if a != 0 { + a += 1; + } +} + +fn unused_func3(mut a: u32) { + if a != 0 { + a += 1; + } +} + +fn main() -> Result<(), u8> { + foo::<u32>(0); + foo::<f32>(0.0); + Ok(()) +} diff --git a/tests/coverage-map/status-quo/while.cov-map b/tests/coverage-map/status-quo/while.cov-map new file mode 100644 index 00000000000..cfd2be96a0d --- /dev/null +++ b/tests/coverage-map/status-quo/while.cov-map @@ -0,0 +1,15 @@ +Function name: while::main +Raw bytes (28): 0x[01, 01, 02, 01, 05, 03, 05, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 01, 06, 06, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16) +- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 20) + = (c0 + c1) +- Code(Zero) at (prev + 0, 21) to (start + 1, 6) +- Code(Expression(1, Sub)) at (prev + 2, 1) to (start + 0, 2) + = ((c0 + c1) - c1) + diff --git a/tests/coverage-map/status-quo/while.rs b/tests/coverage-map/status-quo/while.rs new file mode 100644 index 00000000000..781b90b3566 --- /dev/null +++ b/tests/coverage-map/status-quo/while.rs @@ -0,0 +1,5 @@ +fn main() { + let num = 9; + while num >= 10 { + } +} diff --git a/tests/coverage-map/status-quo/while_early_ret.cov-map b/tests/coverage-map/status-quo/while_early_ret.cov-map new file mode 100644 index 00000000000..369ebe891f1 --- /dev/null +++ b/tests/coverage-map/status-quo/while_early_ret.cov-map @@ -0,0 +1,26 @@ +Function name: while_early_ret::main +Raw bytes (61): 0x[01, 01, 06, 01, 05, 03, 09, 0e, 05, 03, 09, 17, 09, 0d, 11, 09, 01, 04, 01, 01, 1b, 03, 03, 09, 02, 0a, 0e, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 11, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 13, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 6 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 2 operands: lhs = Expression(3, Sub), rhs = Counter(1) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2) +- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(2) +- expression 5 operands: lhs = Counter(3), rhs = Counter(4) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 27) +- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 2, 10) + = (c0 + c1) +- Code(Expression(3, Sub)) at (prev + 5, 13) to (start + 2, 14) + = ((c0 + c1) - c2) +- Code(Expression(2, Sub)) at (prev + 6, 21) to (start + 2, 22) + = (((c0 + c1) - c2) - c1) +- Code(Counter(3)) at (prev + 4, 21) to (start + 0, 27) +- Code(Counter(4)) at (prev + 4, 21) to (start + 0, 27) +- Code(Counter(1)) at (prev + 3, 10) to (start + 3, 10) +- Code(Counter(2)) at (prev + 6, 5) to (start + 0, 11) +- Code(Expression(4, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((c3 + c4) + c2) + diff --git a/tests/coverage-map/status-quo/while_early_ret.rs b/tests/coverage-map/status-quo/while_early_ret.rs new file mode 100644 index 00000000000..b2f0eee2cc0 --- /dev/null +++ b/tests/coverage-map/status-quo/while_early_ret.rs @@ -0,0 +1,42 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while + countdown + > + 0 + { + if + countdown + < + 5 + { + return + if + countdown + > + 8 + { + Ok(()) + } + else + { + Err(1) + } + ; + } + countdown + -= + 1 + ; + } + Ok(()) +} + +// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and +// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux +// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program +// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical +// to the coverage test for early returns, but this is a limitation that should be fixed. diff --git a/tests/coverage-map/status-quo/yield.cov-map b/tests/coverage-map/status-quo/yield.cov-map new file mode 100644 index 00000000000..16caa2db343 --- /dev/null +++ b/tests/coverage-map/status-quo/yield.cov-map @@ -0,0 +1,72 @@ +Function name: yield::main +Raw bytes (118): 0x[01, 01, 11, 01, 00, 05, 09, 0d, 00, 0d, 11, 32, 15, 0d, 11, 11, 15, 2e, 00, 32, 15, 0d, 11, 2e, 00, 32, 15, 0d, 11, 19, 1d, 21, 00, 25, 29, 2d, 00, 10, 01, 07, 01, 01, 16, 03, 06, 0b, 00, 2e, 0d, 01, 27, 00, 29, 07, 01, 0e, 00, 34, 0b, 02, 0b, 00, 2e, 32, 01, 22, 00, 27, 2e, 00, 2c, 00, 2e, 1b, 01, 0e, 00, 34, 1f, 03, 09, 00, 16, 2b, 07, 0b, 00, 2e, 21, 01, 27, 00, 29, 37, 01, 0e, 00, 34, 3b, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 3f, 01, 0e, 00, 34, 43, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 17 +- expression 0 operands: lhs = Counter(0), rhs = Zero +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(3), rhs = Zero +- expression 3 operands: lhs = Counter(3), rhs = Counter(4) +- expression 4 operands: lhs = Expression(12, Sub), rhs = Counter(5) +- expression 5 operands: lhs = Counter(3), rhs = Counter(4) +- expression 6 operands: lhs = Counter(4), rhs = Counter(5) +- expression 7 operands: lhs = Expression(11, Sub), rhs = Zero +- expression 8 operands: lhs = Expression(12, Sub), rhs = Counter(5) +- expression 9 operands: lhs = Counter(3), rhs = Counter(4) +- expression 10 operands: lhs = Expression(11, Sub), rhs = Zero +- expression 11 operands: lhs = Expression(12, Sub), rhs = Counter(5) +- expression 12 operands: lhs = Counter(3), rhs = Counter(4) +- expression 13 operands: lhs = Counter(6), rhs = Counter(7) +- expression 14 operands: lhs = Counter(8), rhs = Zero +- expression 15 operands: lhs = Counter(9), rhs = Counter(10) +- expression 16 operands: lhs = Counter(11), rhs = Zero +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) +- Code(Expression(0, Add)) at (prev + 6, 11) to (start + 0, 46) + = (c0 + Zero) +- Code(Counter(3)) at (prev + 1, 39) to (start + 0, 41) +- Code(Expression(1, Add)) at (prev + 1, 14) to (start + 0, 52) + = (c1 + c2) +- Code(Expression(2, Add)) at (prev + 2, 11) to (start + 0, 46) + = (c3 + Zero) +- Code(Expression(12, Sub)) at (prev + 1, 34) to (start + 0, 39) + = (c3 - c4) +- Code(Expression(11, Sub)) at (prev + 0, 44) to (start + 0, 46) + = ((c3 - c4) - c5) +- Code(Expression(6, Add)) at (prev + 1, 14) to (start + 0, 52) + = (c4 + c5) +- Code(Expression(7, Add)) at (prev + 3, 9) to (start + 0, 22) + = (((c3 - c4) - c5) + Zero) +- Code(Expression(10, Add)) at (prev + 7, 11) to (start + 0, 46) + = (((c3 - c4) - c5) + Zero) +- Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41) +- Code(Expression(13, Add)) at (prev + 1, 14) to (start + 0, 52) + = (c6 + c7) +- Code(Expression(14, Add)) at (prev + 2, 11) to (start + 0, 46) + = (c8 + Zero) +- Code(Counter(11)) at (prev + 1, 39) to (start + 0, 41) +- Code(Expression(15, Add)) at (prev + 1, 14) to (start + 0, 52) + = (c9 + c10) +- Code(Expression(16, Add)) at (prev + 2, 1) to (start + 0, 2) + = (c11 + Zero) + +Function name: yield::main::{closure#0} +Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 1c, 01, 10, 05, 02, 10, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 8, 28) to (start + 1, 16) +- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) + +Function name: yield::main::{closure#1} +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 16) +- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) + diff --git a/tests/coverage-map/status-quo/yield.rs b/tests/coverage-map/status-quo/yield.rs new file mode 100644 index 00000000000..361275c9215 --- /dev/null +++ b/tests/coverage-map/status-quo/yield.rs @@ -0,0 +1,37 @@ +#![feature(generators, generator_trait)] +#![allow(unused_assignments)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +fn main() { + let mut generator = || { + yield 1; + return "foo"; + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } + + let mut generator = || { + yield 1; + yield 2; + yield 3; + return "foo"; + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2) => {} + _ => panic!("unexpected value from resume"), + } +} diff --git a/tests/coverage-map/trivial.cov-map b/tests/coverage-map/trivial.cov-map new file mode 100644 index 00000000000..874e294a1c4 --- /dev/null +++ b/tests/coverage-map/trivial.cov-map @@ -0,0 +1,8 @@ +Function name: trivial::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) + diff --git a/tests/coverage-map/trivial.rs b/tests/coverage-map/trivial.rs new file mode 100644 index 00000000000..d0a9b44fb36 --- /dev/null +++ b/tests/coverage-map/trivial.rs @@ -0,0 +1,3 @@ +// compile-flags: --edition=2021 + +fn main() {} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir index 80ac92d59f3..b06666c9dd7 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -2,7 +2,14 @@ /* generator_layout = GeneratorLayout { field_tys: { _0: GeneratorSavedTy { - ty: impl std::future::Future<Output = ()>, + ty: Alias( + Opaque, + AliasTy { + args: [ + ], + def_id: DefId(0:7 ~ async_await[ccf8]::a::{opaque#0}), + }, + ), source_info: SourceInfo { span: $DIR/async_await.rs:15:9: 15:14 (#8), scope: scope[0], @@ -10,7 +17,14 @@ ignore_for_traits: false, }, _1: GeneratorSavedTy { - ty: impl std::future::Future<Output = ()>, + ty: Alias( + Opaque, + AliasTy { + args: [ + ], + def_id: DefId(0:7 ~ async_await[ccf8]::a::{opaque#0}), + }, + ), source_info: SourceInfo { span: $DIR/async_await.rs:16:9: 16:14 (#10), scope: scope[0], diff --git a/tests/mir-opt/building/custom/debuginfo.numbered.built.after.mir b/tests/mir-opt/building/custom/debuginfo.numbered.built.after.mir new file mode 100644 index 00000000000..d8639253718 --- /dev/null +++ b/tests/mir-opt/building/custom/debuginfo.numbered.built.after.mir @@ -0,0 +1,11 @@ +// MIR for `numbered` after built + +fn numbered(_1: (u32, i32)) -> () { + debug first => (_1.0: u32); + debug second => (_1.0: u32); + let mut _0: (); + + bb0: { + return; + } +} diff --git a/tests/mir-opt/building/custom/debuginfo.pointee.built.after.mir b/tests/mir-opt/building/custom/debuginfo.pointee.built.after.mir new file mode 100644 index 00000000000..86cced6f801 --- /dev/null +++ b/tests/mir-opt/building/custom/debuginfo.pointee.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `pointee` after built + +fn pointee(_1: &mut Option<i32>) -> () { + debug foo => (((*_1) as variant#1).0: i32); + let mut _0: (); + + bb0: { + return; + } +} diff --git a/tests/mir-opt/building/custom/debuginfo.rs b/tests/mir-opt/building/custom/debuginfo.rs new file mode 100644 index 00000000000..bfdc3d3eacd --- /dev/null +++ b/tests/mir-opt/building/custom/debuginfo.rs @@ -0,0 +1,71 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR debuginfo.pointee.built.after.mir +#[custom_mir(dialect = "built")] +fn pointee(opt: &mut Option<i32>) { + mir!( + debug foo => Field::<i32>(Variant(*opt, 1), 0); + { + Return() + } + ) +} + +// EMIT_MIR debuginfo.numbered.built.after.mir +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn numbered(i: (u32, i32)) { + mir!( + debug first => i.0; + debug second => i.0; + { + Return() + } + ) +} + +struct S { x: f32 } + +// EMIT_MIR debuginfo.structured.built.after.mir +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn structured(i: S) { + mir!( + debug x => i.x; + { + Return() + } + ) +} + +// EMIT_MIR debuginfo.variant.built.after.mir +#[custom_mir(dialect = "built")] +fn variant(opt: Option<i32>) { + mir!( + debug inner => Field::<i32>(Variant(opt, 1), 0); + { + Return() + } + ) +} + +// EMIT_MIR debuginfo.variant_deref.built.after.mir +#[custom_mir(dialect = "built")] +fn variant_deref(opt: Option<&i32>) { + mir!( + debug pointer => Field::<&i32>(Variant(opt, 1), 0); + debug deref => *Field::<&i32>(Variant(opt, 1), 0); + { + Return() + } + ) +} + +fn main() { + numbered((5, 6)); + structured(S { x: 5. }); + variant(Some(5)); + variant_deref(Some(&5)); + pointee(&mut Some(5)); +} diff --git a/tests/mir-opt/building/custom/debuginfo.structured.built.after.mir b/tests/mir-opt/building/custom/debuginfo.structured.built.after.mir new file mode 100644 index 00000000000..d122b6bfe29 --- /dev/null +++ b/tests/mir-opt/building/custom/debuginfo.structured.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `structured` after built + +fn structured(_1: S) -> () { + debug x => (_1.0: f32); + let mut _0: (); + + bb0: { + return; + } +} diff --git a/tests/mir-opt/building/custom/debuginfo.variant.built.after.mir b/tests/mir-opt/building/custom/debuginfo.variant.built.after.mir new file mode 100644 index 00000000000..d173723fd89 --- /dev/null +++ b/tests/mir-opt/building/custom/debuginfo.variant.built.after.mir @@ -0,0 +1,10 @@ +// MIR for `variant` after built + +fn variant(_1: Option<i32>) -> () { + debug inner => ((_1 as variant#1).0: i32); + let mut _0: (); + + bb0: { + return; + } +} diff --git a/tests/mir-opt/building/custom/debuginfo.variant_deref.built.after.mir b/tests/mir-opt/building/custom/debuginfo.variant_deref.built.after.mir new file mode 100644 index 00000000000..37d5d1b2dfc --- /dev/null +++ b/tests/mir-opt/building/custom/debuginfo.variant_deref.built.after.mir @@ -0,0 +1,11 @@ +// MIR for `variant_deref` after built + +fn variant_deref(_1: Option<&i32>) -> () { + debug pointer => ((_1 as variant#1).0: &i32); + debug deref => (*((_1 as variant#1).0: &i32)); + let mut _0: (); + + bb0: { + return; + } +} diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index 255ec94816c..ed47baa67da 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -33,14 +33,22 @@ let _15: bool; let _16: u32; scope 6 { - debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, }; +- debug ((f: (bool, bool, u32)).0: bool) => _14; +- debug ((f: (bool, bool, u32)).1: bool) => _15; +- debug ((f: (bool, bool, u32)).2: u32) => _16; ++ debug ((f: (bool, bool, u32)).0: bool) => const true; ++ debug ((f: (bool, bool, u32)).1: bool) => const false; ++ debug ((f: (bool, bool, u32)).2: u32) => const 123_u32; let _10: std::option::Option<u16>; scope 7 { debug o => _10; let _17: u32; let _18: u32; scope 8 { - debug p => Point{ .0 => _17, .1 => _18, }; +- debug ((p: Point).0: u32) => _17; +- debug ((p: Point).1: u32) => _18; ++ debug ((p: Point).0: u32) => const 32_u32; ++ debug ((p: Point).1: u32) => const 32_u32; let _11: u32; scope 9 { - debug a => _11; diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff index 55c774d555d..e443c8991f9 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff index dcab570ea77..592f43f4739 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff index 55c774d555d..e443c8991f9 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff index dcab570ea77..592f43f4739 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff @@ -34,11 +34,11 @@ StorageLive(_5); StorageLive(_6); _6 = const 3_usize; - _7 = const 3_usize; + _7 = Len((*_1)); - _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 3_usize, _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs index 7931c4f02ae..d6b1a93f304 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs @@ -1,8 +1,7 @@ // unit-test: ConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen - // EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff #[allow(unconditional_panic)] fn main() { diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs index 6c03fe9d9c2..d226bd54671 100644 --- a/tests/mir-opt/const_prop/large_array_index.rs +++ b/tests/mir-opt/const_prop/large_array_index.rs @@ -1,6 +1,5 @@ // unit-test: ConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR large_array_index.main.ConstProp.diff diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs index 21dba84af37..fb8b825ee36 100644 --- a/tests/mir-opt/const_prop/repeat.rs +++ b/tests/mir-opt/const_prop/repeat.rs @@ -1,6 +1,5 @@ // unit-test: ConstProp // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR repeat.main.ConstProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 00000000000..212ddc5b154 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 00000000000..5c53d4f4461 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 00000000000..212ddc5b154 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 00000000000..5c53d4f4461 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: [u32; 4]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs new file mode 100644 index 00000000000..ddb3646ca9b --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/array_index.rs @@ -0,0 +1,8 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR array_index.main.DataflowConstProp.diff +fn main() { + let x: u32 = [0, 1, 2, 3][2]; +} diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.rs b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs new file mode 100644 index 00000000000..9e911e85b88 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.rs @@ -0,0 +1,10 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR boolean_identities.test.DataflowConstProp.diff +pub fn test(x: bool, y: bool) -> bool { + (y | true) & (x & false) +} + +fn main() { + test(true, false); +} diff --git a/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff new file mode 100644 index 00000000000..5440c38ce4b --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/boolean_identities.test.DataflowConstProp.diff @@ -0,0 +1,33 @@ +- // MIR for `test` before DataflowConstProp ++ // MIR for `test` after DataflowConstProp + + fn test(_1: bool, _2: bool) -> bool { + debug x => _1; + debug y => _2; + let mut _0: bool; + let mut _3: bool; + let mut _4: bool; + let mut _5: bool; + let mut _6: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = _2; +- _3 = BitOr(move _4, const true); ++ _3 = const true; + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); + _6 = _1; +- _5 = BitAnd(move _6, const false); ++ _5 = const false; + StorageDead(_6); +- _0 = BitAnd(move _3, move _5); ++ _0 = const false; + StorageDead(_5); + StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 00000000000..6c612d46725 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 00000000000..87024da2628 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 00000000000..6c612d46725 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 00000000000..87024da2628 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,39 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: [u8; 5000]; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = [const 0_u8; 5000]; + StorageLive(_3); + _3 = const 2_usize; +- _4 = Len(_2); +- _5 = Lt(_3, _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = _2[_3]; ++ _1 = _2[2 of 3]; + StorageDead(_3); + StorageDead(_2); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs new file mode 100644 index 00000000000..af13c7d1020 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs @@ -0,0 +1,9 @@ +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR large_array_index.main.DataflowConstProp.diff +fn main() { + // check that we don't propagate this, because it's too large + let x: u8 = [0_u8; 5000][2]; +} diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs new file mode 100644 index 00000000000..dbea1480445 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs @@ -0,0 +1,10 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR mult_by_zero.test.DataflowConstProp.diff +fn test(x : i32) -> i32 { + x * 0 +} + +fn main() { + test(10); +} diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff new file mode 100644 index 00000000000..91bc10a562f --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.test.DataflowConstProp.diff @@ -0,0 +1,18 @@ +- // MIR for `test` before DataflowConstProp ++ // MIR for `test` after DataflowConstProp + + fn test(_1: i32) -> i32 { + debug x => _1; + let mut _0: i32; + let mut _2: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = Mul(move _2, const 0_i32); ++ _0 = const 0_i32; + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff new file mode 100644 index 00000000000..c61414b6541 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff @@ -0,0 +1,76 @@ +- // MIR for `concrete` before DataflowConstProp ++ // MIR for `concrete` after DataflowConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); +- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable]; ++ _2 = const 4_usize; ++ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); +- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable]; ++ _4 = const 0_usize; ++ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); +- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable]; ++ _6 = const 2_usize; ++ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); +- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable]; ++ _8 = const 3_usize; ++ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff new file mode 100644 index 00000000000..0c3939a3456 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff @@ -0,0 +1,76 @@ +- // MIR for `concrete` before DataflowConstProp ++ // MIR for `concrete` after DataflowConstProp + + fn concrete() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug x => _1; + let _3: usize; + scope 2 { + debug y => _3; + let _5: usize; + scope 3 { + debug z0 => _5; + let _7: usize; + scope 4 { + debug z1 => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = OffsetOf(Alpha, [0]); +- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue]; ++ _2 = const 4_usize; ++ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = OffsetOf(Alpha, [1]); +- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue]; ++ _4 = const 0_usize; ++ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Alpha, [2, 0]); +- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue]; ++ _6 = const 2_usize; ++ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Alpha, [2, 1]); +- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue]; ++ _8 = const 3_usize; ++ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff new file mode 100644 index 00000000000..d54d4687060 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff @@ -0,0 +1,72 @@ +- // MIR for `generic` before DataflowConstProp ++ // MIR for `generic` after DataflowConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma<T>, [0]); + _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma<T>, [1]); + _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Delta<T>, [1]); +- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable]; ++ _6 = const 0_usize; ++ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Delta<T>, [2]); +- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable]; ++ _8 = const 2_usize; ++ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff new file mode 100644 index 00000000000..6032a2274ef --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff @@ -0,0 +1,72 @@ +- // MIR for `generic` before DataflowConstProp ++ // MIR for `generic` after DataflowConstProp + + fn generic() -> () { + let mut _0: (); + let _1: usize; + let mut _2: usize; + let mut _4: usize; + let mut _6: usize; + let mut _8: usize; + scope 1 { + debug gx => _1; + let _3: usize; + scope 2 { + debug gy => _3; + let _5: usize; + scope 3 { + debug dx => _5; + let _7: usize; + scope 4 { + debug dy => _7; + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = OffsetOf(Gamma<T>, [0]); + _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); + StorageLive(_4); + _4 = OffsetOf(Gamma<T>, [1]); + _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_4); + StorageLive(_5); + StorageLive(_6); +- _6 = OffsetOf(Delta<T>, [1]); +- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue]; ++ _6 = const 0_usize; ++ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = OffsetOf(Delta<T>, [2]); +- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue]; ++ _8 = const 2_usize; ++ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_8); + _0 = const (); + StorageDead(_7); + StorageDead(_5); + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs new file mode 100644 index 00000000000..ccc90790e52 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs @@ -0,0 +1,49 @@ +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(offset_of)] + +use std::marker::PhantomData; +use std::mem::offset_of; + +struct Alpha { + x: u8, + y: u16, + z: Beta, +} + +struct Beta(u8, u8); + +struct Gamma<T> { + x: u8, + y: u16, + _t: T, +} + +#[repr(C)] +struct Delta<T> { + _phantom: PhantomData<T>, + x: u8, + y: u16, +} + +// EMIT_MIR offset_of.concrete.DataflowConstProp.diff +fn concrete() { + let x = offset_of!(Alpha, x); + let y = offset_of!(Alpha, y); + let z0 = offset_of!(Alpha, z.0); + let z1 = offset_of!(Alpha, z.1); +} + +// EMIT_MIR offset_of.generic.DataflowConstProp.diff +fn generic<T>() { + let gx = offset_of!(Gamma<T>, x); + let gy = offset_of!(Gamma<T>, y); + let dx = offset_of!(Delta<T>, x); + let dy = offset_of!(Delta<T>, y); +} + +fn main() { + concrete(); + generic::<()>(); +} diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 00000000000..a18ef6c9db7 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,43 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 00000000000..3356ef98b14 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,43 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 00000000000..a18ef6c9db7 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,43 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 00000000000..3356ef98b14 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,43 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: u32; + let mut _3: [u32; 8]; + let _4: usize; + let mut _5: usize; + let mut _6: bool; + scope 1 { + debug x => _1; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + _3 = [const 42_u32; 8]; + StorageLive(_4); + _4 = const 2_usize; +- _5 = Len(_3); +- _6 = Lt(_4, _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _2 = _3[_4]; ++ _2 = _3[2 of 3]; + _1 = Add(move _2, const 0_u32); + StorageDead(_2); + StorageDead(_4); + StorageDead(_3); + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs new file mode 100644 index 00000000000..9fa353e44c5 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/repeat.rs @@ -0,0 +1,8 @@ +// unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR repeat.main.DataflowConstProp.diff +fn main() { + let x: u32 = [42; 8][2] + 0; +} diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 00000000000..be55d259dcf --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,76 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const _; + _4 = _14; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 00000000000..f9a6c509ac8 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,76 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const _; + _4 = _14; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 00000000000..be55d259dcf --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,76 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const _; + _4 = _14; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind unreachable]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 00000000000..f9a6c509ac8 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,76 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const _; + _4 = _14; + _3 = _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(_6, _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = (*_2)[_6]; ++ _1 = (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const _; + StorageLive(_11); + _11 = const 1_usize; + _12 = Len((*_10)); +- _13 = Lt(_11, _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb2, unwind continue]; ++ _13 = Lt(const 1_usize, _12); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = (*_10)[_11]; ++ _9 = (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs new file mode 100644 index 00000000000..41367e48497 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -0,0 +1,12 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// unit-test: DataflowConstProp +// compile-flags: -Zmir-enable-passes=+InstSimplify +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR slice_len.main.DataflowConstProp.diff +fn main() { + let local = (&[1u32, 2, 3] as &[u32])[1]; + + const SLICE: &[u32] = &[1, 2, 3]; + let constant = SLICE[1]; +} diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..52f096ac0e4 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before DataflowConstProp ++ // MIR for `from_char` after DataflowConstProp + + fn from_char() -> i32 { + let mut _0: i32; + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); ++ _0 = const 82_i32; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..52f096ac0e4 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before DataflowConstProp ++ // MIR for `from_char` after DataflowConstProp + + fn from_char() -> i32 { + let mut _0: i32; + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); ++ _0 = const 82_i32; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..3972eb209a1 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_bool` before DataflowConstProp ++ // MIR for `invalid_bool` after DataflowConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; + scope 1 { + } + + bb0: { +- _0 = const -1_i8 as bool (Transmute); ++ _0 = const {transmute(0xff): bool}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..3972eb209a1 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_bool` before DataflowConstProp ++ // MIR for `invalid_bool` after DataflowConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; + scope 1 { + } + + bb0: { +- _0 = const -1_i8 as bool (Transmute); ++ _0 = const {transmute(0xff): bool}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..837dabde42a --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_char` before DataflowConstProp ++ // MIR for `invalid_char` after DataflowConstProp + + fn invalid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const _ as char (Transmute); ++ _0 = const {transmute(0x7fffffff): char}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..837dabde42a --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `invalid_char` before DataflowConstProp ++ // MIR for `invalid_char` after DataflowConstProp + + fn invalid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const _ as char (Transmute); ++ _0 = const {transmute(0x7fffffff): char}; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..6091e169e8e --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff @@ -0,0 +1,18 @@ +- // MIR for `less_as_i8` before DataflowConstProp ++ // MIR for `less_as_i8` after DataflowConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; + let mut _1: std::cmp::Ordering; + scope 1 { + } + + bb0: { + StorageLive(_1); + _1 = Less; + _0 = move _1 as i8 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..6091e169e8e --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff @@ -0,0 +1,18 @@ +- // MIR for `less_as_i8` before DataflowConstProp ++ // MIR for `less_as_i8` after DataflowConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; + let mut _1: std::cmp::Ordering; + scope 1 { + } + + bb0: { + StorageLive(_1); + _1 = Less; + _0 = move _1 as i8 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs new file mode 100644 index 00000000000..c25e33ab0b6 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.rs @@ -0,0 +1,63 @@ +// unit-test: DataflowConstProp +// compile-flags: -O --crate-type=lib +// ignore-endian-big +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +use std::mem::transmute; + +// EMIT_MIR transmute.less_as_i8.DataflowConstProp.diff +pub fn less_as_i8() -> i8 { + unsafe { transmute(std::cmp::Ordering::Less) } +} + +// EMIT_MIR transmute.from_char.DataflowConstProp.diff +pub fn from_char() -> i32 { + unsafe { transmute('R') } +} + +// EMIT_MIR transmute.valid_char.DataflowConstProp.diff +pub fn valid_char() -> char { + unsafe { transmute(0x52_u32) } +} + +// EMIT_MIR transmute.invalid_char.DataflowConstProp.diff +pub unsafe fn invalid_char() -> char { + unsafe { transmute(i32::MAX) } +} + +// EMIT_MIR transmute.invalid_bool.DataflowConstProp.diff +pub unsafe fn invalid_bool() -> bool { + unsafe { transmute(-1_i8) } +} + +// EMIT_MIR transmute.undef_union_as_integer.DataflowConstProp.diff +pub unsafe fn undef_union_as_integer() -> u32 { + union Union32 { value: u32, unit: () } + unsafe { transmute(Union32 { unit: () }) } +} + +// EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff +pub unsafe fn unreachable_direct() -> ! { + let x: Never = unsafe { transmute(()) }; + match x {} +} + +// EMIT_MIR transmute.unreachable_ref.DataflowConstProp.diff +pub unsafe fn unreachable_ref() -> ! { + let x: &Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_mut.DataflowConstProp.diff +pub unsafe fn unreachable_mut() -> ! { + let x: &mut Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_box.DataflowConstProp.diff +pub unsafe fn unreachable_box() -> ! { + let x: Box<Never> = unsafe { transmute(1_usize) }; + match *x {} +} + +enum Never {} diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..fc0634b1f8f --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before DataflowConstProp ++ // MIR for `undef_union_as_integer` after DataflowConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; + let mut _1: undef_union_as_integer::Union32; + let mut _2: (); + scope 1 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = Union32 { value: move _2 }; + StorageDead(_2); + _0 = move _1 as u32 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..fc0634b1f8f --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before DataflowConstProp ++ // MIR for `undef_union_as_integer` after DataflowConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; + let mut _1: undef_union_as_integer::Union32; + let mut _2: (); + scope 1 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = Union32 { value: move _2 }; + StorageDead(_2); + _0 = move _1 as u32 (Transmute); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..d0c298ba233 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_box` before DataflowConstProp ++ // MIR for `unreachable_box` after DataflowConstProp + + fn unreachable_box() -> ! { + let mut _0: !; + let _1: std::boxed::Box<Never>; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as std::boxed::Box<Never> (Transmute); ++ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..d0c298ba233 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_box` before DataflowConstProp ++ // MIR for `unreachable_box` after DataflowConstProp + + fn unreachable_box() -> ! { + let mut _0: !; + let _1: std::boxed::Box<Never>; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as std::boxed::Box<Never> (Transmute); ++ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..acbb5cd1bc7 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff @@ -0,0 +1,22 @@ +- // MIR for `unreachable_direct` before DataflowConstProp ++ // MIR for `unreachable_direct` after DataflowConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; + let _1: Never; + let mut _2: (); + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = move _2 as Never (Transmute); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..acbb5cd1bc7 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff @@ -0,0 +1,22 @@ +- // MIR for `unreachable_direct` before DataflowConstProp ++ // MIR for `unreachable_direct` after DataflowConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; + let _1: Never; + let mut _2: (); + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (); + _1 = move _2 as Never (Transmute); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..2ffaeea72db --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff @@ -0,0 +1,24 @@ +- // MIR for `unreachable_mut` before DataflowConstProp ++ // MIR for `unreachable_mut` after DataflowConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; + let _1: &mut Never; + let mut _2: &mut Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = const 1_usize as &mut Never (Transmute); ++ _2 = const {0x1 as &mut Never}; + _1 = &mut (*_2); + StorageDead(_2); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..2ffaeea72db --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff @@ -0,0 +1,24 @@ +- // MIR for `unreachable_mut` before DataflowConstProp ++ // MIR for `unreachable_mut` after DataflowConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; + let _1: &mut Never; + let mut _2: &mut Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); + StorageLive(_2); +- _2 = const 1_usize as &mut Never (Transmute); ++ _2 = const {0x1 as &mut Never}; + _1 = &mut (*_2); + StorageDead(_2); + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..31fcaafc5bc --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_ref` before DataflowConstProp ++ // MIR for `unreachable_ref` after DataflowConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; + let _1: &Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as &Never (Transmute); ++ _1 = const {0x1 as &Never}; + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..31fcaafc5bc --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff @@ -0,0 +1,20 @@ +- // MIR for `unreachable_ref` before DataflowConstProp ++ // MIR for `unreachable_ref` after DataflowConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; + let _1: &Never; + scope 1 { + debug x => _1; + } + scope 2 { + } + + bb0: { + StorageLive(_1); +- _1 = const 1_usize as &Never (Transmute); ++ _1 = const {0x1 as &Never}; + unreachable; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff new file mode 100644 index 00000000000..402ef754a64 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before DataflowConstProp ++ // MIR for `valid_char` after DataflowConstProp + + fn valid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); ++ _0 = const 'R'; + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..402ef754a64 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before DataflowConstProp ++ // MIR for `valid_char` after DataflowConstProp + + fn valid_char() -> char { + let mut _0: char; + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); ++ _0 = const 'R'; + return; + } + } + diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs index 6b4f4c80560..79fd9457ce1 100644 --- a/tests/mir-opt/funky_arms.rs +++ b/tests/mir-opt/funky_arms.rs @@ -9,7 +9,7 @@ use core::num::flt2dec; use std::fmt::{Formatter, Result}; // EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff -fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result +pub fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result where T: flt2dec::DecodableFloat, { diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir index 958078b9706..acbb7904985 100644 --- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir +++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir @@ -2,7 +2,11 @@ /* generator_layout = GeneratorLayout { field_tys: { _0: GeneratorSavedTy { - ty: std::string::String, + ty: Adt( + std::string::String, + [ + ], + ), source_info: SourceInfo { span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0), scope: scope[0], diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir index 7e050e585b1..c17d4421542 100644 --- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir +++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir @@ -2,7 +2,11 @@ /* generator_layout = GeneratorLayout { field_tys: { _0: GeneratorSavedTy { - ty: std::string::String, + ty: Adt( + std::string::String, + [ + ], + ), source_info: SourceInfo { span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0), scope: scope[0], diff --git a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 13d703b908c..e33f5f59de1 100644 --- a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -2,7 +2,11 @@ /* generator_layout = GeneratorLayout { field_tys: { _0: GeneratorSavedTy { - ty: HasDrop, + ty: Adt( + HasDrop, + [ + ], + ), source_info: SourceInfo { span: $DIR/generator_tiny.rs:20:13: 20:15 (#0), scope: scope[0], diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index f61632728ba..9d8f272abea 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -33,12 +33,10 @@ _3 = &_4; _2 = move _3 as &[T] (PointerCoercion(Unsize)); StorageDead(_3); - _8 = Len((*_2)); + _8 = const 3_usize; _9 = const 3_usize; -- _10 = Eq(move _8, const 3_usize); -- switchInt(move _10) -> [0: bb1, otherwise: bb2]; -+ nop; -+ switchInt(move _8) -> [3: bb2, otherwise: bb1]; + _10 = const true; + goto -> bb2; } bb1: { diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index f6c337be10f..738b0b1b3e5 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -33,12 +33,10 @@ _3 = &_4; _2 = move _3 as &[T] (PointerCoercion(Unsize)); StorageDead(_3); - _8 = Len((*_2)); + _8 = const 3_usize; _9 = const 3_usize; -- _10 = Eq(move _8, const 3_usize); -- switchInt(move _10) -> [0: bb1, otherwise: bb2]; -+ nop; -+ switchInt(move _8) -> [3: bb2, otherwise: bb1]; + _10 = const true; + goto -> bb2; } bb1: { diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index f12179a8905..b6a673b6355 100644 --- a/tests/mir-opt/issue_99325.main.built.after.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &'static [u8; 4], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir new file mode 100644 index 00000000000..9d112cfa20a --- /dev/null +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -0,0 +1,276 @@ +// MIR for `main` after built + +| User Type Annotations +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| +fn main() -> () { + let mut _0: (); + let _1: (); + let mut _2: (&&[u8], &&[u8; 4]); + let mut _3: &&[u8]; + let _4: &[u8]; + let mut _5: &&[u8; 4]; + let _6: &[u8; 4]; + let _7: [u8; 4]; + let _8: &&[u8]; + let _9: &&[u8; 4]; + let mut _10: bool; + let mut _11: &&[u8]; + let mut _12: &&[u8; 4]; + let mut _13: !; + let _15: !; + let mut _16: core::panicking::AssertKind; + let mut _17: &&[u8]; + let _18: &&[u8]; + let mut _19: &&[u8; 4]; + let _20: &&[u8; 4]; + let mut _21: std::option::Option<std::fmt::Arguments<'_>>; + let _22: (); + let mut _23: (&&[u8], &&[u8; 4]); + let mut _24: &&[u8]; + let _25: &[u8]; + let mut _26: &&[u8; 4]; + let _27: &[u8; 4]; + let _28: &&[u8]; + let _29: &&[u8; 4]; + let mut _30: bool; + let mut _31: &&[u8]; + let mut _32: &&[u8; 4]; + let mut _33: !; + let _35: !; + let mut _36: core::panicking::AssertKind; + let mut _37: &&[u8]; + let _38: &&[u8]; + let mut _39: &&[u8; 4]; + let _40: &&[u8; 4]; + let mut _41: std::option::Option<std::fmt::Arguments<'_>>; + scope 1 { + debug left_val => _8; + debug right_val => _9; + let _14: core::panicking::AssertKind; + scope 2 { + debug kind => _14; + } + } + scope 3 { + debug left_val => _28; + debug right_val => _29; + let _34: core::panicking::AssertKind; + scope 4 { + debug kind => _34; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb21]; + } + + bb1: { + _3 = &_4; + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8]; + _6 = &_7; + _5 = &_6; + _2 = (move _3, move _5); + StorageDead(_5); + StorageDead(_3); + FakeRead(ForMatchedPlace(None), _2); + StorageLive(_8); + _8 = (_2.0: &&[u8]); + StorageLive(_9); + _9 = (_2.1: &&[u8; 4]); + StorageLive(_10); + StorageLive(_11); + _11 = &(*_8); + StorageLive(_12); + _12 = &(*_9); + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb2, unwind: bb21]; + } + + bb2: { + switchInt(move _10) -> [0: bb4, otherwise: bb3]; + } + + bb3: { + StorageDead(_12); + StorageDead(_11); + goto -> bb8; + } + + bb4: { + goto -> bb5; + } + + bb5: { + StorageDead(_12); + StorageDead(_11); + StorageLive(_14); + _14 = core::panicking::AssertKind::Eq; + FakeRead(ForLet(None), _14); + StorageLive(_15); + StorageLive(_16); + _16 = move _14; + StorageLive(_17); + StorageLive(_18); + _18 = &(*_8); + _17 = &(*_18); + StorageLive(_19); + StorageLive(_20); + _20 = &(*_9); + _19 = &(*_20); + StorageLive(_21); + _21 = Option::<Arguments<'_>>::None; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb21; + } + + bb6: { + StorageDead(_21); + StorageDead(_19); + StorageDead(_17); + StorageDead(_16); + StorageDead(_20); + StorageDead(_18); + StorageDead(_15); + StorageDead(_14); + unreachable; + } + + bb7: { + goto -> bb9; + } + + bb8: { + _1 = const (); + goto -> bb9; + } + + bb9: { + StorageDead(_10); + StorageDead(_9); + StorageDead(_8); + goto -> bb10; + } + + bb10: { + StorageDead(_7); + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb11, unwind: bb21]; + } + + bb11: { + _24 = &_25; + StorageLive(_26); + StorageLive(_27); + _27 = const b"AAAA"; + _26 = &_27; + _23 = (move _24, move _26); + StorageDead(_26); + StorageDead(_24); + FakeRead(ForMatchedPlace(None), _23); + StorageLive(_28); + _28 = (_23.0: &&[u8]); + StorageLive(_29); + _29 = (_23.1: &&[u8; 4]); + StorageLive(_30); + StorageLive(_31); + _31 = &(*_28); + StorageLive(_32); + _32 = &(*_29); + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb12, unwind: bb21]; + } + + bb12: { + switchInt(move _30) -> [0: bb14, otherwise: bb13]; + } + + bb13: { + StorageDead(_32); + StorageDead(_31); + goto -> bb18; + } + + bb14: { + goto -> bb15; + } + + bb15: { + StorageDead(_32); + StorageDead(_31); + StorageLive(_34); + _34 = core::panicking::AssertKind::Eq; + FakeRead(ForLet(None), _34); + StorageLive(_35); + StorageLive(_36); + _36 = move _34; + StorageLive(_37); + StorageLive(_38); + _38 = &(*_28); + _37 = &(*_38); + StorageLive(_39); + StorageLive(_40); + _40 = &(*_29); + _39 = &(*_40); + StorageLive(_41); + _41 = Option::<Arguments<'_>>::None; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb21; + } + + bb16: { + StorageDead(_41); + StorageDead(_39); + StorageDead(_37); + StorageDead(_36); + StorageDead(_40); + StorageDead(_38); + StorageDead(_35); + StorageDead(_34); + unreachable; + } + + bb17: { + goto -> bb19; + } + + bb18: { + _22 = const (); + goto -> bb19; + } + + bb19: { + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); + goto -> bb20; + } + + bb20: { + StorageDead(_27); + StorageDead(_25); + StorageDead(_23); + StorageDead(_22); + _0 = const (); + return; + } + + bb21 (cleanup): { + resume; + } +} + +alloc4 (size: 4, align: 1) { + 41 41 41 41 │ AAAA +} diff --git a/tests/mir-opt/issue_99325.rs b/tests/mir-opt/issue_99325.rs index fe819cddb2c..3603228a502 100644 --- a/tests/mir-opt/issue_99325.rs +++ b/tests/mir-opt/issue_99325.rs @@ -1,3 +1,5 @@ +// EMIT_MIR_FOR_EACH_BIT_WIDTH + #![feature(adt_const_params)] #![allow(incomplete_features)] diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff index 95a4a83d663..b2cf3cc1cca 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-abort.diff @@ -12,6 +12,7 @@ StorageLive(_2); _2 = &raw const (*_1); - _0 = read_via_copy::<Never>(move _2) -> unwind unreachable; ++ _0 = (*_2); + unreachable; } } diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff index 95a4a83d663..b2cf3cc1cca 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.panic-unwind.diff @@ -12,6 +12,7 @@ StorageLive(_2); _2 = &raw const (*_1); - _0 = read_via_copy::<Never>(move _2) -> unwind unreachable; ++ _0 = (*_2); + unreachable; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 8dd2cd7900f..2fd669aeeb6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> let mut _4: usize; scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { debug self => _1; - debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; + debug ((index: std::ops::Range<usize>).0: usize) => _3; + debug ((index: std::ops::Range<usize>).1: usize) => _4; let mut _5: *mut [u32]; let mut _13: *mut [u32]; scope 2 { scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { - debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; + debug ((self: std::ops::Range<usize>).0: usize) => _3; + debug ((self: std::ops::Range<usize>).1: usize) => _4; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; let _15: usize; let _16: usize; scope 4 { - debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range<usize>).0: usize) => _15; + debug ((this: std::ops::Range<usize>).1: usize) => _16; scope 5 { let _6: usize; scope 6 { @@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> } } scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { - debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range<usize>).0: usize) => _15; + debug ((this: std::ops::Range<usize>).1: usize) => _16; debug slice => _5; scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { debug self => _5; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 8dd2cd7900f..2fd669aeeb6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> let mut _4: usize; scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { debug self => _1; - debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; + debug ((index: std::ops::Range<usize>).0: usize) => _3; + debug ((index: std::ops::Range<usize>).1: usize) => _4; let mut _5: *mut [u32]; let mut _13: *mut [u32]; scope 2 { scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { - debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, }; + debug ((self: std::ops::Range<usize>).0: usize) => _3; + debug ((self: std::ops::Range<usize>).1: usize) => _4; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; let _15: usize; let _16: usize; scope 4 { - debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range<usize>).0: usize) => _15; + debug ((this: std::ops::Range<usize>).1: usize) => _16; scope 5 { let _6: usize; scope 6 { @@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> } } scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { - debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range<usize>).0: usize) => _15; + debug ((this: std::ops::Range<usize>).1: usize) => _16; debug slice => _5; scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { debug self => _5; diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index bb14b909a95..b020d1baafa 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -33,7 +33,8 @@ + let _32: u32; scope 1 { - debug foo => _1; -+ debug foo => Foo<T>{ .0 => _31, .1 => _32, }; ++ debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _31; ++ debug ((foo: Foo<T>).1: u32) => _32; let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>; scope 2 { debug x => _5; diff --git a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff index 7ee0431692c..1330f9b3ac8 100644 --- a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff @@ -8,7 +8,8 @@ + let _5: u8; scope 1 { - debug y => _1; -+ debug y => (usize, u8){ .0 => _4, .1 => _5, }; ++ debug ((y: (usize, u8)).0: usize) => _4; ++ debug ((y: (usize, u8)).1: u8) => _5; let _2: usize; scope 2 { debug t => _2; diff --git a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff index 0a1de891aee..3621338635e 100644 --- a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff @@ -11,7 +11,10 @@ + let _14: std::option::Option<isize>; scope 1 { - debug y => _2; -+ debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; ++ debug ((y: Foo).0: u8) => _11; ++ debug ((y: Foo).1: ()) => _12; ++ debug ((y: Foo).2: &str) => _13; ++ debug ((y: Foo).3: std::option::Option<isize>) => _14; let _3: u8; scope 2 { debug t => _3; @@ -25,7 +28,10 @@ + let _10: std::option::Option<isize>; scope 4 { - debug z => _5; -+ debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; ++ debug ((z: Foo).0: u8) => _7; ++ debug ((z: Foo).1: ()) => _8; ++ debug ((z: Foo).2: &str) => _9; ++ debug ((z: Foo).3: std::option::Option<isize>) => _10; let _6: (); scope 5 { debug a => _6; diff --git a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff index d7c57c293c4..304bf2fb1a7 100644 --- a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff @@ -11,7 +11,10 @@ + let _8: std::option::Option<isize>; scope 1 { - debug y => _2; -+ debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; ++ debug ((y: Foo).0: u8) => _5; ++ debug ((y: Foo).1: ()) => _6; ++ debug ((y: Foo).2: &str) => _7; ++ debug ((y: Foo).3: std::option::Option<isize>) => _8; let _3: u8; scope 2 { debug t => _3; diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 68132638759..1c9d33dcc8e 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -61,6 +61,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), + expanded_args: Default::default(), }; interface::run_compiler(config, |compiler| { diff --git a/tests/run-make/compressed-debuginfo/Makefile b/tests/run-make/compressed-debuginfo/Makefile new file mode 100644 index 00000000000..f9e4927d008 --- /dev/null +++ b/tests/run-make/compressed-debuginfo/Makefile @@ -0,0 +1,15 @@ +# ignore-cross-compile +include ../tools.mk + +# only-linux +# min-llvm-version: 16.0 +# +# This tests debuginfo-compression. + +all: zlib zstandard + +zlib: + test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zlib foo.rs 2>&1 | sed 's/.*unknown.*zlib.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZLIB + +zstandard: + test "`$(RUSTC) --crate-name=foo --crate-type=lib --emit=obj -C debuginfo=full -Z debuginfo-compression=zstd foo.rs 2>&1 | sed 's/.*unknown.*zstd.*/missing/' | head -n 1`" = missing || readelf -t $(TMPDIR)/foo.o | grep -q ZST diff --git a/tests/run-make/compressed-debuginfo/foo.rs b/tests/run-make/compressed-debuginfo/foo.rs new file mode 100644 index 00000000000..185ce22450c --- /dev/null +++ b/tests/run-make/compressed-debuginfo/foo.rs @@ -0,0 +1,3 @@ +pub fn foo() -> i32 { + 42 +} diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/Makefile b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile new file mode 100644 index 00000000000..a7be301a5b0 --- /dev/null +++ b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile @@ -0,0 +1,16 @@ +include ../tools.mk + +# only-windows-msvc + +# tests if the pdb contains the following information in the LF_BUILDINFO: +# 1. the commandline args to compile it (cmd) +# 2. full path to the compiler (cl) + +# we just do a stringsearch on the pdb, as these need to show up at least once, as the LF_BUILDINFO is created for each cgu +# actual parsing would be better, but this is a simple and good enough solution for now + +all: + $(RUSTC_ORIGINAL) main.rs -g --crate-name my_crate_name --crate-type bin -C metadata=dc9ef878b0a48666 --out-dir $(TMPDIR) + cat '$(TMPDIR)/my_crate_name.pdb' | grep -F '$(RUSTC_ORIGINAL)' +# using a file containing the string so I don't have problems with escaping quotes and spaces + cat '$(TMPDIR)/my_crate_name.pdb' | grep -f 'stringlist.txt' diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/main.rs b/tests/run-make/pdb-buildinfo-cl-cmd/main.rs new file mode 100644 index 00000000000..f79c691f085 --- /dev/null +++ b/tests/run-make/pdb-buildinfo-cl-cmd/main.rs @@ -0,0 +1,2 @@ +fn main() { +} diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt new file mode 100644 index 00000000000..634e9f19e89 --- /dev/null +++ b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt @@ -0,0 +1 @@ +"main.rs" "-g" "--crate-name" "my_crate_name" "--crate-type" "bin" "-C" "metadata=dc9ef878b0a48666" "--out-dir" \ No newline at end of file diff --git a/tests/run-make/print-cfg/Makefile b/tests/run-make/print-cfg/Makefile index 654c303b3e2..6b153e5b54e 100644 --- a/tests/run-make/print-cfg/Makefile +++ b/tests/run-make/print-cfg/Makefile @@ -13,19 +13,19 @@ all: default output_to_file output_to_file: # Backend-independent, printed by rustc_driver_impl/src/lib.rs - $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt -Z unstable-options + $(RUSTC) --target x86_64-pc-windows-gnu --print cfg=$(TMPDIR)/cfg.txt $(CGREP) windows < $(TMPDIR)/cfg.txt # Printed from CodegenBackend trait impl in rustc_codegen_llvm/src/lib.rs - $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt -Z unstable-options + $(RUSTC) --print relocation-models=$(TMPDIR)/relocation-models.txt $(CGREP) dynamic-no-pic < $(TMPDIR)/relocation-models.txt # Printed by compiler/rustc_codegen_llvm/src/llvm_util.rs - $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt -Z unstable-options + $(RUSTC) --target wasm32-unknown-unknown --print target-features=$(TMPDIR)/target-features.txt $(CGREP) reference-types < $(TMPDIR)/target-features.txt # Printed by C++ code in rustc_llvm/llvm-wrapper/PassWrapper.cpp - $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt -Z unstable-options + $(RUSTC) --target wasm32-unknown-unknown --print target-cpus=$(TMPDIR)/target-cpus.txt $(CGREP) generic < $(TMPDIR)/target-cpus.txt ifdef IS_WINDOWS diff --git a/tests/rustdoc-gui/code-color.goml b/tests/rustdoc-gui/code-color.goml index 833fa05db42..92bdfb25b00 100644 --- a/tests/rustdoc-gui/code-color.goml +++ b/tests/rustdoc-gui/code-color.goml @@ -19,6 +19,18 @@ define-function: ( }, ) -call-function: ("check-colors", ("ayu", "rgb(230, 225, 207)", "rgb(255, 180, 84)")) -call-function: ("check-colors", ("dark", "rgb(221, 221, 221)", "rgb(221, 221, 221)")) -call-function: ("check-colors", ("light", "rgb(0, 0, 0)", "rgb(0, 0, 0)")) +call-function: ("check-colors", { + "theme": "ayu", + "doc_code_color": "#e6e1cf", + "doc_inline_code_color": "#ffb454", +}) +call-function: ("check-colors", { + "theme": "dark", + "doc_code_color": "#ddd", + "doc_inline_code_color": "#ddd", +}) +call-function: ("check-colors", { + "theme": "light", + "doc_code_color": "black", + "doc_inline_code_color": "black", +}) diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml index 6e880302f28..84c20355500 100644 --- a/tests/rustdoc-gui/help-page.goml +++ b/tests/rustdoc-gui/help-page.goml @@ -33,21 +33,21 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "color": "rgb(197, 197, 197)", - "background": "rgb(49, 69, 89)", - "box_shadow": "rgb(92, 103, 115)", + "color": "#c5c5c5", + "background": "#314559", + "box_shadow": "#5c6773", }) call-function: ("check-colors", { "theme": "dark", - "color": "rgb(0, 0, 0)", - "background": "rgb(250, 251, 252)", - "box_shadow": "rgb(198, 203, 209)", + "color": "#000", + "background": "#fafbfc", + "box_shadow": "#c6cbd1", }) call-function: ("check-colors", { "theme": "light", - "color": "rgb(0, 0, 0)", - "background": "rgb(250, 251, 252)", - "box_shadow": "rgb(198, 203, 209)", + "color": "#000", + "background": "#fafbfc", + "box_shadow": "#c6cbd1", }) // This test ensures that opening the help popover without switching pages works. diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml index 46d1856b4d6..e7c64791256 100644 --- a/tests/rustdoc-gui/search-no-result.goml +++ b/tests/rustdoc-gui/search-no-result.goml @@ -21,16 +21,16 @@ define-function: ( call-function: ("check-no-result", { "theme": "ayu", - "link": "rgb(57, 175, 215)", - "link_hover": "rgb(57, 175, 215)", + "link": "#39afd7", + "link_hover": "#39afd7", }) call-function: ("check-no-result", { "theme": "dark", - "link": "rgb(210, 153, 29)", - "link_hover": "rgb(210, 153, 29)", + "link": "#d2991d", + "link_hover": "#d2991d", }) call-function: ("check-no-result", { "theme": "light", - "link": "rgb(56, 115, 173)", - "link_hover": "rgb(56, 115, 173)", + "link": "#3873ad", + "link_hover": "#3873ad", }) diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 913d72932b9..520481d3bba 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -25,24 +25,24 @@ call-function: ( "check-colors", { "theme": "ayu", - "color": "rgb(197, 197, 197)", - "background_color": "rgb(20, 25, 31)", + "color": "#c5c5c5", + "background_color": "#14191f", } ) call-function: ( "check-colors", { "theme": "dark", - "color": "rgb(221, 221, 221)", - "background_color": "rgb(80, 80, 80)", + "color": "#ddd", + "background_color": "#505050", } ) call-function: ( "check-colors", { "theme": "light", - "color": "rgb(0, 0, 0)", - "background_color": "rgb(245, 245, 245)", + "color": "black", + "background_color": "#f5f5f5", } ) @@ -55,7 +55,7 @@ assert-text: (".sidebar > .location", "Crate test_docs") assert-count: (".sidebar .location", 1) assert-count: (".sidebar h2", 1) assert-text: ("#all-types", "All Items") -assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"}) +assert-css: ("#all-types", {"color": "#356da4"}) // We check that we have the crates list and that the "current" on is "test_docs". assert-text: (".sidebar-elems ul.crate > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. @@ -88,7 +88,7 @@ assert-property: ("html", {"scrollTop": "0"}) // We now go back to the crate page to click on the "lib2" crate link. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) -assert-css: (".sidebar-elems ul.crate > li:first-child > a", {"color": "rgb(53, 109, 164)"}) +assert-css: (".sidebar-elems ul.crate > li:first-child > a", {"color": "#356da4"}) click: ".sidebar-elems ul.crate > li:first-child > a" // PAGE: lib2/index.html @@ -140,7 +140,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" assert-property: (".sidebar", {"clientWidth": "200"}) click: "//ul[@class='block mod']/preceding-sibling::h3/a" // PAGE: index.html -assert-css: ("#modules", {"background-color": "rgb(253, 255, 211)"}) +assert-css: ("#modules", {"background-color": "#fdffd3"}) // Finally, assert that the `[+]/[−]` toggle doesn't affect sidebar width. click: "#toggle-all-docs" diff --git a/tests/rustdoc-js-std/full-path-function.js b/tests/rustdoc-js-std/full-path-function.js new file mode 100644 index 00000000000..ac157b3aadf --- /dev/null +++ b/tests/rustdoc-js-std/full-path-function.js @@ -0,0 +1,7 @@ +const EXPECTED = { + 'query': 'vec::vec -> usize', + 'others': [ + { 'path': 'std::vec::Vec', 'name': 'len' }, + { 'path': 'std::vec::Vec', 'name': 'capacity' }, + ], +}; diff --git a/tests/rustdoc-js/full-path-function.js b/tests/rustdoc-js/full-path-function.js new file mode 100644 index 00000000000..48be51b156f --- /dev/null +++ b/tests/rustdoc-js/full-path-function.js @@ -0,0 +1,43 @@ +// exact-check + +const EXPECTED = [ + { + 'query': 'sac -> usize', + 'others': [ + { 'path': 'full_path_function::b::Sac', 'name': 'bar' }, + { 'path': 'full_path_function::b::Sac', 'name': 'len' }, + { 'path': 'full_path_function::sac::Sac', 'name': 'len' }, + ], + }, + { + 'query': 'b::sac -> usize', + 'others': [ + { 'path': 'full_path_function::b::Sac', 'name': 'bar' }, + { 'path': 'full_path_function::b::Sac', 'name': 'len' }, + ], + }, + { + 'query': 'b::sac -> u32', + 'others': [ + { 'path': 'full_path_function::b::Sac', 'name': 'bar2' }, + ], + }, + { + 'query': 'string::string -> u32', + 'others': [ + { 'path': 'full_path_function::b::Sac', 'name': 'string' }, + ], + }, + { + 'query': 'alloc::string::string -> u32', + 'others': [ + { 'path': 'full_path_function::b::Sac', 'name': 'string' }, + ], + }, + { + 'query': 'alloc::string -> u32', + 'others': [ + { 'path': 'full_path_function::b::Sac', 'name': 'string' }, + ], + }, +]; diff --git a/tests/rustdoc-js/full-path-function.rs b/tests/rustdoc-js/full-path-function.rs new file mode 100644 index 00000000000..8dcc3f2b69d --- /dev/null +++ b/tests/rustdoc-js/full-path-function.rs @@ -0,0 +1,17 @@ +pub mod sac { + pub struct Sac; + + impl Sac { + pub fn len(&self) -> usize { 0 } + } +} + +pub mod b { + pub struct Sac; + impl Sac { + pub fn len(&self) -> usize { 0 } + pub fn bar(&self, w: u32) -> usize { 0 } + pub fn bar2(&self, w: u32) -> u32 { 0 } + pub fn string(w: String) -> u32 { 0 } + } +} diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs new file mode 100644 index 00000000000..f4e020b3b95 --- /dev/null +++ b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs @@ -0,0 +1,5 @@ +pub struct InlineOne<A> { + pub inline: A +} + +pub type InlineU64 = InlineOne<u64>; diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc/const-generics/const-generic-defaults.rs index f781c6a62f2..7a0a794112d 100644 --- a/tests/rustdoc/const-generics/const-generic-defaults.rs +++ b/tests/rustdoc/const-generics/const-generic-defaults.rs @@ -1,5 +1,5 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \ -// 'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);' +// 'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(' pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T); diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc/const-generics/const-generics-docs.rs index 828486a41d4..70a9518f05b 100644 --- a/tests/rustdoc/const-generics/const-generics-docs.rs +++ b/tests/rustdoc/const-generics/const-generics-docs.rs @@ -33,7 +33,7 @@ impl<const N: usize> Trait<N> for [u8; N] {} // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \ // 'pub struct Foo<const N: usize> where u8: Trait<N>' pub struct Foo<const N: usize> where u8: Trait<N>; -// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)' +// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(' pub struct Bar<T, const N: usize>([T; N]); // @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>' @@ -92,7 +92,7 @@ macro_rules! define_me { } // @has foo/struct.Foz.html '//pre[@class="rust item-decl"]' \ -// 'pub struct Foz<const N: usize>(_);' +// 'pub struct Foz<const N: usize>(/* private fields */);' define_me!(Foz<N>); trait Q { diff --git a/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs b/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs index 644d0699e9d..df88530071b 100644 --- a/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs +++ b/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs @@ -65,3 +65,22 @@ pub trait HigherRankedBoundTrait1<'e> where for<'l> Self: 'e + 'l {} pub trait AmbiguousBoundTrait<'a, 'b>: 'a + 'b {} pub struct AmbiguousBoundWrapper<'a, 'b, T: ?Sized + 'a + 'b>(&'a T, &'b T); + +// Trait objects inside of another trait object, a trait bound or an associated type. + +pub trait Inner {} +pub trait Outer<T: ?Sized> {} +pub trait Base { + type Type<T: ?Sized>; +} +impl Base for () { + type Type<T: ?Sized> = (); +} + +pub type NestedTraitObjects = dyn Outer<dyn Inner>; + +pub fn apit_rpit(o: impl Outer<dyn Inner>) -> impl Outer<dyn Inner> { + o +} + +pub type AssocTy = <() as Base>::Type<dyn Inner>; diff --git a/tests/rustdoc/inline_cross/dyn_trait.rs b/tests/rustdoc/inline_cross/dyn_trait.rs index 1de01af83d1..679972f035a 100644 --- a/tests/rustdoc/inline_cross/dyn_trait.rs +++ b/tests/rustdoc/inline_cross/dyn_trait.rs @@ -128,3 +128,18 @@ pub use dyn_trait::BareAmbiguousBoundEarly1; // @has user/type.BareAmbiguousBoundStatic.html // @has - '//*[@class="rust item-decl"]//code' "dyn AmbiguousBoundTrait<'o, 'o> + 'static;" pub use dyn_trait::BareAmbiguousBoundStatic; + +// Regression test for issue #115179: + +// @has user/type.NestedTraitObjects.html +// @has - '//*[@class="rust item-decl"]//code' "dyn Outer<dyn Inner>;" +pub use dyn_trait::NestedTraitObjects; + +// @has user/fn.apit_rpit.html +// @has - '//pre[@class="rust item-decl"]' \ +// "apit_rpit(o: impl Outer<dyn Inner>) -> impl Outer<dyn Inner>" +pub use dyn_trait::apit_rpit; + +// @has user/type.AssocTy.html +// @has - '//*[@class="rust item-decl"]//code' "<() as Base>::Type<dyn Inner>" +pub use dyn_trait::AssocTy; diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/issue-32077-type-alias-impls.rs new file mode 100644 index 00000000000..26778c67c24 --- /dev/null +++ b/tests/rustdoc/issue-32077-type-alias-impls.rs @@ -0,0 +1,64 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/32077>. + +#![crate_name = "foo"] + +pub struct GenericStruct<T>(T); + +impl<T> GenericStruct<T> { + pub fn on_gen(arg: T) {} +} + +impl GenericStruct<u32> { + pub fn on_u32(arg: u32) {} +} + +pub trait Foo {} +pub trait Bar {} + +impl<T> Foo for GenericStruct<T> {} +impl Bar for GenericStruct<u32> {} + +// @has 'foo/type.TypedefStruct.html' +// We check that we have the implementation of the type alias itself. +// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct' +// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' +// @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl<T> GenericStruct<T>' +// @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)' +// @has - '//*[@id="impl-Foo-for-GenericStruct%3CT%3E"]/h3' 'impl<T> Foo for GenericStruct<T>' +// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs. +// @!has - '//h3' 'impl Bar for GenericStruct<u32> {}' +// Same goes for the `Deref` impl. +// @!has - '//h2' 'Methods from Deref<Target = u32>' +// @count - '//nav[@class="sidebar"]//a' 'on_alias' 1 +// @count - '//nav[@class="sidebar"]//a' 'on_gen' 1 +// @count - '//nav[@class="sidebar"]//a' 'Foo' 1 +// @!has - '//nav[@class="sidebar"]//a' 'Bar' +// @!has - '//nav[@class="sidebar"]//a' 'on_u32' +pub type TypedefStruct = GenericStruct<u8>; + +impl TypedefStruct { + pub fn on_alias() {} +} + +impl std::ops::Deref for GenericStruct<u32> { + type Target = u32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub struct Wrap<T>(GenericStruct<T>); + +// @has 'foo/type.Alias.html' +// @has - '//h2' 'Methods from Deref<Target = u32>' +// @has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl<T> Deref for Wrap<T>' +pub type Alias = Wrap<u32>; + +impl<T> std::ops::Deref for Wrap<T> { + type Target = GenericStruct<T>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/tests/rustdoc/issue-88600.rs b/tests/rustdoc/issue-88600.rs index db0d102b741..f89af472f6e 100644 --- a/tests/rustdoc/issue-88600.rs +++ b/tests/rustdoc/issue-88600.rs @@ -8,10 +8,10 @@ pub struct S; // @has issue_88600/enum.FooEnum.html pub enum FooEnum { - // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(_)' + // @has - '//*[@id="variant.HiddenTupleItem"]//h3' 'HiddenTupleItem(/* private fields */)' // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0 HiddenTupleItem(#[doc(hidden)] H), - // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(_, _)' + // @has - '//*[@id="variant.MultipleHidden"]//h3' 'MultipleHidden(/* private fields */)' // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0 // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0 MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H), diff --git a/tests/rustdoc/private-fields-tuple-struct.rs b/tests/rustdoc/private-fields-tuple-struct.rs new file mode 100644 index 00000000000..c6989dd8cdf --- /dev/null +++ b/tests/rustdoc/private-fields-tuple-struct.rs @@ -0,0 +1,15 @@ +// This test checks the diplay of "/* private fields */" sentence in tuple structs. +#![crate_name = "foo"] + +// @has 'foo/struct.A.html' '//*[@class="rust item-decl"]/code' 'pub struct A(pub u8, _);' +pub struct A(pub u8, u8); +// @has 'foo/struct.B.html' '//*[@class="rust item-decl"]/code' 'pub struct B(_, pub u8);' +pub struct B(u8, pub u8); +// @has 'foo/struct.C.html' '//*[@class="rust item-decl"]/code' 'pub struct C(_, pub u8, _);' +pub struct C(u8, pub u8, u8); +// @has 'foo/struct.D.html' '//*[@class="rust item-decl"]/code' 'pub struct D(pub u8, _, pub u8);' +pub struct D(pub u8, u8, pub u8); +// @has 'foo/struct.E.html' '//*[@class="rust item-decl"]/code' 'pub struct E(/* private fields */);' +pub struct E(u8); +// @has 'foo/struct.F.html' '//*[@class="rust item-decl"]/code' 'pub struct F(/* private fields */);' +pub struct F(u8, u8); diff --git a/tests/rustdoc/show-const-contents.rs b/tests/rustdoc/show-const-contents.rs index 69e742ee747..91df03adbbc 100644 --- a/tests/rustdoc/show-const-contents.rs +++ b/tests/rustdoc/show-const-contents.rs @@ -47,7 +47,7 @@ pub struct MyTypeWithStr(&'static str); // @!hasraw show_const_contents/constant.MY_TYPE_WITH_STR.html '; //' pub const MY_TYPE_WITH_STR: MyTypeWithStr = MyTypeWithStr("show this"); -// @hasraw show_const_contents/constant.PI.html '= 3.14159265358979323846264338327950288f32;' +// @hasraw show_const_contents/constant.PI.html '= 3.14159265358979323846264338327950288_f32;' // @hasraw show_const_contents/constant.PI.html '; // 3.14159274f32' pub use std::f32::consts::PI; diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs new file mode 100644 index 00000000000..ff84352d716 --- /dev/null +++ b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs @@ -0,0 +1,34 @@ +#![crate_name = "inner_types_lazy"] + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +// @has 'inner_types_lazy/struct.Pair.html' +pub struct Pair<A, B> { + pub first: A, + pub second: B, +} + +// @has 'inner_types_lazy/type.ReversedTypesPair.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 0 +pub type ReversedTypesPair<Q, R> = Pair<R, Q>; + +// @has 'inner_types_lazy/type.ReadWrite.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 2 +pub type ReadWrite<R, W> = Pair<R, W> +where + R: std::io::Read, + W: std::io::Write; + +// @has 'inner_types_lazy/type.VecPair.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//span[@class="where fmt-newline"]' 0 +pub type VecPair<U, V> = Pair<Vec<U>, Vec<V>>; diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs new file mode 100644 index 00000000000..b734714fd64 --- /dev/null +++ b/tests/rustdoc/typedef-inner-variants.rs @@ -0,0 +1,119 @@ +// This test checks different combinations of structs, enums, and unions +// for the "Show Aliased Type" feature on type definition. + +#![crate_name = "inner_variants"] + +// aux-build:cross_crate_generic_typedef.rs +extern crate cross_crate_generic_typedef; + +pub struct Adt; +pub struct Ty; +pub struct TyCtxt; + +pub trait Interner { + type Adt; + type Ty; +} + +impl Interner for TyCtxt { + type Adt = Adt; + type Ty = Ty; +} + +// @has 'inner_variants/type.AliasTy.html' +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 0 +pub type AliasTy = Ty; + +// @has 'inner_variants/enum.IrTyKind.html' +pub enum IrTyKind<A, I: Interner> { + /// Doc comment for AdtKind + AdtKind(I::Adt), + /// and another one for TyKind + TyKind(I::Adt, <I as Interner>::Ty), + // no comment + StructKind { a: A, }, + #[doc(hidden)] + Unspecified, +} + +// @has 'inner_variants/type.NearlyTyKind.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 1 +// @count - '//*[@id="fields"]' 0 +pub type NearlyTyKind<A> = IrTyKind<A, TyCtxt>; + +// @has 'inner_variants/type.TyKind.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 1 +// @count - '//*[@id="fields"]' 0 +// @count - '//*[@class="variant"]' 3 +// @matches - '//pre[@class="rust item-decl"]//code' "enum TyKind" +// @has - '//pre[@class="rust item-decl"]//code/a[1]' "Adt" +// @has - '//pre[@class="rust item-decl"]//code/a[2]' "Adt" +// @has - '//pre[@class="rust item-decl"]//code/a[3]' "Ty" +// @has - '//pre[@class="rust item-decl"]//code/a[4]' "i64" +pub type TyKind = IrTyKind<i64, TyCtxt>; + +// @has 'inner_variants/union.OneOr.html' +pub union OneOr<A: Copy> { + pub one: i64, + pub or: A, +} + +// @has 'inner_variants/type.OneOrF64.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//*[@class="structfield small-section-header"]' 2 +// @matches - '//pre[@class="rust item-decl"]//code' "union OneOrF64" +pub type OneOrF64 = OneOr<f64>; + +// @has 'inner_variants/struct.One.html' +pub struct One<T> { + pub val: T, + #[doc(hidden)] + pub __hidden: T, + __private: T, +} + +// @has 'inner_variants/type.OneU64.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @count - '//*[@class="structfield small-section-header"]' 1 +// @matches - '//pre[@class="rust item-decl"]//code' "struct OneU64" +// @matches - '//pre[@class="rust item-decl"]//code' "pub val" +pub type OneU64 = One<u64>; + +// @has 'inner_variants/struct.OnceA.html' +pub struct OnceA<'a, A> { + pub a: &'a A, +} + +// @has 'inner_variants/type.Once.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @matches - '//pre[@class="rust item-decl"]//code' "struct Once<'a>" +// @matches - '//pre[@class="rust item-decl"]//code' "&'a" +pub type Once<'a> = OnceA<'a, i64>; + +// @has 'inner_variants/struct.HighlyGenericStruct.html' +pub struct HighlyGenericStruct<A, B, C, D> { + pub z: (A, B, C, D) +} + +// @has 'inner_variants/type.HighlyGenericAABB.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +// @matches - '//pre[@class="rust item-decl"]//code' "struct HighlyGenericAABB<A, B>" +// @matches - '//pre[@class="rust item-decl"]//code' "pub z" +pub type HighlyGenericAABB<A, B> = HighlyGenericStruct<A, A, B, B>; + +// @has 'inner_variants/type.InlineU64.html' +// @count - '//*[@id="aliased-type"]' 1 +// @count - '//*[@id="variants"]' 0 +// @count - '//*[@id="fields"]' 1 +pub use cross_crate_generic_typedef::InlineU64; diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html index 3e72ba2b74f..46708b9e4e9 100644 --- a/tests/rustdoc/where.SWhere_Simd_item-decl.html +++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html @@ -1,3 +1,3 @@ -<pre class="rust item-decl"><code>pub struct Simd<T>(_) +<pre class="rust item-decl"><code>pub struct Simd<T>(/* private fields */) <span class="where">where T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre> diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc/where.alpha_trait_decl.html index a7700055c9a..0c0b2d1ceca 100644 --- a/tests/rustdoc/where.alpha_trait_decl.html +++ b/tests/rustdoc/where.alpha_trait_decl.html @@ -1,3 +1,3 @@ -<code>pub struct Alpha<A>(_) +<code>pub struct Alpha<A>(/* private fields */) <span class="where">where A: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code> \ No newline at end of file diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 2aa9c8b5461..aea02c14039 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -4,7 +4,7 @@ use std::io::Lines; pub trait MyTrait { fn dummy(&self) { } } -// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait" +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(/* private fields */) where A: MyTrait" // @snapshot alpha_trait_decl - '//*[@class="rust item-decl"]/code' pub struct Alpha<A>(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait" diff --git a/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr b/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr index 20486d596d9..6e17bbde021 100644 --- a/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr +++ b/tests/ui-fulldeps/plugin/lint-group-plugin-deny-cmdline.stderr @@ -13,6 +13,7 @@ LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | = note: `-D test-lint` implied by `-D lint-me` + = help: to override `-D lint-me` add `#[allow(test_lint)]` error: item is named 'pleaselintme' --> $DIR/lint-group-plugin-deny-cmdline.rs:12:1 @@ -21,6 +22,7 @@ LL | fn pleaselintme() { } | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D please-lint` implied by `-D lint-me` + = help: to override `-D lint-me` add `#[allow(please_lint)]` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr index b060e3a3e38..0e661795999 100644 --- a/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr +++ b/tests/ui-fulldeps/plugin/lint-tool-cmdline-allow.stderr @@ -1,9 +1,12 @@ -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint +warning: lint name `test_lint` is deprecated and may not have an effect in the future. | + = help: change it to clippy::test_lint = note: requested on the command line with `-A test_lint` + = note: `#[warn(renamed_and_removed_lints)]` on by default -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint +warning: lint name `test_lint` is deprecated and may not have an effect in the future. | + = help: change it to clippy::test_lint = note: requested on the command line with `-A test_lint` warning: item is named 'lintme' @@ -22,8 +25,9 @@ LL | #![plugin(lint_tool_test)] | = note: `#[warn(deprecated)]` on by default -warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint +warning: lint name `test_lint` is deprecated and may not have an effect in the future. | + = help: change it to clippy::test_lint = note: requested on the command line with `-A test_lint` warning: 5 warnings emitted diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 8c876213ae0..e014fc8c693 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -23,7 +23,7 @@ LL | arg: NotIntoDiagnosticArg, | = help: normalized in stderr note: required by a bound in `Diagnostic::set_arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:960:5 + --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:968:5 error: aborting due to 2 previous errors diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs new file mode 100644 index 00000000000..23a9e2a064c --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -0,0 +1,77 @@ +// run-pass +// Test StableMIR behavior when different results are given + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] + +extern crate rustc_middle; +extern crate rustc_smir; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::{rustc_internal, stable_mir}; +use std::io::Write; +use std::ops::ControlFlow; + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "input_compilation_result_test.rs"; + generate_input(&path).unwrap(); + let args = vec!["rustc".to_string(), path.to_string()]; + test_continue(args.clone()); + test_break(args.clone()); + test_failed(args.clone()); + test_skipped(args); +} + +fn test_continue(args: Vec<String>) { + let continue_fn = |_: TyCtxt| ControlFlow::Continue::<(), bool>(true); + let result = rustc_internal::StableMir::new(args, continue_fn).run(); + assert_eq!(result, Ok(true)); +} + +fn test_break(args: Vec<String>) { + let continue_fn = |_: TyCtxt| ControlFlow::Break::<bool, i32>(false); + let result = rustc_internal::StableMir::new(args, continue_fn).run(); + assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false))); +} + +fn test_skipped(mut args: Vec<String>) { + args.push("--version".to_string()); + let unreach_fn = |_: TyCtxt| -> ControlFlow<()> { unreachable!() }; + let result = rustc_internal::StableMir::new(args, unreach_fn).run(); + assert_eq!(result, Err(stable_mir::CompilerError::Skipped)); +} + +fn test_failed(mut args: Vec<String>) { + args.push("--cfg=broken".to_string()); + let unreach_fn = |_: TyCtxt| -> ControlFlow<()> { unreachable!() }; + let result = rustc_internal::StableMir::new(args, unreach_fn).run(); + assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + // This should trigger a compilation failure when enabled. + #[cfg(broken)] + mod broken_mod {{ + fn call_invalid() {{ + invalid_fn(); + }} + }} + + fn main() {{}} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 00dce3e004e..d55eae86f07 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -8,6 +8,7 @@ #![feature(rustc_private)] #![feature(assert_matches)] +#![feature(control_flow_enum)] extern crate rustc_hir; extern crate rustc_middle; @@ -15,14 +16,18 @@ extern crate rustc_smir; use rustc_hir::def::DefKind; use rustc_middle::ty::TyCtxt; -use rustc_smir::{rustc_internal, stable_mir}; +use rustc_smir::{ + rustc_internal, + stable_mir::{self, fold::Foldable}, +}; use std::assert_matches::assert_matches; use std::io::Write; +use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(tcx: TyCtxt<'_>) { +fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> { // Get the local crate using stable_mir API. let local = stable_mir::local_crate(); assert_eq!(&local.name, CRATE_NAME); @@ -108,6 +113,48 @@ fn test_stable_mir(tcx: TyCtxt<'_>) { stable_mir::mir::Terminator::Assert { .. } => {} other => panic!("{other:?}"), } + + let monomorphic = get_item(tcx, &items, (DefKind::Fn, "monomorphic")).unwrap(); + for block in monomorphic.body().blocks { + match &block.terminator { + stable_mir::mir::Terminator::Call { func, .. } => match func { + stable_mir::mir::Operand::Constant(c) => match &c.literal.literal { + stable_mir::ty::ConstantKind::Allocated(alloc) => { + assert!(alloc.bytes.is_empty()); + match c.literal.ty.kind() { + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::FnDef( + def, + mut args, + )) => { + let func = def.body(); + match func.locals[1] + .fold(&mut args) + .continue_value() + .unwrap() + .kind() + { + stable_mir::ty::TyKind::RigidTy( + stable_mir::ty::RigidTy::Uint(_), + ) => {} + stable_mir::ty::TyKind::RigidTy( + stable_mir::ty::RigidTy::Tuple(_), + ) => {} + other => panic!("{other:?}"), + } + } + other => panic!("{other:?}"), + } + } + other => panic!("{other:?}"), + }, + other => panic!("{other:?}"), + }, + stable_mir::mir::Terminator::Return => {} + other => panic!("{other:?}"), + } + } + + ControlFlow::Continue(()) } // Use internal API to find a function in a crate. @@ -136,7 +183,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - rustc_internal::StableMir::new(args, test_stable_mir).run(); + rustc_internal::StableMir::new(args, test_stable_mir).run().unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { @@ -144,6 +191,16 @@ fn generate_input(path: &str) -> std::io::Result<()> { write!( file, r#" + fn generic<T, const U: usize>(t: T) -> [(); U] {{ + _ = t; + [(); U] + }} + + pub fn monomorphic() {{ + generic::<(), 5>(()); + generic::<u32, 0>(45); + }} + mod foo {{ pub fn bar(i: i32) -> i64 {{ i as i64 diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs new file mode 100644 index 00000000000..86fb365507a --- /dev/null +++ b/tests/ui/abi/compatibility.rs @@ -0,0 +1,150 @@ +// check-pass +#![feature(rustc_attrs, transparent_unions)] +#![allow(unused, improper_ctypes_definitions)] +use std::marker::PhantomData; +use std::mem::ManuallyDrop; +use std::num::NonZeroI32; +use std::ptr::NonNull; + +macro_rules! assert_abi_compatible { + ($name:ident, $t1:ty, $t2:ty) => { + mod $name { + use super::*; + // Test argument and return value, `Rust` and `C` ABIs. + #[rustc_abi(assert_eq)] + type TestRust = (fn($t1) -> $t1, fn($t2) -> $t2); + #[rustc_abi(assert_eq)] + type TestC = (extern "C" fn($t1) -> $t1, extern "C" fn($t2) -> $t2); + } + }; +} + +#[derive(Copy, Clone)] +struct Zst; + +#[repr(C)] +struct ReprC1<T>(T); +#[repr(C)] +struct ReprC2Int<T>(i32, T); +#[repr(C)] +struct ReprC2Float<T>(f32, T); +#[repr(C)] +struct ReprC4<T>(T, Vec<i32>, Zst, T); +#[repr(C)] +struct ReprC4Mixed<T>(T, f32, i32, T); +#[repr(C)] +enum ReprCEnum<T> { + Variant1, + Variant2(T), +} +#[repr(C)] +union ReprCUnion<T> { + nothing: (), + something: ManuallyDrop<T>, +} + +macro_rules! test_abi_compatible { + ($name:ident, $t1:ty, $t2:ty) => { + mod $name { + use super::*; + assert_abi_compatible!(plain, $t1, $t2); + // We also do some tests with differences in fields of `repr(C)` types. + assert_abi_compatible!(repr_c_1, ReprC1<$t1>, ReprC1<$t2>); + assert_abi_compatible!(repr_c_2_int, ReprC2Int<$t1>, ReprC2Int<$t2>); + assert_abi_compatible!(repr_c_2_float, ReprC2Float<$t1>, ReprC2Float<$t2>); + assert_abi_compatible!(repr_c_4, ReprC4<$t1>, ReprC4<$t2>); + assert_abi_compatible!(repr_c_4mixed, ReprC4Mixed<$t1>, ReprC4Mixed<$t2>); + assert_abi_compatible!(repr_c_enum, ReprCEnum<$t1>, ReprCEnum<$t2>); + assert_abi_compatible!(repr_c_union, ReprCUnion<$t1>, ReprCUnion<$t2>); + } + }; +} + +// Compatibility of pointers is probably de-facto guaranteed, +// but that does not seem to be documented. +test_abi_compatible!(ptr_mut, *const i32, *mut i32); +test_abi_compatible!(ptr_pointee, *const i32, *const Vec<i32>); +test_abi_compatible!(ref_mut, &i32, &mut i32); +test_abi_compatible!(ref_ptr, &i32, *const i32); +test_abi_compatible!(box_ptr, Box<i32>, *const i32); +test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32); +test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32); + +// Some further guarantees we will likely (have to) make. +test_abi_compatible!(zst_unit, Zst, ()); +test_abi_compatible!(zst_array, Zst, [u8; 0]); +test_abi_compatible!(nonzero_int, NonZeroI32, i32); + +// `repr(transparent)` compatibility. +#[repr(transparent)] +struct Wrapper1<T>(T); +#[repr(transparent)] +struct Wrapper2<T>((), Zst, T); +#[repr(transparent)] +struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>); +#[repr(transparent)] +union WrapperUnion<T> { + nothing: (), + something: ManuallyDrop<T>, +} + +macro_rules! test_transparent { + ($name:ident, $t:ty) => { + mod $name { + use super::*; + test_abi_compatible!(wrap1, $t, Wrapper1<$t>); + test_abi_compatible!(wrap2, $t, Wrapper2<$t>); + test_abi_compatible!(wrap3, $t, Wrapper3<$t>); + test_abi_compatible!(wrap4, $t, WrapperUnion<$t>); + } + }; +} + +test_transparent!(simple, i32); +test_transparent!(reference, &'static i32); +test_transparent!(zst, Zst); +test_transparent!(unit, ()); +test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment +test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit +test_transparent!(tuple, (i32, f32, i64, f64)); +test_transparent!(empty_array, [u32; 0]); +test_transparent!(empty_1zst_array, [u8; 0]); +test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit +test_transparent!(large_array, [i32; 16]); +test_transparent!(enum_, Option<i32>); +test_transparent!(enum_niched, Option<&'static i32>); +// Pure-float types that are not ScalarPair seem to be tricky. +// FIXME: <https://github.com/rust-lang/rust/issues/115664> +#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] +mod tricky { + use super::*; + test_transparent!(triple_f32, (f32, f32, f32)); + test_transparent!(triple_f64, (f64, f64, f64)); +} + +// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>. +macro_rules! test_nonnull { + ($name:ident, $t:ty) => { + mod $name { + use super::*; + test_abi_compatible!(option, Option<$t>, $t); + test_abi_compatible!(result_err_unit, Result<$t, ()>, $t); + test_abi_compatible!(result_ok_unit, Result<(), $t>, $t); + test_abi_compatible!(result_err_zst, Result<$t, Zst>, $t); + test_abi_compatible!(result_ok_zst, Result<Zst, $t>, $t); + test_abi_compatible!(result_err_arr, Result<$t, [i8; 0]>, $t); + test_abi_compatible!(result_ok_arr, Result<[i8; 0], $t>, $t); + } + } +} + +test_nonnull!(ref_, &i32); +test_nonnull!(mut_, &mut i32); +test_nonnull!(ref_unsized, &[i32]); +test_nonnull!(mut_unsized, &mut [i32]); +test_nonnull!(fn_, fn()); +test_nonnull!(nonnull, NonNull<i32>); +test_nonnull!(nonnull_unsized, NonNull<dyn std::fmt::Debug>); +test_nonnull!(non_zero, NonZeroI32); + +fn main() {} diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index 13464be275e..ac37d7b6bff 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -4,20 +4,51 @@ // normalize-stderr-test "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL" // This pattern is prepared for when we account for alignment in the niche. // normalize-stderr-test "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL" +// normalize-stderr-test "Leaf\(0x0*20\)" -> "Leaf(0x0...20)" // Some attributes are only computed for release builds: // compile-flags: -O #![feature(rustc_attrs)] #![crate_type = "lib"] +struct S(u16); + #[rustc_abi(debug)] fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi +#[rustc_abi(debug)] +type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi #[rustc_abi(debug)] fn test_generic<T>(_x: *const T) { } //~ ERROR: fn_abi -struct S(u16); +#[rustc_abi(debug)] +const C: () = (); //~ ERROR: can only be applied to + +impl S { + #[rustc_abi(debug)] + const C: () = (); //~ ERROR: can only be applied to +} + impl S { #[rustc_abi(debug)] fn assoc_test(&self) { } //~ ERROR: fn_abi } + +#[rustc_abi(assert_eq)] +type TestAbiEq = (fn(bool), fn(bool)); + +#[rustc_abi(assert_eq)] +type TestAbiNe = (fn(u8), fn(u32)); //~ ERROR: ABIs are not compatible + +#[rustc_abi(assert_eq)] +type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); //~ ERROR: ABIs are not compatible + +#[rustc_abi(assert_eq)] +type TestAbiNeFloat = (fn(f32), fn(u32)); //~ ERROR: ABIs are not compatible + +// Sign matters on some targets (such as s390x), so let's make sure we never accept this. +#[rustc_abi(assert_eq)] +type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible + +#[rustc_abi(assert_eq)] +type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 4f4ee3de4b8..f56f5c525ab 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -1,4 +1,4 @@ -error: fn_abi_of_instance(test) = FnAbi { +error: fn_abi_of(test) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { @@ -87,16 +87,110 @@ error: fn_abi_of_instance(test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:13:1 + --> $DIR/debug.rs:16:1 | LL | fn test(_x: u8) -> bool { true } | ^^^^^^^^^^^^^^^^^^^^^^^ -error: fn_abi_of_instance(test_generic) = FnAbi { +error: fn_abi_of(TestFnPtr) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { - ty: *const T, + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:19:1 + | +LL | type TestFnPtr = fn(bool) -> u8; + | ^^^^^^^^^^^^^^ + +error: fn_abi_of(test_generic) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: *const T/#0, layout: Layout { size: $SOME_SIZE, align: AbiAndPrefAlign { @@ -163,16 +257,620 @@ error: fn_abi_of_instance(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:17:1 + --> $DIR/debug.rs:22:1 | LL | fn test_generic<T>(_x: *const T) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: fn_abi_of_instance(assoc_test) = FnAbi { +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:25:1 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:41:1 + | +LL | type TestAbiNe = (fn(u8), fn(u32)); + | ^^^^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u8; Const { ty: usize, kind: Leaf(0x0...20) }], + layout: Layout { + size: Size(32 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Array { + stride: Size(1 bytes), + count: 32, + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: NoAlias | NoCapture | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(32 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + extra_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u32; Const { ty: usize, kind: Leaf(0x0...20) }], + layout: Layout { + size: Size(128 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Array { + stride: Size(4 bytes), + count: 32, + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: NoAlias | NoCapture | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(128 bytes), + pointee_align: Some( + Align(4 bytes), + ), + }, + extra_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:44:1 + | +LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); + | ^^^^^^^^^^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: f32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: F32, + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:47:1 + | +LL | type TestAbiNeFloat = (fn(f32), fn(u32)); + | ^^^^^^^^^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + true, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:51:1 + | +LL | type TestAbiNeSign = (fn(i32), fn(u32)); + | ^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/debug.rs:54:46 + | +LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:29:5 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: fn_abi_of(assoc_test) = FnAbi { args: [ ArgAbi { layout: TyAndLayout { - ty: &S, + ty: &ReErased Adt(S, []), layout: Layout { size: $SOME_SIZE, align: AbiAndPrefAlign { @@ -251,10 +949,11 @@ error: fn_abi_of_instance(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:22:5 + --> $DIR/debug.rs:34:5 | LL | fn assoc_test(&self) { } | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-consts/double-elided.rs b/tests/ui/associated-consts/double-elided.rs new file mode 100644 index 00000000000..fd0317781bb --- /dev/null +++ b/tests/ui/associated-consts/double-elided.rs @@ -0,0 +1,12 @@ +struct S; + +impl S { + const C: &&str = &""; + //~^ WARN `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| WARN `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| ERROR in type `&&str`, reference has a longer lifetime than the data it references +} + +fn main() {} diff --git a/tests/ui/associated-consts/double-elided.stderr b/tests/ui/associated-consts/double-elided.stderr new file mode 100644 index 00000000000..ba4e6a23e27 --- /dev/null +++ b/tests/ui/associated-consts/double-elided.stderr @@ -0,0 +1,47 @@ +warning: `&` without an explicit lifetime name cannot be used here + --> $DIR/double-elided.rs:4:14 + | +LL | const C: &&str = &""; + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010> + = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default +help: use the `'static` lifetime + | +LL | const C: &'static &str = &""; + | +++++++ + +warning: `&` without an explicit lifetime name cannot be used here + --> $DIR/double-elided.rs:4:15 + | +LL | const C: &&str = &""; + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010> +help: use the `'static` lifetime + | +LL | const C: &&'static str = &""; + | +++++++ + +error[E0491]: in type `&&str`, reference has a longer lifetime than the data it references + --> $DIR/double-elided.rs:4:5 + | +LL | const C: &&str = &""; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the anonymous lifetime as defined here + --> $DIR/double-elided.rs:4:14 + | +LL | const C: &&str = &""; + | ^ +note: but the referenced data is only valid for the anonymous lifetime as defined here + --> $DIR/double-elided.rs:4:14 + | +LL | const C: &&str = &""; + | ^ + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index c2da4f57696..edce1045e24 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -13,12 +13,12 @@ error: future cannot be sent between threads safely LL | is_send(foo::<T>()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>>` + = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method() }` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/basic.rs:13:5 | LL | T::method().await?; - | ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>>`, which is not `Send` + | ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>> { <T as Foo>::method() }`, which is not `Send` note: required by a bound in `is_send` --> $DIR/basic.rs:17:20 | diff --git a/tests/ui/associated-types/issue-23595-2.stderr b/tests/ui/associated-types/issue-23595-2.stderr index dded673f6ee..73effa9f955 100644 --- a/tests/ui/associated-types/issue-23595-2.stderr +++ b/tests/ui/associated-types/issue-23595-2.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `anything_here_kills_it` not found for `Self` --> $DIR/issue-23595-2.rs:6:22 | LL | type B = C<Self::anything_here_kills_it>; - | ^^^^^^^^^^^^^^^^^^^^^^ associated type `anything_here_kills_it` not found + | ^^^^^^^^^^^^^^^^^^^^^^ help: `Self` has the following associated type: `B` error: aborting due to previous error diff --git a/tests/ui/associated-types/issue-85103-layout-debug.rs b/tests/ui/associated-types/issue-85103-layout-debug.rs new file mode 100644 index 00000000000..77c9876ffa5 --- /dev/null +++ b/tests/ui/associated-types/issue-85103-layout-debug.rs @@ -0,0 +1,9 @@ +#![feature(rustc_attrs)] + +use std::borrow::Cow; + +#[rustc_layout(debug)] +type Edges<'a, E> = Cow<'a, [E]>; +//~^ the trait bound `[E]: ToOwned` is not satisfied + +fn main() {} diff --git a/tests/ui/associated-types/issue-85103-layout-debug.stderr b/tests/ui/associated-types/issue-85103-layout-debug.stderr new file mode 100644 index 00000000000..0bdea10ba47 --- /dev/null +++ b/tests/ui/associated-types/issue-85103-layout-debug.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `[E]: ToOwned` is not satisfied + --> $DIR/issue-85103-layout-debug.rs:6:21 + | +LL | type Edges<'a, E> = Cow<'a, [E]>; + | ^^^^^^^^^^^^ the trait `ToOwned` is not implemented for `[E]` + | +note: required by a bound in `Cow` + --> $SRC_DIR/alloc/src/borrow.rs:LL:COL +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | type Edges<'a, E> where [E]: ToOwned = Cow<'a, [E]>; + | ++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-85103.rs b/tests/ui/associated-types/issue-85103.rs deleted file mode 100644 index 9c6a419e9f7..00000000000 --- a/tests/ui/associated-types/issue-85103.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(rustc_attrs)] - -use std::borrow::Cow; - -#[rustc_layout(debug)] -type Edges<'a, E> = Cow<'a, [E]>; -//~^ 6:1: 6:18: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized - -fn main() {} diff --git a/tests/ui/associated-types/issue-85103.stderr b/tests/ui/associated-types/issue-85103.stderr deleted file mode 100644 index 17f7148074c..00000000000 --- a/tests/ui/associated-types/issue-85103.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unable to determine layout for `<[E] as ToOwned>::Owned` because `<[E] as ToOwned>::Owned` cannot be normalized - --> $DIR/issue-85103.rs:6:1 - | -LL | type Edges<'a, E> = Cow<'a, [E]>; - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr index 5d29325c827..c855e902ba9 100644 --- a/tests/ui/async-await/async-is-unwindsafe.stderr +++ b/tests/ui/async-await/async-is-unwindsafe.stderr @@ -15,7 +15,7 @@ LL | | }); | within this `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]` | = help: within `[async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6]`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>` - = note: `UnwindSafe` is implemented for `&std::task::Context<'_>`, but not for `&mut std::task::Context<'_>` + = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>` note: future does not implement `UnwindSafe` as this value is used across an await --> $DIR/async-is-unwindsafe.rs:25:18 | diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs index 81e1e59a362..3505690f1ec 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs @@ -2,14 +2,14 @@ // edition: 2021 #![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] use std::future::Future; use std::pin::Pin; use std::task::Poll; -trait MyTrait { +pub trait MyTrait { async fn foo(&self) -> i32; } @@ -27,8 +27,7 @@ impl Future for MyFuture { } impl MyTrait for i32 { - // FIXME: this should eventually require `#[refine]` to compile, because it also provides - // `Clone`. + #[expect(refining_impl_trait)] fn foo(&self) -> impl Future<Output = i32> + Clone { MyFuture(*self) } diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs index fb92ec78674..0a5023176fe 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared.rs @@ -12,7 +12,7 @@ trait MyTrait { } impl MyTrait for i32 { - fn foo(&self) -> impl Future<Output = i32> + '_ { + fn foo(&self) -> impl Future<Output = i32> { async { *self } } } diff --git a/tests/ui/async-await/large_moves.attribute.stderr b/tests/ui/async-await/large_moves.attribute.stderr index ef9fd78ffe3..1d1999462ce 100644 --- a/tests/ui/async-await/large_moves.attribute.stderr +++ b/tests/ui/async-await/large_moves.attribute.stderr @@ -1,5 +1,5 @@ error: moving 10024 bytes - --> $DIR/large_moves.rs:19:14 + --> $DIR/large_moves.rs:21:14 | LL | let z = (x, 42); | ^ value moved from here @@ -12,12 +12,28 @@ LL | #![deny(large_assignments)] | ^^^^^^^^^^^^^^^^^ error: moving 10024 bytes - --> $DIR/large_moves.rs:20:13 + --> $DIR/large_moves.rs:22:13 | LL | let a = z.0; | ^^^ value moved from here | = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -error: aborting due to 2 previous errors +error: moving 9999 bytes + --> $DIR/large_moves.rs:27:13 + | +LL | let _ = NotBox::new([0; 9999]); + | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 9999 bytes + --> $DIR/large_moves.rs:41:13 + | +LL | data, + | ^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/large_moves.option.stderr b/tests/ui/async-await/large_moves.option.stderr index ef9fd78ffe3..1d1999462ce 100644 --- a/tests/ui/async-await/large_moves.option.stderr +++ b/tests/ui/async-await/large_moves.option.stderr @@ -1,5 +1,5 @@ error: moving 10024 bytes - --> $DIR/large_moves.rs:19:14 + --> $DIR/large_moves.rs:21:14 | LL | let z = (x, 42); | ^ value moved from here @@ -12,12 +12,28 @@ LL | #![deny(large_assignments)] | ^^^^^^^^^^^^^^^^^ error: moving 10024 bytes - --> $DIR/large_moves.rs:20:13 + --> $DIR/large_moves.rs:22:13 | LL | let a = z.0; | ^^^ value moved from here | = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -error: aborting due to 2 previous errors +error: moving 9999 bytes + --> $DIR/large_moves.rs:27:13 + | +LL | let _ = NotBox::new([0; 9999]); + | ^^^^^^^^^^^^^^^^^^^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: moving 9999 bytes + --> $DIR/large_moves.rs:41:13 + | +LL | data, + | ^^^^ value moved from here + | + = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` + +error: aborting due to 4 previous errors diff --git a/tests/ui/async-await/large_moves.rs b/tests/ui/async-await/large_moves.rs index faf6c66c612..62b12104694 100644 --- a/tests/ui/async-await/large_moves.rs +++ b/tests/ui/async-await/large_moves.rs @@ -9,6 +9,8 @@ // edition:2018 // compile-flags: -Zmir-opt-level=0 +use std::{sync::Arc, rc::Rc}; + fn main() { let x = async { let y = [0; 9999]; @@ -19,8 +21,24 @@ fn main() { let z = (x, 42); //~ ERROR large_assignments let a = z.0; //~ ERROR large_assignments let b = z.1; + let _ = Arc::new([0; 9999]); // OK! + let _ = Box::new([0; 9999]); // OK! + let _ = Rc::new([0; 9999]); // OK! + let _ = NotBox::new([0; 9999]); //~ ERROR large_assignments } async fn thing(y: &[u8]) { dbg!(y); } + +struct NotBox { + data: [u8; 9999], +} + +impl NotBox { + fn new(data: [u8; 9999]) -> Self { + Self { + data, //~ ERROR large_assignments + } + } +} diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr new file mode 100644 index 00000000000..3b63ec45804 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr @@ -0,0 +1,27 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:23:11 + | +LL | build(Bar); + | ----- ^^^ `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Send` is not implemented for `impl Future<Output = ()> { <_ as Foo>::bar() }` +note: required by a bound in `build` + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:20:39 + | +LL | fn build<T>(_: T) where T: Foo<bar(): Send> {} + | ^^^^ required by this bound in `build` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr new file mode 100644 index 00000000000..6fab7178767 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs new file mode 100644 index 00000000000..b2cd9707db9 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -0,0 +1,24 @@ +// revisions: current next +//[current] known-bug: #109924 +//[next] check-pass +//[next] compile-flags: -Ztrait-solver=next +// edition:2021 + +#![feature(async_fn_in_trait)] +#![feature(return_type_notation)] +//[next]~^ WARN the feature `return_type_notation` is incomplete + +trait Foo { + async fn bar(&self); +} + +struct Bar; +impl Foo for Bar { + async fn bar(&self) {} +} + +fn build<T>(_: T) where T: Foo<bar(): Send> {} + +fn main() { + build(Bar); +} diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs new file mode 100644 index 00000000000..4a6c2f9ed06 --- /dev/null +++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs @@ -0,0 +1,16 @@ +#![allow(dead_code)] + +fn bar<'a>(_: std::fmt::Arguments<'a>) {} +fn main() { + let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); + //~^ ERROR temporary value dropped while borrowed + + bar(x); + + let foo = format_args!("{}", "hi"); + //~^ ERROR temporary value dropped while borrowed + bar(foo); + + let foo = format_args!("hi"); // no placeholder in arguments, so no error + bar(foo); +} diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr new file mode 100644 index 00000000000..8221505b100 --- /dev/null +++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr @@ -0,0 +1,33 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13 + | +LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | bar(x); + | - borrow later used here + | + = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used + = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html> + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15 + | +LL | let foo = format_args!("{}", "hi"); + | ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | bar(foo); + | --- borrow later used here + | + = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used + = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html> + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed new file mode 100644 index 00000000000..4653fe7375d --- /dev/null +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +pub trait Layer { + fn process(&mut self) -> u32; +} + +pub struct State { + layers: Vec<Box<dyn Layer>>, +} + +impl State { + pub fn process(&mut self) -> u32 { + self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process()) + //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs new file mode 100644 index 00000000000..e0f6ab1321f --- /dev/null +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.rs @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +pub trait Layer { + fn process(&mut self) -> u32; +} + +pub struct State { + layers: Vec<Box<dyn Layer>>, +} + +impl State { + pub fn process(&mut self) -> u32 { + self.layers.iter().fold(0, |result, mut layer| result + layer.process()) + //~^ ERROR cannot borrow `**layer` as mutable, as it is behind a `&` reference + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr new file mode 100644 index 00000000000..7e0fc2cf298 --- /dev/null +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr @@ -0,0 +1,16 @@ +error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` reference + --> $DIR/issue-115259-suggest-iter-mut.rs:15:65 + | +LL | self.layers.iter().fold(0, |result, mut layer| result + layer.process()) + | --------- ^^^^^ `layer` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut Box<dyn Layer>` + | +help: you may want to use `iter_mut` here + | +LL | self.layers.iter_mut().fold(0, |result, mut layer| result + layer.process()) + | ~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed new file mode 100644 index 00000000000..f02374d8e11 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.fixed @@ -0,0 +1,36 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] +use std::path::PathBuf; + +#[derive(Clone)] +struct Container { + things: Vec<PathBuf>, +} + +impl Container { + fn things(&mut self) -> &[PathBuf] { + &self.things + } +} + +// contains containers +struct ContainerContainer { + contained: Vec<Container>, +} + +impl ContainerContainer { + fn contained(&self) -> &[Container] { + &self.contained + } + + fn all_the_things(&mut self) -> &[PathBuf] { + let mut vec = self.contained.clone(); + let _a = + vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>(); + //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs new file mode 100644 index 00000000000..2d0b837a946 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.rs @@ -0,0 +1,36 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] +use std::path::PathBuf; + +#[derive(Clone)] +struct Container { + things: Vec<PathBuf>, +} + +impl Container { + fn things(&mut self) -> &[PathBuf] { + &self.things + } +} + +// contains containers +struct ContainerContainer { + contained: Vec<Container>, +} + +impl ContainerContainer { + fn contained(&self) -> &[Container] { + &self.contained + } + + fn all_the_things(&mut self) -> &[PathBuf] { + let mut vec = self.contained.clone(); + let _a = + vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>(); + //~^ ERROR cannot borrow `*container` as mutable, as it is behind a `&` reference + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr new file mode 100644 index 00000000000..19f194100a1 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr @@ -0,0 +1,16 @@ +error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` reference + --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45 + | +LL | vec.iter().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>(); + | --------- ^^^^^^^^^ `container` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut Container` + | +help: you may want to use `iter_mut` here + | +LL | vec.iter_mut().flat_map(|container| container.things()).cloned().collect::<Vec<PathBuf>>(); + | ~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed new file mode 100644 index 00000000000..8bf2625de6d --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.fixed @@ -0,0 +1,30 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +#[derive(Debug)] +struct A { + a: i32, +} + +impl A { + fn double(&mut self) { + self.a += self.a + } +} + +fn baz() { + let mut v = [A { a: 4 }]; + v.iter_mut().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn bar() { + let mut v = [A { a: 4 }]; + v.iter_mut().rev().rev().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs new file mode 100644 index 00000000000..39bc30bf294 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.rs @@ -0,0 +1,30 @@ +// run-rustfix +#![allow(unused_mut)] +#![allow(dead_code)] + +#[derive(Debug)] +struct A { + a: i32, +} + +impl A { + fn double(&mut self) { + self.a += self.a + } +} + +fn baz() { + let mut v = [A { a: 4 }]; + v.iter().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn bar() { + let mut v = [A { a: 4 }]; + v.iter().rev().rev().for_each(|a| a.double()); + //~^ ERROR cannot borrow `*a` as mutable, as it is behind a `&` reference + println!("{:?}", v); +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr new file mode 100644 index 00000000000..fd58e433020 --- /dev/null +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr @@ -0,0 +1,29 @@ +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference + --> $DIR/issue-62387-suggest-iter-mut.rs:18:27 + | +LL | v.iter().for_each(|a| a.double()); + | - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut A` + | +help: you may want to use `iter_mut` here + | +LL | v.iter_mut().for_each(|a| a.double()); + | ~~~~~~~~ + +error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference + --> $DIR/issue-62387-suggest-iter-mut.rs:25:39 + | +LL | v.iter().rev().rev().for_each(|a| a.double()); + | - ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut A` + | +help: you may want to use `iter_mut` here + | +LL | v.iter_mut().rev().rev().for_each(|a| a.double()); + | ~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr index 3a5fad15421..0807f459029 100644 --- a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr @@ -45,7 +45,8 @@ note: `E2` defined here | LL | pub enum E2 { A, B } | ^^^^^^^^^^^ - = note: the matched value is of type `E2`, which is marked as non-exhaustive + = note: the matched value is of type `E2` + = note: `E2` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } }; diff --git a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs new file mode 100644 index 00000000000..0bf2f0e6669 --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] + +struct Bug([u8; panic!{"\t"}]); +//~^ ERROR evaluation of constant value failed +//~| NOTE: in this expansion of panic! diff --git a/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr new file mode 100644 index 00000000000..82c63dd176d --- /dev/null +++ b/tests/ui/consts/const-eval/const_panic-normalize-tabs-115498.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic-normalize-tabs-115498.rs:3:17 + | +LL | struct Bug([u8; panic!{"\t"}]); + | ^^^^^^^^^^^^ the evaluated program panicked at ' ', $DIR/const_panic-normalize-tabs-115498.rs:3:17 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-uninhabit.rs b/tests/ui/consts/const-eval/ub-uninhabit.rs index 10edae437ee..01600f545ae 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.rs +++ b/tests/ui/consts/const-eval/ub-uninhabit.rs @@ -1,7 +1,10 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" // normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +#![feature(core_intrinsics)] +#![feature(never_type)] +use std::intrinsics; use std::mem; #[derive(Copy, Clone)] @@ -15,11 +18,24 @@ union MaybeUninit<T: Copy> { const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR evaluation of constant value failed +//~| constructing invalid value const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; //~^ ERROR it is undefined behavior to use this value +//~| constructing invalid value const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR evaluation of constant value failed +//~| constructing invalid value + + +const READ_NEVER: () = unsafe { + let mem = [0u32; 8]; + let ptr = mem.as_ptr().cast::<!>(); + let _val = intrinsics::read_via_copy(ptr); + //~^ ERROR evaluation of constant value failed + //~| constructing invalid value +}; + fn main() {} diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index f1ad0f04d3d..d26f4e03666 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/ub-uninhabit.rs:16:35 + --> $DIR/ub-uninhabit.rs:19:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type `Bar` error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:19:1 + --> $DIR/ub-uninhabit.rs:23:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -16,11 +16,17 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: evaluation of constant value failed - --> $DIR/ub-uninhabit.rs:22:42 + --> $DIR/ub-uninhabit.rs:27:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type `Bar` -error: aborting due to 3 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/ub-uninhabit.rs:35:16 + | +LL | let _val = intrinsics::read_via_copy(ptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/drop-maybe_uninit.rs b/tests/ui/consts/drop-maybe_uninit.rs new file mode 100644 index 00000000000..2fdeae5f185 --- /dev/null +++ b/tests/ui/consts/drop-maybe_uninit.rs @@ -0,0 +1,17 @@ +// build-pass + +pub const fn f<T, const N: usize>(_: [std::mem::MaybeUninit<T>; N]) {} + +pub struct Blubb<T>(*const T); + +pub const fn g<T, const N: usize>(_: [Blubb<T>; N]) {} + +pub struct Blorb<const N: usize>([String; N]); + +pub const fn h(_: Blorb<0>) {} + +pub struct Wrap(Blorb<0>); + +pub const fn i(_: Wrap) {} + +fn main() {} diff --git a/tests/ui/derive-uninhabited-enum-38885.stderr b/tests/ui/derive-uninhabited-enum-38885.stderr index dcdf8f8430f..3fabf446dc3 100644 --- a/tests/ui/derive-uninhabited-enum-38885.stderr +++ b/tests/ui/derive-uninhabited-enum-38885.stderr @@ -9,6 +9,7 @@ LL | Void(Void), | = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis = note: `-W dead-code` implied by `-W unused` + = help: to override `-W unused` add `#[allow(dead_code)]` warning: 1 warning emitted diff --git a/tests/ui/drop-bounds/drop-bounds-impl-drop.rs b/tests/ui/drop-bounds/drop-bounds-impl-drop.rs index 063efc7b31a..15aebdf1bc9 100644 --- a/tests/ui/drop-bounds/drop-bounds-impl-drop.rs +++ b/tests/ui/drop-bounds/drop-bounds-impl-drop.rs @@ -2,13 +2,13 @@ #![deny(drop_bounds)] // As a special exemption, `impl Drop` in the return position raises no error. // This allows a convenient way to return an unnamed drop guard. -fn voldemort_type() -> impl Drop { - struct Voldemort; - impl Drop for Voldemort { +fn unnameable_type() -> impl Drop { + struct Unnameable; + impl Drop for Unnameable { fn drop(&mut self) {} } - Voldemort + Unnameable } fn main() { - let _ = voldemort_type(); + let _ = unnameable_type(); } diff --git a/tests/ui/error-codes/E0220.stderr b/tests/ui/error-codes/E0220.stderr index 11763ce788d..e03eadacae4 100644 --- a/tests/ui/error-codes/E0220.stderr +++ b/tests/ui/error-codes/E0220.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `F` not found for `Trait` --> $DIR/E0220.rs:5:22 | LL | type Foo = dyn Trait<F=i32>; - | ^ associated type `F` not found + | ^ help: `Trait` has the following associated type: `Bar` error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must be specified --> $DIR/E0220.rs:5:16 diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs index 8fadce526d9..77d28838a10 100644 --- a/tests/ui/error-codes/E0602.rs +++ b/tests/ui/error-codes/E0602.rs @@ -1,6 +1,8 @@ // compile-flags:-D bogus +// check-pass // error-pattern:E0602 // error-pattern:requested on the command line with `-D bogus` +// error-pattern:`#[warn(unknown_lints)]` on by default fn main() {} diff --git a/tests/ui/error-codes/E0602.stderr b/tests/ui/error-codes/E0602.stderr index 2b372263345..60ecec7cdd7 100644 --- a/tests/ui/error-codes/E0602.stderr +++ b/tests/ui/error-codes/E0602.stderr @@ -1,11 +1,16 @@ -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` + = note: `#[warn(unknown_lints)]` on by default -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` -error: aborting due to 2 previous errors +warning[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +warning: 3 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/feature-gates/print-with-path.cfg.stderr b/tests/ui/feature-gates/print-with-path.cfg.stderr deleted file mode 100644 index a6c51baa320..00000000000 --- a/tests/ui/feature-gates/print-with-path.cfg.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/feature-gates/print-with-path.rs b/tests/ui/feature-gates/print-with-path.rs deleted file mode 100644 index f929c14c218..00000000000 --- a/tests/ui/feature-gates/print-with-path.rs +++ /dev/null @@ -1,7 +0,0 @@ -// check-fail -// revisions: cfg target-features target-cpus -// [cfg]compile-flags: --print cfg=cfg.txt -// [target-cpus]compile-flags: --print target-cpu=target_cpu.txt -// [target-features]compile-flags: --print target-features=target_features.txt - -fn main() {} diff --git a/tests/ui/feature-gates/print-with-path.target-cpus.stderr b/tests/ui/feature-gates/print-with-path.target-cpus.stderr deleted file mode 100644 index a6c51baa320..00000000000 --- a/tests/ui/feature-gates/print-with-path.target-cpus.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/feature-gates/print-with-path.target-features.stderr b/tests/ui/feature-gates/print-with-path.target-features.stderr deleted file mode 100644 index a6c51baa320..00000000000 --- a/tests/ui/feature-gates/print-with-path.target-features.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Z unstable-options` flag must also be passed to enable the path print option - diff --git a/tests/ui/fn/keyword-order.stderr b/tests/ui/fn/keyword-order.stderr index d3b140c8528..97d8f91b1ee 100644 --- a/tests/ui/fn/keyword-order.stderr +++ b/tests/ui/fn/keyword-order.stderr @@ -11,6 +11,8 @@ error: expected item, found keyword `pub` | LL | default pub const async unsafe extern fn err() {} | ^^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index cfc2193f633..6e99402113a 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -1,4 +1,4 @@ -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] use std::ops::Deref; @@ -8,6 +8,7 @@ pub trait Foo { pub struct Foreign; impl Foo for Foreign { + #[expect(refining_impl_trait)] fn bar(self) -> &'static () { &() } diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs index ff7ad4bf389..fbbbb8585d1 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs @@ -2,7 +2,7 @@ #![feature(return_position_impl_trait_in_trait)] -trait Iterable { +pub trait Iterable { type Item<'a> where Self: 'a; @@ -17,6 +17,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR impl has stricter requirements than trait fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> { + //~^ WARN impl trait in impl method signature does not match trait method signature (*self).iter() } } diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr index 106b8a7c804..a5fb338ea4e 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr @@ -12,6 +12,22 @@ help: copy the `where` clause predicates from the trait LL | where Self: 'b; | ~~~~~~~~~~~~~~ -error: aborting due to previous error +warning: impl trait in impl method signature does not match trait method signature + --> $DIR/bad-item-bound-within-rpitit.rs:19:28 + | +LL | fn iter(&self) -> impl '_ + Iterator<Item = Self::Item<'_>>; + | ----------------------------------------- return type from trait method defined here +... +LL | fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> { + | ^^ this bound is stronger than that defined on the trait + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: `#[warn(refining_impl_trait)]` on by default +help: replace the return type so that it matches the trait + | +LL | fn iter(&self) -> impl Iterator<Item = <Self as Iterable>::Item<'_>> + '_ { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs index 78cff97c616..fc290f11f9d 100644 --- a/tests/ui/impl-trait/in-trait/deep-match-works.rs +++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs @@ -1,15 +1,16 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] -struct Wrapper<T>(T); +pub struct Wrapper<T>(T); -trait Foo { +pub trait Foo { fn bar() -> Wrapper<impl Sized>; } impl Foo for () { + #[expect(refining_impl_trait)] fn bar() -> Wrapper<i32> { Wrapper(0) } diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs index b0c93a02935..6285d7786d5 100644 --- a/tests/ui/impl-trait/in-trait/foreign.rs +++ b/tests/ui/impl-trait/in-trait/foreign.rs @@ -1,14 +1,25 @@ // check-pass // aux-build: rpitit.rs +#![feature(lint_reasons)] + extern crate rpitit; use rpitit::{Foo, Foreign}; use std::sync::Arc; // Implement an RPITIT from another crate. -struct Local; +pub struct Local; impl Foo for Local { + #[expect(refining_impl_trait)] + fn bar(self) -> Arc<String> { + Arc::new(String::new()) + } +} + +struct LocalIgnoreRefining; +impl Foo for LocalIgnoreRefining { + #[deny(refining_impl_trait)] fn bar(self) -> Arc<String> { Arc::new(String::new()) } @@ -23,4 +34,5 @@ fn main() { let &() = Foreign.bar(); let x: Arc<String> = Local.bar(); + let x: Arc<String> = LocalIgnoreRefining.bar(); } diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr index 5d55b9fa4f9..18bb63745d7 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -6,7 +6,11 @@ LL | MyTrait::foo(&self) | | | required by a bound introduced by this call | - = help: the trait `MyTrait` is implemented for `Outer` +help: consider removing the leading `&`-reference + | +LL - MyTrait::foo(&self) +LL + MyTrait::foo(self) + | error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied --> $DIR/issue-102140.rs:23:9 diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs index 61c91e64417..ccb53031c44 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.rs +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -8,14 +8,6 @@ trait Foo { fn bar(self) -> impl Deref<Target = impl Display + ?Sized>; } -struct A; - -impl Foo for A { - fn bar(self) -> &'static str { - "Hello, world" - } -} - fn foo<T: Foo>(t: T) { let () = t.bar(); //~^ ERROR mismatched types diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr index 87219941d91..594b9ae9cd6 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102571.rs:20:9 + --> $DIR/issue-102571.rs:12:9 | LL | let () = t.bar(); | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs index 65285e3a3cc..58ba1acaf14 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs @@ -1,26 +1,28 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] use std::fmt::Display; use std::ops::Deref; -trait Foo { +pub trait Foo { fn bar(self) -> impl Deref<Target = impl Display + ?Sized>; } -struct A; +pub struct A; impl Foo for A { + #[expect(refining_impl_trait)] fn bar(self) -> &'static str { "Hello, world" } } -struct B; +pub struct B; impl Foo for B { + #[expect(refining_impl_trait)] fn bar(self) -> Box<i32> { Box::new(42) } diff --git a/tests/ui/impl-trait/in-trait/object-safety-sized.rs b/tests/ui/impl-trait/in-trait/object-safety-sized.rs new file mode 100644 index 00000000000..f221cfbb176 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/object-safety-sized.rs @@ -0,0 +1,23 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(return_position_impl_trait_in_trait)] + +fn main() { + let vec: Vec<Box<dyn Trait>> = Vec::new(); + + for i in vec { + i.fn_2(); + } +} + +trait OtherTrait {} + +trait Trait { + fn fn_1(&self) -> impl OtherTrait + where + Self: Sized; + + fn fn_2(&self) -> bool; +} diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index 9a231e59b09..d1c9fba4e99 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -8,7 +8,7 @@ trait Foo { } impl Foo for u32 { - fn baz(&self) -> u32 { + fn baz(&self) -> impl Debug { 32 } } diff --git a/tests/ui/impl-trait/in-trait/refine.rs b/tests/ui/impl-trait/in-trait/refine.rs new file mode 100644 index 00000000000..a91f9b3e722 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine.rs @@ -0,0 +1,48 @@ +#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] +#![deny(refining_impl_trait)] + +pub trait Foo { + fn bar() -> impl Sized; +} + +pub struct A; +impl Foo for A { + fn bar() -> impl Copy {} + //~^ ERROR impl method signature does not match trait method signature +} + +pub struct B; +impl Foo for B { + fn bar() {} + //~^ ERROR impl method signature does not match trait method signature +} + +pub struct C; +impl Foo for C { + fn bar() -> () {} + //~^ ERROR impl method signature does not match trait method signature +} + +struct Private; +impl Foo for Private { + fn bar() -> () {} +} + +pub trait Arg<A> { + fn bar() -> impl Sized; +} +impl Arg<Private> for A { + fn bar() -> () {} +} + +pub trait Late { + fn bar<'a>(&'a self) -> impl Sized + 'a; +} + +pub struct D; +impl Late for D { + fn bar(&self) -> impl Copy + '_ {} + //~^ ERROR impl method signature does not match trait method signature +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine.stderr b/tests/ui/impl-trait/in-trait/refine.stderr new file mode 100644 index 00000000000..29aa08e25bb --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine.stderr @@ -0,0 +1,67 @@ +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:10:22 + | +LL | fn bar() -> impl Sized; + | ---------- return type from trait method defined here +... +LL | fn bar() -> impl Copy {} + | ^^^^ this bound is stronger than that defined on the trait + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate +note: the lint level is defined here + --> $DIR/refine.rs:2:9 + | +LL | #![deny(refining_impl_trait)] + | ^^^^^^^^^^^^^^^^^^^ +help: replace the return type so that it matches the trait + | +LL | fn bar() -> impl Sized {} + | ~~~~~~~~~~ + +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:16:5 + | +LL | fn bar() -> impl Sized; + | ---------- return type from trait method defined here +... +LL | fn bar() {} + | ^^^^^^^^ + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate +help: replace the return type so that it matches the trait + | +LL | fn bar() -> impl Sized {} + | +++++++++++++ + +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:22:17 + | +LL | fn bar() -> impl Sized; + | ---------- return type from trait method defined here +... +LL | fn bar() -> () {} + | ^^ + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate +help: replace the return type so that it matches the trait + | +LL | fn bar() -> impl Sized {} + | ~~~~~~~~~~ + +error: impl trait in impl method signature does not match trait method signature + --> $DIR/refine.rs:44:27 + | +LL | fn bar<'a>(&'a self) -> impl Sized + 'a; + | --------------- return type from trait method defined here +... +LL | fn bar(&self) -> impl Copy + '_ {} + | ^^^^ this bound is stronger than that defined on the trait + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate +help: replace the return type so that it matches the trait + | +LL | fn bar(&self) -> impl Sized + '_ {} + | ~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs index d6ede1cc495..b1b46d75b8f 100644 --- a/tests/ui/impl-trait/in-trait/reveal.rs +++ b/tests/ui/impl-trait/in-trait/reveal.rs @@ -1,13 +1,14 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] -trait Foo { +pub trait Foo { fn f() -> Box<impl Sized>; } impl Foo for () { + #[expect(refining_impl_trait)] fn f() -> Box<String> { Box::new(String::new()) } diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs index 7682884f879..44a2b430344 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs @@ -1,6 +1,6 @@ // issue: 113903 -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] use std::ops::Deref; @@ -10,6 +10,7 @@ pub trait Tr { } impl Tr for () { + #[expect(refining_impl_trait)] fn w() -> &'static () { &() } diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr index 186580f5756..468cf12f1bc 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr @@ -1,5 +1,5 @@ error[E0623]: lifetime mismatch - --> $DIR/signature-mismatch.rs:77:10 + --> $DIR/signature-mismatch.rs:79:10 | LL | &'a self, | -------- this parameter and the return type are declared with different lifetimes... diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs index c84a3b8f46b..685c0f06e88 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -2,18 +2,17 @@ // revisions: success failure //[success] check-pass -#![feature(return_position_impl_trait_in_trait)] -#![allow(incomplete_features)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] use std::future::Future; -trait Captures<'a> {} +pub trait Captures<'a> {} impl<T> Captures<'_> for T {} -trait Captures2<'a, 'b> {} +pub trait Captures2<'a, 'b> {} impl<T> Captures2<'_, '_> for T {} -trait AsyncTrait { +pub trait AsyncTrait { #[cfg(success)] fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>; @@ -45,6 +44,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] + #[expect(refining_impl_trait)] fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a { async move { buff.to_vec() } } @@ -52,6 +52,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] + #[expect(refining_impl_trait)] fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a { async move { buff.to_vec() } } @@ -59,6 +60,7 @@ impl AsyncTrait for Struct { // Does not capture more lifetimes that trait def'n, since trait def'n // implicitly captures all in-scope lifetimes. #[cfg(success)] + #[expect(refining_impl_trait)] fn async_fn_multiple<'a, 'b>( &'a self, buff: &'b [u8], diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs index c9ee877db8e..41fc285883a 100644 --- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs +++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs @@ -1,10 +1,10 @@ // check-pass #![feature(specialization)] -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] -trait Foo { +pub trait Foo { fn bar(&self) -> impl Sized; } @@ -12,6 +12,7 @@ impl<U> Foo for U where U: Copy, { + #[expect(refining_impl_trait)] fn bar(&self) -> U { *self } diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs index 4cbe682b46f..7d415ea17a4 100644 --- a/tests/ui/impl-trait/in-trait/success.rs +++ b/tests/ui/impl-trait/in-trait/success.rs @@ -1,29 +1,32 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] +#![feature(return_position_impl_trait_in_trait, lint_reasons)] #![allow(incomplete_features)] use std::fmt::Display; -trait Foo { +pub trait Foo { fn bar(&self) -> impl Display; } impl Foo for i32 { + #[expect(refining_impl_trait)] fn bar(&self) -> i32 { *self } } impl Foo for &'static str { + #[expect(refining_impl_trait)] fn bar(&self) -> &'static str { *self } } -struct Yay; +pub struct Yay; impl Foo for Yay { + #[expect(refining_impl_trait)] fn bar(&self) -> String { String::from(":^)") } diff --git a/tests/ui/implied-bounds/implied-bounds-unconstrained-1.rs b/tests/ui/implied-bounds/implied-bounds-unconstrained-1.rs new file mode 100644 index 00000000000..025e5176ff7 --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-unconstrained-1.rs @@ -0,0 +1,28 @@ +// check-pass + +// Regression test for #112832. +pub trait QueryDb { + type Db; +} + +pub struct QueryTable<Q, DB> { + db: DB, + storage: Q, +} + +// We normalize `<Q as QueryDb>::Db` to `<Q as AsyncQueryFunction<'d>>::SendDb` +// using the where-bound. 'd is an unconstrained region variable which previously +// triggered an assert. +impl<Q> QueryTable<Q, <Q as QueryDb>::Db> where Q: for<'d> AsyncQueryFunction<'d> {} + +pub trait AsyncQueryFunction<'d>: QueryDb<Db = <Self as AsyncQueryFunction<'d>>::SendDb> { + type SendDb: 'd; +} + +pub trait QueryStorageOpsAsync<Q> +where + Q: for<'d> AsyncQueryFunction<'d>, +{ +} + +fn main() {} diff --git a/tests/ui/implied-bounds/implied-bounds-unconstrained-2.rs b/tests/ui/implied-bounds/implied-bounds-unconstrained-2.rs new file mode 100644 index 00000000000..976054facee --- /dev/null +++ b/tests/ui/implied-bounds/implied-bounds-unconstrained-2.rs @@ -0,0 +1,20 @@ +// check-pass + +// Another minimized regression test for #112832. +trait Trait { + type Assoc; +} + +trait Sub<'a>: Trait<Assoc = <Self as Sub<'a>>::SubAssoc> { + type SubAssoc; +} + +// By using the where-clause we normalize `<T as Trait>::Assoc` to +// `<T as Sub<'a>>::SubAssoc` where `'a` is an unconstrained region +// variable. +fn foo<T>(x: <T as Trait>::Assoc) +where + for<'a> T: Sub<'a>, +{} + +fn main() {} diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs index b74a8d3b917..65f2f3b89af 100644 --- a/tests/ui/layout/debug.rs +++ b/tests/ui/layout/debug.rs @@ -17,6 +17,9 @@ type Test = Result<i32, i32>; //~ ERROR: layout_of #[rustc_layout(debug)] type T = impl std::fmt::Debug; //~ ERROR: layout_of +fn f() -> T { + 0i32 +} #[rustc_layout(debug)] pub union V { //~ ERROR: layout_of @@ -63,6 +66,13 @@ union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of #[rustc_layout(debug)] type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of -fn f() -> T { - 0i32 +#[rustc_layout(debug)] +const C: () = (); //~ ERROR: can only be applied to + +impl S { + #[rustc_layout(debug)] + const C: () = (); //~ ERROR: can only be applied to } + +#[rustc_layout(debug)] +type Impossible = (str, str); //~ ERROR: cannot be known at compilation time diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index c20a0198ccb..5162a771b4d 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -162,7 +162,7 @@ error: layout_of(U) = Layout { LL | union U { f1: (i32, i32), f3: i32 } | ^^^^^^^ -error: layout_of(std::result::Result<i32, i32>) = Layout { +error: layout_of(Result<i32, i32>) = Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), @@ -344,7 +344,7 @@ error: layout_of(V) = Layout { max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } - --> $DIR/debug.rs:22:1 + --> $DIR/debug.rs:25:1 | LL | pub union V { | ^^^^^^^^^^^ @@ -368,7 +368,7 @@ error: layout_of(W) = Layout { max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } - --> $DIR/debug.rs:28:1 + --> $DIR/debug.rs:31:1 | LL | pub union W { | ^^^^^^^^^^^ @@ -392,7 +392,7 @@ error: layout_of(Y) = Layout { max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } - --> $DIR/debug.rs:34:1 + --> $DIR/debug.rs:37:1 | LL | pub union Y { | ^^^^^^^^^^^ @@ -416,7 +416,7 @@ error: layout_of(P1) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:41:1 + --> $DIR/debug.rs:44:1 | LL | union P1 { x: u32 } | ^^^^^^^^ @@ -440,7 +440,7 @@ error: layout_of(P2) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:45:1 + --> $DIR/debug.rs:48:1 | LL | union P2 { x: (u32, u32) } | ^^^^^^^^ @@ -464,7 +464,7 @@ error: layout_of(P3) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:53:1 + --> $DIR/debug.rs:56:1 | LL | union P3 { x: F32x4 } | ^^^^^^^^ @@ -488,7 +488,7 @@ error: layout_of(P4) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:57:1 + --> $DIR/debug.rs:60:1 | LL | union P4 { x: E } | ^^^^^^^^ @@ -517,12 +517,12 @@ error: layout_of(P5) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:61:1 + --> $DIR/debug.rs:64:1 | LL | union P5 { zst: [u16; 0], byte: u8 } | ^^^^^^^^ -error: layout_of(std::mem::MaybeUninit<u8>) = Layout { +error: layout_of(MaybeUninit<u8>) = Layout { size: Size(1 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), @@ -546,10 +546,32 @@ error: layout_of(std::mem::MaybeUninit<u8>) = Layout { max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } - --> $DIR/debug.rs:64:1 + --> $DIR/debug.rs:67:1 | LL | type X = std::mem::MaybeUninit<u8>; | ^^^^^^ -error: aborting due to 14 previous errors +error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases + --> $DIR/debug.rs:70:1 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/debug.rs:78:19 + | +LL | type Impossible = (str, str); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + +error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases + --> $DIR/debug.rs:74:5 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: aborting due to 17 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index df9f1cc8d10..8161f97dde0 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -1,4 +1,4 @@ -error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { +error: layout_of(Result<[u32; 0], bool>) = Layout { size: Size(4 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), @@ -232,7 +232,7 @@ error: layout_of(MultipleAlignments) = Layout { LL | enum MultipleAlignments { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) = Layout { +error: layout_of(Result<[u32; 0], Packed<NonZeroU16>>) = Layout { size: Size(4 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), @@ -337,7 +337,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) = LL | type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZeroU16>>; | ^^^^^^^^^^^^^^^^^^^^^^^ -error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout { +error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout { size: Size(4 bytes), align: AbiAndPrefAlign { abi: Align(4 bytes), diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index 5b93eff8614..6361d8ad30b 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -36,7 +36,7 @@ error[E0220]: associated type `B` not found for `Self` --> $DIR/issue-95023.rs:6:44 | LL | fn foo<const N: usize>(&self) -> Self::B<{N}>; - | ^ associated type `B` not found + | ^ help: `Self` has the following associated type: `Output` error: aborting due to 5 previous errors diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.rs b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs new file mode 100644 index 00000000000..ce8d9848e42 --- /dev/null +++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs @@ -0,0 +1,14 @@ +// build-fail +// failure-status: 101 +// known-bug: #109681 + +// This test verifies that we continue to hit the LLVM error for common linkage with non-zero +// initializers, since it generates invalid LLVM IR. +// Linkages are internal features marked as perma-unstable, so we don't need to fix the issue +// for now. +#![crate_type="lib"] +#![feature(linkage)] + +#[linkage = "common"] +#[no_mangle] +pub static TEST: bool = true; diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr new file mode 100644 index 00000000000..667bb3ec130 --- /dev/null +++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.stderr @@ -0,0 +1,3 @@ +'common' global must have a zero initializer! +ptr @TEST +LLVM ERROR: Broken module found, compilation aborted! diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.stderr b/tests/ui/lint-group-forbid-always-trumps-cli.stderr index 8910af87ca2..cd042179cce 100644 --- a/tests/ui/lint-group-forbid-always-trumps-cli.stderr +++ b/tests/ui/lint-group-forbid-always-trumps-cli.stderr @@ -5,6 +5,7 @@ LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` | = note: `-F unused-variables` implied by `-F unused` + = help: to override `-F unused` add `#[allow(unused_variables)]` error: aborting due to previous error diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs index f3dea87a6b6..a9e4e4a6017 100644 --- a/tests/ui/lint/cli-unknown-force-warn.rs +++ b/tests/ui/lint/cli-unknown-force-warn.rs @@ -1,7 +1,11 @@ // Checks that rustc correctly errors when passed an invalid lint with // `--force-warn`. This is a regression test for issue #86958. -// + +// check-pass // compile-flags: --force-warn foo-qux + // error-pattern: unknown lint: `foo_qux` +// error-pattern: requested on the command line with `--force-warn foo_qux` +// error-pattern: `#[warn(unknown_lints)]` on by default fn main() {} diff --git a/tests/ui/lint/cli-unknown-force-warn.stderr b/tests/ui/lint/cli-unknown-force-warn.stderr index 9ce9f405aee..2ee718a8c8e 100644 --- a/tests/ui/lint/cli-unknown-force-warn.stderr +++ b/tests/ui/lint/cli-unknown-force-warn.stderr @@ -1,11 +1,16 @@ -error[E0602]: unknown lint: `foo_qux` +warning[E0602]: unknown lint: `foo_qux` | = note: requested on the command line with `--force-warn foo_qux` + = note: `#[warn(unknown_lints)]` on by default -error[E0602]: unknown lint: `foo_qux` +warning[E0602]: unknown lint: `foo_qux` | = note: requested on the command line with `--force-warn foo_qux` -error: aborting due to 2 previous errors +warning[E0602]: unknown lint: `foo_qux` + | + = note: requested on the command line with `--force-warn foo_qux` + +warning: 3 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/command-line-lint-group-deny.stderr b/tests/ui/lint/command-line-lint-group-deny.stderr index 04c3f6f2637..59d8429ea69 100644 --- a/tests/ui/lint/command-line-lint-group-deny.stderr +++ b/tests/ui/lint/command-line-lint-group-deny.stderr @@ -5,6 +5,7 @@ LL | let _InappropriateCamelCasing = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `_inappropriate_camel_casing` | = note: `-D non-snake-case` implied by `-D bad-style` + = help: to override `-D bad-style` add `#[allow(non_snake_case)]` error: aborting due to previous error diff --git a/tests/ui/lint/command-line-lint-group-forbid.stderr b/tests/ui/lint/command-line-lint-group-forbid.stderr index 73678214063..486d32a9f08 100644 --- a/tests/ui/lint/command-line-lint-group-forbid.stderr +++ b/tests/ui/lint/command-line-lint-group-forbid.stderr @@ -5,6 +5,7 @@ LL | let _InappropriateCamelCasing = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `_inappropriate_camel_casing` | = note: `-F non-snake-case` implied by `-F bad-style` + = help: to override `-F bad-style` add `#[allow(non_snake_case)]` error: aborting due to previous error diff --git a/tests/ui/lint/command-line-lint-group-warn.stderr b/tests/ui/lint/command-line-lint-group-warn.stderr index e9c80b4ef21..cfe346a5bf6 100644 --- a/tests/ui/lint/command-line-lint-group-warn.stderr +++ b/tests/ui/lint/command-line-lint-group-warn.stderr @@ -5,6 +5,7 @@ LL | let _InappropriateCamelCasing = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `_inappropriate_camel_casing` | = note: `-W non-snake-case` implied by `-W bad-style` + = help: to override `-W bad-style` add `#[allow(non_snake_case)]` warning: 1 warning emitted diff --git a/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr index d1b764b3414..01c2ed84c63 100644 --- a/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr @@ -7,6 +7,7 @@ LL | 0...100 => true, = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> = note: `--force-warn ellipsis-inclusive-range-patterns` implied by `--force-warn rust-2021-compatibility` + = help: to override `--force-warn rust-2021-compatibility` add `#[allow(ellipsis_inclusive_range_patterns)]` warning: 1 warning emitted diff --git a/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr b/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr index dc7b1b7b98d..e925a195fb1 100644 --- a/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr +++ b/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr @@ -5,6 +5,7 @@ LL | pub fn FUNCTION() {} | ^^^^^^^^ help: convert the identifier to snake case: `function` | = note: `--force-warn non-snake-case` implied by `--force-warn nonstandard-style` + = help: to override `--force-warn nonstandard-style` add `#[allow(non_snake_case)]` warning: 1 warning emitted diff --git a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr index e17630fd358..b0cd3ddd26f 100644 --- a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr @@ -7,6 +7,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms` + = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]` help: use `dyn` | LL | pub fn function(_x: Box<dyn SomeTrait>) {} diff --git a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr index 72198541a70..8c841916c93 100644 --- a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr +++ b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr @@ -7,6 +7,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms` + = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]` help: use `dyn` | LL | pub fn function(_x: Box<dyn SomeTrait>) {} diff --git a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr index 52c870ac28a..c0144205d6a 100644 --- a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr @@ -7,6 +7,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms` + = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]` help: use `dyn` | LL | pub fn function(_x: Box<dyn SomeTrait>) {} diff --git a/tests/ui/lint/future-incompat-test.stderr b/tests/ui/lint/future-incompat-test.stderr index 52674a84384..2951f904fb5 100644 --- a/tests/ui/lint/future-incompat-test.stderr +++ b/tests/ui/lint/future-incompat-test.stderr @@ -6,4 +6,5 @@ LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` | = note: `-A unused-variables` implied by `-A unused` + = help: to override `-A unused` add `#[allow(unused_variables)]` diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs index 70dd2a71f26..ac24f61b0ac 100644 --- a/tests/ui/lint/lint-ctypes-94223.rs +++ b/tests/ui/lint/lint-ctypes-94223.rs @@ -24,6 +24,13 @@ enum BadUnion { type Foo = extern "C" fn([u8]); //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +pub trait FooTrait { + type FooType; +} + +pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>); +//~^ ERROR `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe + pub struct FfiUnsafe; #[allow(improper_ctypes_definitions)] diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr index 49e64ed5140..bd127cf6004 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -66,8 +66,17 @@ LL | type Foo = extern "C" fn([u8]); = help: consider using a raw pointer instead = note: slices have no C equivalent +error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:31:20 + | +LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe - --> $DIR/lint-ctypes-94223.rs:34:17 + --> $DIR/lint-ctypes-94223.rs:41:17 | LL | pub static BAD: extern "C" fn(FfiUnsafe) = f; | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -75,13 +84,13 @@ LL | pub static BAD: extern "C" fn(FfiUnsafe) = f; = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes-94223.rs:27:1 + --> $DIR/lint-ctypes-94223.rs:34:1 | LL | pub struct FfiUnsafe; | ^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe - --> $DIR/lint-ctypes-94223.rs:37:30 + --> $DIR/lint-ctypes-94223.rs:44:30 | LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -89,13 +98,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes-94223.rs:27:1 + --> $DIR/lint-ctypes-94223.rs:34:1 | LL | pub struct FfiUnsafe; | ^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe - --> $DIR/lint-ctypes-94223.rs:37:56 + --> $DIR/lint-ctypes-94223.rs:44:56 | LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -103,13 +112,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes-94223.rs:27:1 + --> $DIR/lint-ctypes-94223.rs:34:1 | LL | pub struct FfiUnsafe; | ^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe - --> $DIR/lint-ctypes-94223.rs:41:22 + --> $DIR/lint-ctypes-94223.rs:48:22 | LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -117,10 +126,10 @@ LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes-94223.rs:27:1 + --> $DIR/lint-ctypes-94223.rs:34:1 | LL | pub struct FfiUnsafe; | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/lint/lint-pre-expansion-extern-module.stderr b/tests/ui/lint/lint-pre-expansion-extern-module.stderr index ce3e8806a9e..8a6e1531d5f 100644 --- a/tests/ui/lint/lint-pre-expansion-extern-module.stderr +++ b/tests/ui/lint/lint-pre-expansion-extern-module.stderr @@ -7,6 +7,7 @@ LL | pub fn try() {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> = note: `-W keyword-idents` implied by `-W rust-2018-compatibility` + = help: to override `-W rust-2018-compatibility` add `#[allow(keyword_idents)]` warning: 1 warning emitted diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs new file mode 100644 index 00000000000..8cf91cf60eb --- /dev/null +++ b/tests/ui/lint/lint-removed-cmdline-deny.rs @@ -0,0 +1,13 @@ +// The raw_pointer_derived lint warns about its removal +// cc #30346 + +// compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive + +// error-pattern:lint `raw_pointer_derive` has been removed +// error-pattern:requested on the command line with `-D raw_pointer_derive` +// error-pattern:requested on the command line with `-D renamed-and-removed-lints` + +#![warn(unused)] + +#[deny(warnings)] +fn main() { let unused = (); } diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr new file mode 100644 index 00000000000..80c85d01e53 --- /dev/null +++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr @@ -0,0 +1,28 @@ +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: requested on the command line with `-D renamed-and-removed-lints` + +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + +error: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + +error: unused variable: `unused` + --> $DIR/lint-removed-cmdline-deny.rs:13:17 + | +LL | fn main() { let unused = (); } + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` + | +note: the lint level is defined here + --> $DIR/lint-removed-cmdline-deny.rs:12:8 + | +LL | #[deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs index 462beabb945..34373df3a9c 100644 --- a/tests/ui/lint/lint-removed-cmdline.rs +++ b/tests/ui/lint/lint-removed-cmdline.rs @@ -4,6 +4,7 @@ // compile-flags:-D raw_pointer_derive // error-pattern:lint `raw_pointer_derive` has been removed +// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default // error-pattern:requested on the command line with `-D raw_pointer_derive` #![warn(unused)] diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr index 9be532ef234..ebfae34ade9 100644 --- a/tests/ui/lint/lint-removed-cmdline.stderr +++ b/tests/ui/lint/lint-removed-cmdline.stderr @@ -1,6 +1,7 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | = note: requested on the command line with `-D raw_pointer_derive` + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok | @@ -11,13 +12,13 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point = note: requested on the command line with `-D raw_pointer_derive` error: unused variable: `unused` - --> $DIR/lint-removed-cmdline.rs:12:17 + --> $DIR/lint-removed-cmdline.rs:13:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-removed-cmdline.rs:11:8 + --> $DIR/lint-removed-cmdline.rs:12:8 | LL | #[deny(warnings)] | ^^^^^^^^ diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs new file mode 100644 index 00000000000..01629aaca80 --- /dev/null +++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs @@ -0,0 +1,10 @@ +// compile-flags:-D renamed-and-removed-lints -D bare_trait_object + +// error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects` +// error-pattern:use the new name `bare_trait_objects` +// error-pattern:requested on the command line with `-D bare_trait_object` +// error-pattern:requested on the command line with `-D renamed-and-removed-lints` +// error-pattern:unused + +#[deny(unused)] +fn main() { let unused = (); } diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr new file mode 100644 index 00000000000..df22ef60daf --- /dev/null +++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr @@ -0,0 +1,31 @@ +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = help: use the new name `bare_trait_objects` + = note: requested on the command line with `-D bare_trait_object` + = note: requested on the command line with `-D renamed-and-removed-lints` + +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = help: use the new name `bare_trait_objects` + = note: requested on the command line with `-D bare_trait_object` + +error: lint `bare_trait_object` has been renamed to `bare_trait_objects` + | + = help: use the new name `bare_trait_objects` + = note: requested on the command line with `-D bare_trait_object` + +error: unused variable: `unused` + --> $DIR/lint-renamed-cmdline-deny.rs:10:17 + | +LL | fn main() { let unused = (); } + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` + | +note: the lint level is defined here + --> $DIR/lint-renamed-cmdline-deny.rs:9:8 + | +LL | #[deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs index c873771e308..fba7c33311d 100644 --- a/tests/ui/lint/lint-renamed-cmdline.rs +++ b/tests/ui/lint/lint-renamed-cmdline.rs @@ -2,6 +2,7 @@ // error-pattern:lint `bare_trait_object` has been renamed to `bare_trait_objects` // error-pattern:requested on the command line with `-D bare_trait_object` +// error-pattern:`#[warn(renamed_and_removed_lints)]` on by default // error-pattern:unused #[deny(unused)] diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr index 8dfd61ac927..a41284003ed 100644 --- a/tests/ui/lint/lint-renamed-cmdline.stderr +++ b/tests/ui/lint/lint-renamed-cmdline.stderr @@ -1,23 +1,27 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | + = help: use the new name `bare_trait_objects` = note: requested on the command line with `-D bare_trait_object` error: unused variable: `unused` - --> $DIR/lint-renamed-cmdline.rs:8:17 + --> $DIR/lint-renamed-cmdline.rs:9:17 | LL | fn main() { let unused = (); } | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused` | note: the lint level is defined here - --> $DIR/lint-renamed-cmdline.rs:7:8 + --> $DIR/lint-renamed-cmdline.rs:8:8 | LL | #[deny(unused)] | ^^^^^^ diff --git a/tests/ui/lint/lint-unexported-no-mangle.stderr b/tests/ui/lint/lint-unexported-no-mangle.stderr index a11ee769c7c..85852782222 100644 --- a/tests/ui/lint/lint-unexported-no-mangle.stderr +++ b/tests/ui/lint/lint-unexported-no-mangle.stderr @@ -1,6 +1,7 @@ warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported | = note: requested on the command line with `-F private_no_mangle_fns` + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported | diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs new file mode 100644 index 00000000000..c7f8d434c04 --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs @@ -0,0 +1,4 @@ +// check-pass +// compile-flags:-A unknown-lints -D bogus -D dead_cod + +fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs new file mode 100644 index 00000000000..31bc2047356 --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs @@ -0,0 +1,9 @@ +// compile-flags:-D unknown-lints -D bogus -D dead_cod + +// error-pattern:unknown lint: `bogus` +// error-pattern:requested on the command line with `-D bogus` +// error-pattern:requested on the command line with `-D dead_cod` +// error-pattern:requested on the command line with `-D unknown-lints` +// error-pattern:did you mean: `dead_code` + +fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr new file mode 100644 index 00000000000..677b5edc894 --- /dev/null +++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr @@ -0,0 +1,31 @@ +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + = note: requested on the command line with `-D unknown-lints` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +error[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs index 7f3f55fbad0..81539cb6dc1 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.rs +++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs @@ -1,7 +1,9 @@ +// check-pass // compile-flags:-D bogus -D dead_cod // error-pattern:unknown lint: `bogus` // error-pattern:requested on the command line with `-D bogus` +// error-pattern:`#[warn(unknown_lints)]` on by default // error-pattern:unknown lint: `dead_cod` // error-pattern:requested on the command line with `-D dead_cod` // error-pattern:did you mean: `dead_code` diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.stderr b/tests/ui/lint/lint-unknown-lint-cmdline.stderr index 3855d552792..10db76ac4f1 100644 --- a/tests/ui/lint/lint-unknown-lint-cmdline.stderr +++ b/tests/ui/lint/lint-unknown-lint-cmdline.stderr @@ -1,21 +1,31 @@ -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` + = note: `#[warn(unknown_lints)]` on by default -error[E0602]: unknown lint: `dead_cod` +warning[E0602]: unknown lint: `dead_cod` | = help: did you mean: `dead_code` = note: requested on the command line with `-D dead_cod` -error[E0602]: unknown lint: `bogus` +warning[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` -error[E0602]: unknown lint: `dead_cod` +warning[E0602]: unknown lint: `dead_cod` | = help: did you mean: `dead_code` = note: requested on the command line with `-D dead_cod` -error: aborting due to 4 previous errors +warning[E0602]: unknown lint: `bogus` + | + = note: requested on the command line with `-D bogus` + +warning[E0602]: unknown lint: `dead_cod` + | + = help: did you mean: `dead_code` + = note: requested on the command line with `-D dead_cod` + +warning: 6 warnings emitted For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index 92d985948ec..7745d4ef4c3 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -36,6 +36,10 @@ unsafe fn ref_to_mut() { //~^ ERROR casting `&T` to `&mut T` is undefined behavior let _num = &mut *std::mem::transmute::<_, *mut i32>(num); //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let _num = &mut *std::cell::UnsafeCell::raw_get( + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + num as *const i32 as *const std::cell::UnsafeCell<i32> + ); let deferred = num as *const i32 as *mut i32; let _num = &mut *deferred; @@ -50,6 +54,16 @@ unsafe fn ref_to_mut() { &mut *((this as *const _) as *mut _) //~^ ERROR casting `&T` to `&mut T` is undefined behavior } + + fn as_mut<T>(x: &T) -> &mut T { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + } + + fn as_mut_i32(x: &i32) -> &mut i32 { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + } } unsafe fn assign_to_ref() { @@ -111,6 +125,20 @@ unsafe fn no_warn() { let mut value = 3; let value: *const i32 = &mut value; *(value as *const i16 as *mut i16) = 42; + + fn safe_as_mut<T>(x: &std::cell::UnsafeCell<T>) -> &mut T { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + } + + fn cell_as_mut(x: &std::cell::Cell<i32>) -> &mut i32 { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + } + + #[repr(transparent)] + struct DoesContainUnsafeCell(std::cell::UnsafeCell<i32>); + fn safe_as_mut2(x: &DoesContainUnsafeCell) -> &mut DoesContainUnsafeCell { + unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + } } fn main() {} diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr index 47b95460ec3..1189942c809 100644 --- a/tests/ui/lint/reference_casting.stderr +++ b/tests/ui/lint/reference_casting.stderr @@ -80,7 +80,19 @@ LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(num); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:41:16 + --> $DIR/reference_casting.rs:39:16 + | +LL | let _num = &mut *std::cell::UnsafeCell::raw_get( + | ________________^ +LL | | +LL | | num as *const i32 as *const std::cell::UnsafeCell<i32> +LL | | ); + | |_____^ + | + = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:45:16 | LL | let deferred = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -90,7 +102,7 @@ LL | let _num = &mut *deferred; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:44:16 + --> $DIR/reference_casting.rs:48:16 | LL | let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32; | ---------------------------------------------------------------------------- casting happend here @@ -100,7 +112,7 @@ LL | let _num = &mut *deferred; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:46:16 + --> $DIR/reference_casting.rs:50:16 | LL | let _num = &mut *(num as *const _ as usize as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,15 +120,31 @@ LL | let _num = &mut *(num as *const _ as usize as *mut i32); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:50:9 + --> $DIR/reference_casting.rs:54:9 | LL | &mut *((this as *const _) as *mut _) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:59:18 + | +LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:64:18 + | +LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> + error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:60:5 + --> $DIR/reference_casting.rs:74:5 | LL | *(a as *const _ as *mut _) = String::from("Replaced"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +152,7 @@ LL | *(a as *const _ as *mut _) = String::from("Replaced"); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:62:5 + --> $DIR/reference_casting.rs:76:5 | LL | *(a as *const _ as *mut String) += " world"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +160,7 @@ LL | *(a as *const _ as *mut String) += " world"; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:64:5 + --> $DIR/reference_casting.rs:78:5 | LL | *std::ptr::from_ref(num).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +168,7 @@ LL | *std::ptr::from_ref(num).cast_mut() += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:66:5 + --> $DIR/reference_casting.rs:80:5 | LL | *std::ptr::from_ref({ num }).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +176,7 @@ LL | *std::ptr::from_ref({ num }).cast_mut() += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:68:5 + --> $DIR/reference_casting.rs:82:5 | LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -156,7 +184,7 @@ LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:70:5 + --> $DIR/reference_casting.rs:84:5 | LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +192,7 @@ LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:72:5 + --> $DIR/reference_casting.rs:86:5 | LL | *std::mem::transmute::<_, *mut i32>(num) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +200,7 @@ LL | *std::mem::transmute::<_, *mut i32>(num) += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:74:5 + --> $DIR/reference_casting.rs:88:5 | LL | / std::ptr::write( LL | | @@ -184,7 +212,7 @@ LL | | ); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:81:5 + --> $DIR/reference_casting.rs:95:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -194,7 +222,7 @@ LL | *value = 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:83:5 + --> $DIR/reference_casting.rs:97:5 | LL | *(num as *const i32).cast::<i32>().cast_mut() = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -202,7 +230,7 @@ LL | *(num as *const i32).cast::<i32>().cast_mut() = 2; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:85:5 + --> $DIR/reference_casting.rs:99:5 | LL | *(num as *const _ as usize as *mut i32) = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +238,7 @@ LL | *(num as *const _ as usize as *mut i32) = 2; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:87:5 + --> $DIR/reference_casting.rs:101:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -221,7 +249,7 @@ LL | std::ptr::write(value, 2); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:89:5 + --> $DIR/reference_casting.rs:103:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -232,7 +260,7 @@ LL | std::ptr::write_unaligned(value, 2); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:91:5 + --> $DIR/reference_casting.rs:105:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -243,12 +271,12 @@ LL | std::ptr::write_volatile(value, 2); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:95:9 + --> $DIR/reference_casting.rs:109:9 | LL | *(this as *const _ as *mut _) = a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> -error: aborting due to 29 previous errors +error: aborting due to 32 previous errors diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs index 54d86c31fb4..ba32fb566e8 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs @@ -26,6 +26,32 @@ fn doc_comment_on_expr(num: u8) -> bool { num == 3 } +fn doc_comment_on_expr_field() -> bool { + struct S { foo: i32 } + + let x = S { + /// useless doc comment + //~^ ERROR: unused doc comment + foo: 3 + }; + + true +} + +fn doc_comment_on_pat_field() -> bool { + struct S { foo: i32 } + + let S { + /// useless doc comment + //~^ ERROR: unused doc comment + foo + } = S { + foo: 3 + }; + + true +} + fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {} //~^ ERROR: unused doc comment diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr index 078b780d8b9..b5aa6215797 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -42,7 +42,29 @@ LL | num == 3 = help: use `//` for a plain comment error: unused doc comment - --> $DIR/unused-doc-comments-edge-cases.rs:29:27 + --> $DIR/unused-doc-comments-edge-cases.rs:33:9 + | +LL | /// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | foo: 3 + | ------ rustdoc does not generate documentation for expression fields + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/unused-doc-comments-edge-cases.rs:45:9 + | +LL | /// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | foo + | --- rustdoc does not generate documentation for pattern fields + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/unused-doc-comments-edge-cases.rs:55:27 | LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {} | ^^^^^^^^^^^^ - rustdoc does not generate documentation for generic parameters @@ -50,7 +72,7 @@ LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/unused-doc-comments-edge-cases.rs:33:5 + --> $DIR/unused-doc-comments-edge-cases.rs:59:5 | LL | /// unused doc comment | ^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +85,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/unused-doc-comments-edge-cases.rs:40:1 + --> $DIR/unused-doc-comments-edge-cases.rs:66:1 | LL | /// unused doc comment | ^^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +111,7 @@ help: you might have meant to return this value LL | return true; | ++++++ + -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/lint/unused/unused-parens-issue-106413.rs b/tests/ui/lint/unused/unused-parens-issue-106413.rs new file mode 100644 index 00000000000..7e76ab073b4 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-issue-106413.rs @@ -0,0 +1,32 @@ +// check-pass +#![warn(unused_parens)] + +fn id<T>(t: T) -> T { t } + +fn main() { + // This should not warn + let _ = 1 as (i32) < 2; + let _ = id(1 as (i32) < 2); + let _ = id(1 as i32) + as (i32) < 2; + // These should warn + let _ = 1 as ((i32)) < 2; //~WARN unnecessary parentheses + let _ = 1 as (i32); //~WARN unnecessary parentheses + let _ = 1 as (i32) > 2; //~WARN unnecessary parentheses + let _ = id(1 as (i32)) //~WARN unnecessary parentheses + as (i32) < 2; + let _ = id(1 as (i32)) < 2; //~WARN unnecessary parentheses + + // This should not warn + let _ = 1 as (i32) << 2; + let _ = id(1 as (i32) << 2); + let _ = id(1 as i32) + as (i32) << 2; + // These should warn + let _ = 1 as ((i32)) << 2; //~WARN unnecessary parentheses + let _ = 1 as (i32); //~WARN unnecessary parentheses + let _ = 1 as (i32) >> 2; //~WARN unnecessary parentheses + let _ = id(1 as (i32)) //~WARN unnecessary parentheses + as (i32) << 2; + let _ = id(1 as (i32)) << 2; //~WARN unnecessary parentheses +} diff --git a/tests/ui/lint/unused/unused-parens-issue-106413.stderr b/tests/ui/lint/unused/unused-parens-issue-106413.stderr new file mode 100644 index 00000000000..d2d8f76d967 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-issue-106413.stderr @@ -0,0 +1,127 @@ +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:13:19 + | +LL | let _ = 1 as ((i32)) < 2; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-issue-106413.rs:2:9 + | +LL | #![warn(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - let _ = 1 as ((i32)) < 2; +LL + let _ = 1 as (i32) < 2; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:14:18 + | +LL | let _ = 1 as (i32); + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = 1 as (i32); +LL + let _ = 1 as i32; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:15:18 + | +LL | let _ = 1 as (i32) > 2; + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = 1 as (i32) > 2; +LL + let _ = 1 as i32 > 2; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:16:21 + | +LL | let _ = id(1 as (i32)) + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = id(1 as (i32)) +LL + let _ = id(1 as i32) + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:18:21 + | +LL | let _ = id(1 as (i32)) < 2; + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = id(1 as (i32)) < 2; +LL + let _ = id(1 as i32) < 2; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:26:19 + | +LL | let _ = 1 as ((i32)) << 2; + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = 1 as ((i32)) << 2; +LL + let _ = 1 as (i32) << 2; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:27:18 + | +LL | let _ = 1 as (i32); + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = 1 as (i32); +LL + let _ = 1 as i32; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:28:18 + | +LL | let _ = 1 as (i32) >> 2; + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = 1 as (i32) >> 2; +LL + let _ = 1 as i32 >> 2; + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:29:21 + | +LL | let _ = id(1 as (i32)) + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = id(1 as (i32)) +LL + let _ = id(1 as i32) + | + +warning: unnecessary parentheses around type + --> $DIR/unused-parens-issue-106413.rs:31:21 + | +LL | let _ = id(1 as (i32)) << 2; + | ^ ^ + | +help: remove these parentheses + | +LL - let _ = id(1 as (i32)) << 2; +LL + let _ = id(1 as i32) << 2; + | + +warning: 10 warnings emitted + diff --git a/tests/ui/macros/must-use-in-macro-55516.stderr b/tests/ui/macros/must-use-in-macro-55516.stderr index 8878b0eea0f..7bf4aaab51c 100644 --- a/tests/ui/macros/must-use-in-macro-55516.stderr +++ b/tests/ui/macros/must-use-in-macro-55516.stderr @@ -6,6 +6,7 @@ LL | write!(&mut example, "{}", 42); | = note: this `Result` may be an `Err` variant, which should be handled = note: `-W unused-must-use` implied by `-W unused` + = help: to override `-W unused` add `#[allow(unused_must_use)]` = note: this warning originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 1 warning emitted diff --git a/tests/ui/match/match_non_exhaustive.stderr b/tests/ui/match/match_non_exhaustive.stderr index 46ee8d5179e..7b8bdfe0053 100644 --- a/tests/ui/match/match_non_exhaustive.stderr +++ b/tests/ui/match/match_non_exhaustive.stderr @@ -45,7 +45,8 @@ note: `E2` defined here | LL | pub enum E2 { A, B } | ^^^^^^^^^^^ - = note: the matched value is of type `E2`, which is marked as non-exhaustive + = note: the matched value is of type `E2` + = note: `E2` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match e2 { E2::A => (), E2::B => (), _ => todo!() }; diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs b/tests/ui/object-safety/assoc_type_bounds_sized_used.rs index cf5345b1c1d..d59fc1712ea 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.rs +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.rs @@ -1,6 +1,5 @@ -//! This test checks that even if some associated types have -//! `where Self: Sized` bounds, those without still need to be -//! mentioned in trait objects. +//! This test checks that associated types with `Self: Sized` cannot be projected +//! from a `dyn Trait`. trait Bop { type Bar: Default @@ -16,5 +15,4 @@ fn bop<T: Bop + ?Sized>() { fn main() { bop::<dyn Bop>(); - //~^ ERROR: the size for values of type `dyn Bop` cannot be known at compilation time } diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr index 6b5bc360349..224d33fb2da 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr @@ -1,5 +1,5 @@ error[E0599]: the function or associated item `default` exists for associated type `<T as Bop>::Bar`, but its trait bounds were not satisfied - --> $DIR/assoc_type_bounds_sized_used.rs:12:30 + --> $DIR/assoc_type_bounds_sized_used.rs:11:30 | LL | let _ = <T as Bop>::Bar::default(); | ^^^^^^^ function or associated item cannot be called on `<T as Bop>::Bar` due to unsatisfied trait bounds @@ -13,7 +13,7 @@ LL | fn bop<T: Bop + ?Sized>() where T: Sized { | ++++++++++++++ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/assoc_type_bounds_sized_used.rs:12:14 + --> $DIR/assoc_type_bounds_sized_used.rs:11:14 | LL | fn bop<T: Bop + ?Sized>() { | - this type parameter needs to be `Sized` @@ -21,7 +21,7 @@ LL | let _ = <T as Bop>::Bar::default(); | ^ doesn't have a size known at compile-time | note: required by a bound in `Bop::Bar` - --> $DIR/assoc_type_bounds_sized_used.rs:8:15 + --> $DIR/assoc_type_bounds_sized_used.rs:7:15 | LL | type Bar: Default | --- required by a bound in this associated type @@ -34,20 +34,7 @@ LL - fn bop<T: Bop + ?Sized>() { LL + fn bop<T: Bop>() { | -error[E0277]: the size for values of type `dyn Bop` cannot be known at compilation time - --> $DIR/assoc_type_bounds_sized_used.rs:18:11 - | -LL | bop::<dyn Bop>(); - | ^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `dyn Bop` -note: required by a bound in `bop` - --> $DIR/assoc_type_bounds_sized_used.rs:11:11 - | -LL | fn bop<T: Bop + ?Sized>() { - | ^^^ required by this bound in `bop` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs b/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs new file mode 100644 index 00000000000..0b30a88fdd4 --- /dev/null +++ b/tests/ui/object-safety/call-when-assoc-ty-is-sized.rs @@ -0,0 +1,25 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +trait Foo { + type Bar<'a> + where + Self: Sized; + + fn test(&self); +} + +impl Foo for () { + type Bar<'a> = () where Self: Sized; + + fn test(&self) {} +} + +fn test(x: &dyn Foo) { + x.test(); +} + +fn main() { + test(&()); +} diff --git a/tests/ui/parser/default-unmatched.stderr b/tests/ui/parser/default-unmatched.stderr index 331e003f63c..de142411d69 100644 --- a/tests/ui/parser/default-unmatched.stderr +++ b/tests/ui/parser/default-unmatched.stderr @@ -11,6 +11,8 @@ error: expected item, found reserved keyword `do` | LL | default do | ^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 2 previous errors diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr index 755addf1452..a57cc075ccc 100644 --- a/tests/ui/parser/impl-parsing.stderr +++ b/tests/ui/parser/impl-parsing.stderr @@ -35,6 +35,8 @@ error: expected item, found keyword `unsafe` | LL | default unsafe FAIL | ^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 6 previous errors diff --git a/tests/ui/parser/issue-101477-enum.stderr b/tests/ui/parser/issue-101477-enum.stderr index 1edca391e8f..94130671f1c 100644 --- a/tests/ui/parser/issue-101477-enum.stderr +++ b/tests/ui/parser/issue-101477-enum.stderr @@ -11,6 +11,8 @@ error: expected item, found `==` | LL | B == 2 | ^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs new file mode 100644 index 00000000000..3b6f4304369 --- /dev/null +++ b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.rs @@ -0,0 +1 @@ + 5 //~ ERROR expected item, found `5` diff --git a/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr new file mode 100644 index 00000000000..0789c4548a0 --- /dev/null +++ b/tests/ui/parser/issues/issue-113110-non-item-at-module-root.stderr @@ -0,0 +1,10 @@ +error: expected item, found `5` + --> $DIR/issue-113110-non-item-at-module-root.rs:1:2 + | +LL | 5 + | ^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-17904-2.stderr b/tests/ui/parser/issues/issue-17904-2.stderr index 9c7fdf6ccb4..7185a5e5752 100644 --- a/tests/ui/parser/issues/issue-17904-2.stderr +++ b/tests/ui/parser/issues/issue-17904-2.stderr @@ -3,6 +3,8 @@ error: expected item, found keyword `where` | LL | struct Bar<T> { x: T } where T: Copy | ^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-43196.stderr b/tests/ui/parser/issues/issue-43196.stderr index 4f7ed5cc6fd..15bbb158cd1 100644 --- a/tests/ui/parser/issues/issue-43196.stderr +++ b/tests/ui/parser/issues/issue-43196.stderr @@ -11,6 +11,8 @@ error: expected item, found `|` | LL | | | ^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-62913.stderr b/tests/ui/parser/issues/issue-62913.stderr index 6f385e8dc17..c33e4683728 100644 --- a/tests/ui/parser/issues/issue-62913.stderr +++ b/tests/ui/parser/issues/issue-62913.stderr @@ -17,6 +17,8 @@ error: expected item, found `"\u\"` | LL | "\u\" | ^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/issue-68890.stderr b/tests/ui/parser/issues/issue-68890.stderr index 2a3bf6b41f0..0d7b53a67c5 100644 --- a/tests/ui/parser/issues/issue-68890.stderr +++ b/tests/ui/parser/issues/issue-68890.stderr @@ -15,6 +15,8 @@ error: expected item, found `)` | LL | enum e{A((?'a a+?+l))} | ^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 3 previous errors diff --git a/tests/ui/parser/shebang/shebang-doc-comment.stderr b/tests/ui/parser/shebang/shebang-doc-comment.stderr index 2227d45ec5a..a36b2a2f72b 100644 --- a/tests/ui/parser/shebang/shebang-doc-comment.stderr +++ b/tests/ui/parser/shebang/shebang-doc-comment.stderr @@ -3,6 +3,8 @@ error: expected item, found `[` | LL | [allow(unused_variables)] | ^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to previous error diff --git a/tests/ui/parser/struct-literal-in-if.rs b/tests/ui/parser/struct-literal-in-if.rs index 2ce2c8f1899..c4a253c3da2 100644 --- a/tests/ui/parser/struct-literal-in-if.rs +++ b/tests/ui/parser/struct-literal-in-if.rs @@ -14,4 +14,9 @@ fn main() { }.hi() { println!("yo"); } + if let true = Foo { //~ ERROR struct literals are not allowed here + x: 3 + }.hi() { + println!("yo"); + } } diff --git a/tests/ui/parser/struct-literal-in-if.stderr b/tests/ui/parser/struct-literal-in-if.stderr index b5a9864bbc4..8b72469fcf5 100644 --- a/tests/ui/parser/struct-literal-in-if.stderr +++ b/tests/ui/parser/struct-literal-in-if.stderr @@ -14,5 +14,21 @@ LL | x: 3 LL ~ }).hi() { | -error: aborting due to previous error +error: struct literals are not allowed here + --> $DIR/struct-literal-in-if.rs:17:19 + | +LL | if let true = Foo { + | ___________________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ + | +help: surround the struct literal with parentheses + | +LL ~ if let true = (Foo { +LL | x: 3 +LL ~ }).hi() { + | + +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/struct-literal-in-match-guard.rs b/tests/ui/parser/struct-literal-in-match-guard.rs index bf0551b5c97..bbee60e2817 100644 --- a/tests/ui/parser/struct-literal-in-match-guard.rs +++ b/tests/ui/parser/struct-literal-in-match-guard.rs @@ -3,6 +3,8 @@ // Unlike `if` condition, `match` guards accept struct literals. // This is detected in <https://github.com/rust-lang/rust/pull/74566#issuecomment-663613705>. +#![feature(if_let_guard)] + #[derive(PartialEq)] struct Foo { x: isize, @@ -11,6 +13,7 @@ struct Foo { fn foo(f: Foo) { match () { () if f == Foo { x: 42 } => {} + () if let Foo { x: 0.. } = Foo { x: 42 } => {} _ => {} } } diff --git a/tests/ui/parser/struct-literal-in-while.rs b/tests/ui/parser/struct-literal-in-while.rs index 5000ce85b7f..86931f7888d 100644 --- a/tests/ui/parser/struct-literal-in-while.rs +++ b/tests/ui/parser/struct-literal-in-while.rs @@ -14,4 +14,9 @@ fn main() { }.hi() { println!("yo"); } + while let true = Foo { //~ ERROR struct literals are not allowed here + x: 3 + }.hi() { + println!("yo"); + } } diff --git a/tests/ui/parser/struct-literal-in-while.stderr b/tests/ui/parser/struct-literal-in-while.stderr index 17e9277e074..13d003608a1 100644 --- a/tests/ui/parser/struct-literal-in-while.stderr +++ b/tests/ui/parser/struct-literal-in-while.stderr @@ -14,5 +14,21 @@ LL | x: 3 LL ~ }).hi() { | -error: aborting due to previous error +error: struct literals are not allowed here + --> $DIR/struct-literal-in-while.rs:17:22 + | +LL | while let true = Foo { + | ______________________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ + | +help: surround the struct literal with parentheses + | +LL ~ while let true = (Foo { +LL | x: 3 +LL ~ }).hi() { + | + +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/virtual-structs.stderr b/tests/ui/parser/virtual-structs.stderr index a5211d83f84..268fc105796 100644 --- a/tests/ui/parser/virtual-structs.stderr +++ b/tests/ui/parser/virtual-structs.stderr @@ -3,6 +3,8 @@ error: expected item, found reserved keyword `virtual` | LL | virtual struct SuperStruct { | ^^^^^^^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to previous error diff --git a/tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs b/tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs new file mode 100644 index 00000000000..6f459b8268f --- /dev/null +++ b/tests/ui/pattern/usefulness/auxiliary/non-exhaustive.rs @@ -0,0 +1,2 @@ +#[non_exhaustive] +pub enum NonExhaustiveEnum { A, B } diff --git a/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs new file mode 100644 index 00000000000..0ee7856c680 --- /dev/null +++ b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs @@ -0,0 +1,12 @@ +fn main() { + let a = ""; + let b = ""; + match (a, b) { + //~^ ERROR non-exhaustive patterns: `(&_, _)` not covered [E0004] + //~| NOTE pattern `(&_, _)` not covered + //~| NOTE the matched value is of type `(&str, &str)` + //~| NOTE `&str` cannot be matched exhaustively, so a wildcard `_` is necessary + ("a", "b") => {} + ("c", "d") => {} + } +} diff --git a/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr new file mode 100644 index 00000000000..771fc320a13 --- /dev/null +++ b/tests/ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.stderr @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: `(&_, _)` not covered + --> $DIR/issue-105479-str-non-exhaustiveness.rs:4:11 + | +LL | match (a, b) { + | ^^^^^^ pattern `(&_, _)` not covered + | + = note: the matched value is of type `(&str, &str)` + = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ ("c", "d") => {}, +LL + (&_, _) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr index ff755d681ac..da8bbdffbf6 100644 --- a/tests/ui/pattern/usefulness/issue-30240.stderr +++ b/tests/ui/pattern/usefulness/issue-30240.stderr @@ -5,6 +5,7 @@ LL | match "world" { | ^^^^^^^ pattern `&_` not covered | = note: the matched value is of type `&str` + = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ "hello" => {}, @@ -18,6 +19,7 @@ LL | match "world" { | ^^^^^^^ pattern `&_` not covered | = note: the matched value is of type `&str` + = note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ "hello" => {}, diff --git a/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs new file mode 100644 index 00000000000..3a8a74d1fd6 --- /dev/null +++ b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.rs @@ -0,0 +1,18 @@ +// aux-build:non-exhaustive.rs + +extern crate non_exhaustive; + +use non_exhaustive::NonExhaustiveEnum; + +fn main() { + match Some(NonExhaustiveEnum::A) { + //~^ ERROR non-exhaustive patterns: `Some(_)` not covered [E0004] + //~| NOTE pattern `Some(_)` not covered + //~| NOTE `Option<NonExhaustiveEnum>` defined here + //~| NOTE the matched value is of type `Option<NonExhaustiveEnum>` + //~| NOTE `NonExhaustiveEnum` is marked as non-exhaustive + Some(NonExhaustiveEnum::A) => {} + Some(NonExhaustiveEnum::B) => {} + None => {} + } +} diff --git a/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr new file mode 100644 index 00000000000..9fbd871db7c --- /dev/null +++ b/tests/ui/pattern/usefulness/nested-non-exhaustive-enums.stderr @@ -0,0 +1,22 @@ +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/nested-non-exhaustive-enums.rs:8:11 + | +LL | match Some(NonExhaustiveEnum::A) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option<NonExhaustiveEnum>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option<NonExhaustiveEnum>` + = note: `NonExhaustiveEnum` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ None => {}, +LL + Some(_) => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/privacy/private-bounds-locally-allowed.rs b/tests/ui/privacy/private-bounds-locally-allowed.rs new file mode 100644 index 00000000000..96a007a64f6 --- /dev/null +++ b/tests/ui/privacy/private-bounds-locally-allowed.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: --crate-type=lib + +#[allow(private_bounds)] +pub trait Foo: FooImpl {} + +trait FooImpl {} diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs index e35aaec5b3b..c6c5561c3c4 100644 --- a/tests/ui/privacy/unnameable_types.rs +++ b/tests/ui/privacy/unnameable_types.rs @@ -20,10 +20,10 @@ mod m { } } -pub trait Voldemort<T> {} +pub trait Unnameable<T> {} -impl Voldemort<m::PubStruct> for i32 {} -impl Voldemort<m::PubE> for i32 {} -impl<T> Voldemort<T> for u32 where T: m::PubTr {} +impl Unnameable<m::PubStruct> for i32 {} +impl Unnameable<m::PubE> for i32 {} +impl<T> Unnameable<T> for u32 where T: m::PubTr {} fn main() {} diff --git a/tests/ui/pub/pub-restricted-error-fn.stderr b/tests/ui/pub/pub-restricted-error-fn.stderr index 0511a821a7a..ca5d8e1b58e 100644 --- a/tests/ui/pub/pub-restricted-error-fn.stderr +++ b/tests/ui/pub/pub-restricted-error-fn.stderr @@ -11,6 +11,8 @@ error: expected item, found `(` | LL | pub(crate) () fn foo() {} | ^ expected item + | + = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 2 previous errors diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 277d9b2682d..ecfc56961ee 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -19,7 +19,7 @@ LL | for i in false..true {} i64 i128 usize - and 5 others + and 6 others = note: required for `std::ops::Range<bool>` to implement `Iterator` = note: required for `std::ops::Range<bool>` to implement `IntoIterator` diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed new file mode 100644 index 00000000000..fc68884fe9c --- /dev/null +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.fixed @@ -0,0 +1,16 @@ +// run-rustfix +// compile-flags: --cfg=whatever -Aunused + +use y::z; +#[cfg(whatever)] +use y::Whatever; + +mod y { + pub(crate) fn z() {} + pub(crate) struct Whatever; +} + +fn main() { + z(); + //~^ ERROR cannot find function `z` in this scope +} diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs new file mode 100644 index 00000000000..38a1095703b --- /dev/null +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.rs @@ -0,0 +1,15 @@ +// run-rustfix +// compile-flags: --cfg=whatever -Aunused + +#[cfg(whatever)] +use y::Whatever; + +mod y { + pub(crate) fn z() {} + pub(crate) struct Whatever; +} + +fn main() { + z(); + //~^ ERROR cannot find function `z` in this scope +} diff --git a/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr new file mode 100644 index 00000000000..d3574851d5c --- /dev/null +++ b/tests/ui/resolve/suggest-import-without-clobbering-attrs.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find function `z` in this scope + --> $DIR/suggest-import-without-clobbering-attrs.rs:13:5 + | +LL | z(); + | ^ not found in this scope + | +help: consider importing this function + | +LL + use y::z; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr index 872cb9b8bc6..4e7f3098ab4 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr @@ -28,7 +28,8 @@ note: `NonExhaustiveEnum` defined here | LL | pub enum NonExhaustiveEnum { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive + = note: the matched value is of type `NonExhaustiveEnum` + = note: `NonExhaustiveEnum` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ NonExhaustiveEnum::Struct { .. } => "third", @@ -46,7 +47,7 @@ note: `NonExhaustiveEnum` defined here | LL | pub enum NonExhaustiveEnum { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive + = note: the matched value is of type `NonExhaustiveEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ match enum_unit { diff --git a/tests/ui/rmeta/auxiliary/rmeta-meta.rs b/tests/ui/rmeta/auxiliary/rmeta-meta.rs index 6d8ed95bd38..6d435049527 100644 --- a/tests/ui/rmeta/auxiliary/rmeta-meta.rs +++ b/tests/ui/rmeta/auxiliary/rmeta-meta.rs @@ -6,3 +6,7 @@ pub struct Foo { pub field: i32, } + +pub fn missing_optimized_mir() { + println!("indeed"); +} diff --git a/tests/ui/rmeta/no_optitimized_mir.rs b/tests/ui/rmeta/no_optitimized_mir.rs new file mode 100644 index 00000000000..c503005f16b --- /dev/null +++ b/tests/ui/rmeta/no_optitimized_mir.rs @@ -0,0 +1,11 @@ +// aux-build:rmeta-meta.rs +// no-prefer-dynamic +// build-fail + +// Check that we do not ICE when we need optimized MIR but it is missing. + +extern crate rmeta_meta; + +fn main() { + rmeta_meta::missing_optimized_mir(); +} diff --git a/tests/ui/rmeta/no_optitimized_mir.stderr b/tests/ui/rmeta/no_optitimized_mir.stderr new file mode 100644 index 00000000000..a17024c5310 --- /dev/null +++ b/tests/ui/rmeta/no_optitimized_mir.stderr @@ -0,0 +1,10 @@ +error: missing optimized MIR for an item in the crate `rmeta_meta` + | +note: missing optimized MIR for this item (was the crate `rmeta_meta` compiled with `--emit=metadata`?) + --> $DIR/auxiliary/rmeta-meta.rs:10:1 + | +LL | pub fn missing_optimized_mir() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/sanitize/cfg.rs b/tests/ui/sanitize/cfg.rs index c0f08a6d1e5..523de1ceaee 100644 --- a/tests/ui/sanitize/cfg.rs +++ b/tests/ui/sanitize/cfg.rs @@ -2,19 +2,19 @@ // the `#[cfg(sanitize = "option")]` attribute is configured. // needs-sanitizer-support -// needs-sanitizer-address -// needs-sanitizer-cfi -// needs-sanitizer-kcfi -// needs-sanitizer-leak -// needs-sanitizer-memory -// needs-sanitizer-thread // check-pass -// revisions: address leak memory thread +// revisions: address cfi kcfi leak memory thread +//[address]needs-sanitizer-address //[address]compile-flags: -Zsanitizer=address --cfg address -//[cfi]compile-flags: -Zsanitizer=cfi --cfg cfi +//[cfi]needs-sanitizer-cfi +//[cfi]compile-flags: -Zsanitizer=cfi --cfg cfi -Clto +//[kcfi]needs-sanitizer-kcfi //[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi +//[leak]needs-sanitizer-leak //[leak]compile-flags: -Zsanitizer=leak --cfg leak +//[memory]needs-sanitizer-memory //[memory]compile-flags: -Zsanitizer=memory --cfg memory +//[thread]needs-sanitizer-thread //[thread]compile-flags: -Zsanitizer=thread --cfg thread #![feature(cfg_sanitize)] diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout index 7bddc925996..af7f2b67152 100644 --- a/tests/ui/thir-print/thir-flat-const-variant.stdout +++ b/tests/ui/thir-print/thir-flat-const-variant.stdout @@ -1,7 +1,11 @@ DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1): Thir { body_type: Const( - Foo, + Adt( + Foo, + [ + ], + ), ), arms: [], blocks: [], @@ -46,7 +50,11 @@ Thir { base: None, }, ), - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -60,7 +68,11 @@ Thir { ), value: e2, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -72,7 +84,11 @@ Thir { lint_level: Inherited, value: e3, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -86,7 +102,11 @@ Thir { DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2): Thir { body_type: Const( - Foo, + Adt( + Foo, + [ + ], + ), ), arms: [], blocks: [], @@ -131,7 +151,11 @@ Thir { base: None, }, ), - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -145,7 +169,11 @@ Thir { ), value: e2, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -157,7 +185,11 @@ Thir { lint_level: Inherited, value: e3, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -171,7 +203,11 @@ Thir { DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3): Thir { body_type: Const( - Foo, + Adt( + Foo, + [ + ], + ), ), arms: [], blocks: [], @@ -216,7 +252,11 @@ Thir { base: None, }, ), - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -230,7 +270,11 @@ Thir { ), value: e2, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -242,7 +286,11 @@ Thir { lint_level: Inherited, value: e3, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -256,7 +304,11 @@ Thir { DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4): Thir { body_type: Const( - Foo, + Adt( + Foo, + [ + ], + ), ), arms: [], blocks: [], @@ -301,7 +353,11 @@ Thir { base: None, }, ), - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -315,7 +371,11 @@ Thir { ), value: e2, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), @@ -327,7 +387,11 @@ Thir { lint_level: Inherited, value: e3, }, - ty: Foo, + ty: Adt( + Foo, + [ + ], + ), temp_lifetime: Some( Node(3), ), diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 3fc130f0176..0e21b98307b 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -1,13 +1,13 @@ DefId(0:16 ~ thir_tree_match[fcf8]::has_match): params: [ Param { - ty: Foo + ty: Adt(Foo, []) ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0)) self_kind: None hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).1)) param: Some( Pat: { - ty: Foo + ty: Adt(Foo, []) span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0) kind: PatKind { Binding { @@ -15,7 +15,7 @@ params: [ name: "foo" mode: ByValue var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2)) - ty: Foo + ty: Adt(Foo, []) is_primary: true subpattern: None } @@ -73,7 +73,7 @@ body: Match { scrutinee: Expr { - ty: Foo + ty: Adt(Foo, []) temp_lifetime: Some(Node(26)) span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: @@ -82,7 +82,7 @@ body: lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4)) value: Expr { - ty: Foo + ty: Adt(Foo, []) temp_lifetime: Some(Node(26)) span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: @@ -96,7 +96,7 @@ body: Arm { pattern: Pat: { - ty: Foo + ty: Adt(Foo, []) span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0) kind: PatKind { Variant { @@ -110,7 +110,7 @@ body: variant_index: 0 subpatterns: [ Pat: { - ty: Bar + ty: Adt(Bar, []) span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0) kind: PatKind { Variant { @@ -169,7 +169,7 @@ body: Arm { pattern: Pat: { - ty: Foo + ty: Adt(Foo, []) span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0) kind: PatKind { Variant { @@ -183,7 +183,7 @@ body: variant_index: 0 subpatterns: [ Pat: { - ty: Bar + ty: Adt(Bar, []) span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0) kind: PatKind { Wild @@ -232,7 +232,7 @@ body: Arm { pattern: Pat: { - ty: Foo + ty: Adt(Foo, []) span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0) kind: PatKind { Variant { diff --git a/tests/ui/trait-bounds/issue-82038.rs b/tests/ui/trait-bounds/issue-82038.rs new file mode 100644 index 00000000000..11de714faf0 --- /dev/null +++ b/tests/ui/trait-bounds/issue-82038.rs @@ -0,0 +1,9 @@ +// Failed bound `bool: Foo` must not point at the `Self: Clone` line + +trait Foo { + fn my_method() where Self: Clone; +} + +fn main() { + <bool as Foo>::my_method(); //~ERROR [E0277] +} diff --git a/tests/ui/trait-bounds/issue-82038.stderr b/tests/ui/trait-bounds/issue-82038.stderr new file mode 100644 index 00000000000..f37e3286f4b --- /dev/null +++ b/tests/ui/trait-bounds/issue-82038.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `bool: Foo` is not satisfied + --> $DIR/issue-82038.rs:8:6 + | +LL | <bool as Foo>::my_method(); + | ^^^^ the trait `Foo` is not implemented for `bool` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.rs b/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.rs new file mode 100644 index 00000000000..b9798c79d5e --- /dev/null +++ b/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.rs @@ -0,0 +1,19 @@ +// compile-flags: -Ztrait-solver=next-coherence + +// Makes sure we don't ICE on associated const projection when the feature gate +// is not enabled, since we should avoid encountering ICEs on stable if possible. + +trait Bar { + const ASSOC: usize; +} +impl Bar for () { + const ASSOC: usize = 1; +} + +trait Foo {} +impl Foo for () {} +impl<T> Foo for T where T: Bar<ASSOC = 0> {} +//~^ ERROR associated const equality is incomplete +//~| ERROR conflicting implementations of trait `Foo` for type `()` + +fn main() {} diff --git a/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr b/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr new file mode 100644 index 00000000000..7ad495a35e0 --- /dev/null +++ b/tests/ui/traits/new-solver/dont-ice-on-assoc-projection.stderr @@ -0,0 +1,21 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/dont-ice-on-assoc-projection.rs:15:32 + | +LL | impl<T> Foo for T where T: Bar<ASSOC = 0> {} + | ^^^^^^^^^ + | + = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + +error[E0119]: conflicting implementations of trait `Foo` for type `()` + --> $DIR/dont-ice-on-assoc-projection.rs:15:1 + | +LL | impl Foo for () {} + | --------------- first implementation here +LL | impl<T> Foo for T where T: Bar<ASSOC = 0> {} + | ^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0658. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/object/enforce-supertrait-projection.rs b/tests/ui/traits/object/enforce-supertrait-projection.rs index 2c9b41eea2a..0ea944ec2df 100644 --- a/tests/ui/traits/object/enforce-supertrait-projection.rs +++ b/tests/ui/traits/object/enforce-supertrait-projection.rs @@ -7,7 +7,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {} fn transmute<A, B>(x: A) -> B { foo::<A, B, dyn Trait<A = A, B = B>>(x) - //~^ ERROR type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B` + //~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B` } fn foo<A, B, T: ?Sized>(x: T::A) -> B diff --git a/tests/ui/traits/object/enforce-supertrait-projection.stderr b/tests/ui/traits/object/enforce-supertrait-projection.stderr index 848b4e69a4b..2fb94d34896 100644 --- a/tests/ui/traits/object/enforce-supertrait-projection.stderr +++ b/tests/ui/traits/object/enforce-supertrait-projection.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B` +error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B` --> $DIR/enforce-supertrait-projection.rs:9:17 | LL | fn transmute<A, B>(x: A) -> B { diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs new file mode 100644 index 00000000000..c6f9e345618 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.rs @@ -0,0 +1,15 @@ +fn use_iterator<I>(itr: I) +where + I: IntoIterator<Item = i32>, +{ +} + +fn pass_iterator<I>(i: &dyn IntoIterator<Item = i32, IntoIter = I>) +where + I: Iterator<Item = i32>, +{ + use_iterator(i); + //~^ ERROR `&dyn IntoIterator<IntoIter = I, Item = i32>` is not an iterator +} + +fn main() {} diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr new file mode 100644 index 00000000000..bd0e7ca2c02 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr @@ -0,0 +1,22 @@ +error[E0277]: `&dyn IntoIterator<IntoIter = I, Item = i32>` is not an iterator + --> $DIR/dont-suggest-unsize-deref.rs:11:18 + | +LL | use_iterator(i); + | ------------ ^ `&dyn IntoIterator<IntoIter = I, Item = i32>` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&dyn IntoIterator<IntoIter = I, Item = i32>` + = note: required for `&dyn IntoIterator<IntoIter = I, Item = i32>` to implement `IntoIterator` +note: required by a bound in `use_iterator` + --> $DIR/dont-suggest-unsize-deref.rs:3:8 + | +LL | fn use_iterator<I>(itr: I) + | ------------ required by a bound in this function +LL | where +LL | I: IntoIterator<Item = i32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `use_iterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/suggest-deferences/issue-39029.fixed b/tests/ui/traits/suggest-dereferences/issue-39029.fixed index a1abf668b8b..a1abf668b8b 100644 --- a/tests/ui/traits/suggest-deferences/issue-39029.fixed +++ b/tests/ui/traits/suggest-dereferences/issue-39029.fixed diff --git a/tests/ui/traits/suggest-deferences/issue-39029.rs b/tests/ui/traits/suggest-dereferences/issue-39029.rs index 90d097105ed..90d097105ed 100644 --- a/tests/ui/traits/suggest-deferences/issue-39029.rs +++ b/tests/ui/traits/suggest-dereferences/issue-39029.rs diff --git a/tests/ui/traits/suggest-deferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr index 49105de3d69..49105de3d69 100644 --- a/tests/ui/traits/suggest-deferences/issue-39029.stderr +++ b/tests/ui/traits/suggest-dereferences/issue-39029.stderr diff --git a/tests/ui/traits/suggest-deferences/issue-62530.fixed b/tests/ui/traits/suggest-dereferences/issue-62530.fixed index 406caaa007f..406caaa007f 100644 --- a/tests/ui/traits/suggest-deferences/issue-62530.fixed +++ b/tests/ui/traits/suggest-dereferences/issue-62530.fixed diff --git a/tests/ui/traits/suggest-deferences/issue-62530.rs b/tests/ui/traits/suggest-dereferences/issue-62530.rs index 53846be7306..53846be7306 100644 --- a/tests/ui/traits/suggest-deferences/issue-62530.rs +++ b/tests/ui/traits/suggest-dereferences/issue-62530.rs diff --git a/tests/ui/traits/suggest-deferences/issue-62530.stderr b/tests/ui/traits/suggest-dereferences/issue-62530.stderr index e47ae0b65af..e47ae0b65af 100644 --- a/tests/ui/traits/suggest-deferences/issue-62530.stderr +++ b/tests/ui/traits/suggest-dereferences/issue-62530.stderr diff --git a/tests/ui/traits/suggest-deferences/multiple-0.fixed b/tests/ui/traits/suggest-dereferences/multiple-0.fixed index b7160b75c60..b7160b75c60 100644 --- a/tests/ui/traits/suggest-deferences/multiple-0.fixed +++ b/tests/ui/traits/suggest-dereferences/multiple-0.fixed diff --git a/tests/ui/traits/suggest-deferences/multiple-0.rs b/tests/ui/traits/suggest-dereferences/multiple-0.rs index 9ac55177ffa..9ac55177ffa 100644 --- a/tests/ui/traits/suggest-deferences/multiple-0.rs +++ b/tests/ui/traits/suggest-dereferences/multiple-0.rs diff --git a/tests/ui/traits/suggest-deferences/multiple-0.stderr b/tests/ui/traits/suggest-dereferences/multiple-0.stderr index 6a4d4b8d521..6a4d4b8d521 100644 --- a/tests/ui/traits/suggest-deferences/multiple-0.stderr +++ b/tests/ui/traits/suggest-dereferences/multiple-0.stderr diff --git a/tests/ui/traits/suggest-deferences/multiple-1.rs b/tests/ui/traits/suggest-dereferences/multiple-1.rs index 91c6c7924a4..91c6c7924a4 100644 --- a/tests/ui/traits/suggest-deferences/multiple-1.rs +++ b/tests/ui/traits/suggest-dereferences/multiple-1.rs diff --git a/tests/ui/traits/suggest-deferences/multiple-1.stderr b/tests/ui/traits/suggest-dereferences/multiple-1.stderr index 6e12321c233..6e12321c233 100644 --- a/tests/ui/traits/suggest-deferences/multiple-1.stderr +++ b/tests/ui/traits/suggest-dereferences/multiple-1.stderr diff --git a/tests/ui/traits/suggest-deferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed index 7a8433f9057..7a8433f9057 100644 --- a/tests/ui/traits/suggest-deferences/root-obligation.fixed +++ b/tests/ui/traits/suggest-dereferences/root-obligation.fixed diff --git a/tests/ui/traits/suggest-deferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs index 51bac2107e3..51bac2107e3 100644 --- a/tests/ui/traits/suggest-deferences/root-obligation.rs +++ b/tests/ui/traits/suggest-dereferences/root-obligation.rs diff --git a/tests/ui/traits/suggest-deferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index 1363fb8c47a..1363fb8c47a 100644 --- a/tests/ui/traits/suggest-deferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed index ea3d1bf853a..ea3d1bf853a 100644 --- a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.fixed +++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.fixed diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs index 9eda68027b2..9eda68027b2 100644 --- a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.rs +++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.rs diff --git a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr index ede31a2c7bc..ede31a2c7bc 100644 --- a/tests/ui/traits/suggest-deferences/suggest-dereferencing-receiver-argument.stderr +++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr diff --git a/tests/ui/transmute/issue-115402-overflow-size.rs b/tests/ui/transmute/issue-115402-overflow-size.rs new file mode 100644 index 00000000000..91168041ed6 --- /dev/null +++ b/tests/ui/transmute/issue-115402-overflow-size.rs @@ -0,0 +1,27 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +mod assert { + use std::mem::BikeshedIntrinsicFrom; + struct Context; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, Context>, + { + } +} + +fn main() { + pub union Uninit { + a: [u8; usize::MAX], + } + + #[repr(C)] + struct ExplicitlyPadded(Uninit); + + assert::is_maybe_transmutable::<(), ExplicitlyPadded>(); + //~^ ERROR `()` cannot be safely transmuted into `ExplicitlyPadded` + + assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); + //~^ ERROR `ExplicitlyPadded` cannot be safely transmuted into `()` +} diff --git a/tests/ui/transmute/issue-115402-overflow-size.stderr b/tests/ui/transmute/issue-115402-overflow-size.stderr new file mode 100644 index 00000000000..08d180f6427 --- /dev/null +++ b/tests/ui/transmute/issue-115402-overflow-size.stderr @@ -0,0 +1,33 @@ +error[E0277]: `()` cannot be safely transmuted into `ExplicitlyPadded` in the defining scope of `assert::Context` + --> $DIR/issue-115402-overflow-size.rs:22:41 + | +LL | assert::is_maybe_transmutable::<(), ExplicitlyPadded>(); + | ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/issue-115402-overflow-size.rs:9:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, Context>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` in the defining scope of `assert::Context` + --> $DIR/issue-115402-overflow-size.rs:25:55 + | +LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); + | ^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/issue-115402-overflow-size.rs:9:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, Context>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs new file mode 100644 index 00000000000..68559338d49 --- /dev/null +++ b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs @@ -0,0 +1,16 @@ +// Regression test for #115348. + +unsafe fn uwu() {} + +// Tests that the false-positive warning "unnecessary `unsafe` block" +// should not be reported, when the error "non-exhaustive patterns" +// appears. + +fn foo(x: Option<u32>) { + match x { + //~^ ERROR non-exhaustive patterns: `None` not covered + Some(_) => unsafe { uwu() }, + } +} + +fn main() {} diff --git a/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr new file mode 100644 index 00000000000..7384899b978 --- /dev/null +++ b/tests/ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `None` not covered + --> $DIR/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs:10:11 + | +LL | match x { + | ^ pattern `None` not covered + | +note: `Option<u32>` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option<u32>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Some(_) => unsafe { uwu() }, +LL ~ None => todo!(), + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/unsized/issue-115203.rs b/tests/ui/unsized/issue-115203.rs new file mode 100644 index 00000000000..5fe7bd64288 --- /dev/null +++ b/tests/ui/unsized/issue-115203.rs @@ -0,0 +1,11 @@ +// compile-flags: --emit link + +fn main() { + let a: [i32; 0] = []; + match [a[..]] { + //~^ ERROR cannot move a value of type `[i32] + //~| ERROR cannot move out of type `[i32]`, a non-copy slice + [[]] => (), + _ => (), + } +} diff --git a/tests/ui/unsized/issue-115203.stderr b/tests/ui/unsized/issue-115203.stderr new file mode 100644 index 00000000000..3ee734988c5 --- /dev/null +++ b/tests/ui/unsized/issue-115203.stderr @@ -0,0 +1,19 @@ +error[E0161]: cannot move a value of type `[i32]` + --> $DIR/issue-115203.rs:5:12 + | +LL | match [a[..]] { + | ^^^^^ the size of `[i32]` cannot be statically determined + +error[E0508]: cannot move out of type `[i32]`, a non-copy slice + --> $DIR/issue-115203.rs:5:12 + | +LL | match [a[..]] { + | ^^^^^ + | | + | cannot move out of here + | move occurs because value has type `[i32]`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0161, E0508. +For more information about an error, try `rustc --explain E0161`. diff --git a/triagebot.toml b/triagebot.toml index 6f7efd4c3db..39c18a55697 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -585,7 +585,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "clubby789"] +users_on_vacation = ["jyn514", "clubby789", "spastorino"] [assign.adhoc_groups] compiler-team = [ @@ -626,6 +626,7 @@ rustdoc = [ "@jsha", "@GuillaumeGomez", "@notriddle", + "@fmease", ] docs = [ "@ehuss", |
