diff options
889 files changed, 8765 insertions, 4115 deletions
diff --git a/Cargo.lock b/Cargo.lock index 1296468b4e2..75c5f78e2b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -509,9 +509,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.3.1" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b" +checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" dependencies = [ "clap", ] @@ -580,7 +580,7 @@ dependencies = [ "clap", "indoc", "itertools", - "opener", + "opener 0.5.2", "shell-escape", "walkdir", ] @@ -2340,9 +2340,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.31" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b67ee4a744f36e6280792016c17e69921b51df357181d1eb17d620fcc3609f3" +checksum = "80992cb0e05f22cc052c99f8e883f1593b891014b96a8b4637fd274d7030c85e" dependencies = [ "ammonia", "anyhow", @@ -2355,7 +2355,8 @@ dependencies = [ "log", "memchr", "once_cell", - "opener", + "opener 0.6.1", + "pathdiff", "pulldown-cmark", "regex", "serde", @@ -2545,6 +2546,15 @@ dependencies = [ ] [[package]] +name = "normpath" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] name = "ntapi" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2632,6 +2642,17 @@ dependencies = [ ] [[package]] +name = "opener" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" +dependencies = [ + "bstr", + "normpath", + "winapi", +] + +[[package]] name = "openssl" version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 815edcc0dc4..050366b081f 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -14,7 +14,7 @@ use crate::{ pub trait LayoutCalculator { type TargetDataLayoutRef: Borrow<TargetDataLayout>; - fn delay_bug(&self, txt: String); + fn delayed_bug(&self, txt: String); fn current_data_layout(&self) -> Self::TargetDataLayoutRef; fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>( @@ -792,7 +792,7 @@ pub trait LayoutCalculator { let only_variant = &variants[VariantIdx::new(0)]; for field in only_variant { if field.is_unsized() { - self.delay_bug("unsized field in union".to_string()); + self.delayed_bug("unsized field in union".to_string()); } align = align.max(field.align); @@ -1038,7 +1038,7 @@ fn univariant< for &i in &inverse_memory_index { let field = &fields[i]; if !sized { - this.delay_bug(format!( + this.delayed_bug(format!( "univariant: field #{} comes after unsized field", offsets.len(), )); diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cba9121aa5a..e8731cf20f2 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2251,6 +2251,18 @@ pub enum InlineAsmOperand { }, } +impl InlineAsmOperand { + pub fn reg(&self) -> Option<&InlineAsmRegOrRegClass> { + match self { + Self::In { reg, .. } + | Self::Out { reg, .. } + | Self::InOut { reg, .. } + | Self::SplitInOut { reg, .. } => Some(reg), + Self::Const { .. } | Self::Sym { .. } => None, + } + } +} + /// Inline assembly. /// /// E.g., `asm!("NOP");`. diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 951bf41d9d7..b75a686b819 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -342,61 +342,75 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Flag to output the error only once per operand let mut skip = false; - reg.overlapping_regs(|r| { - let mut check = |used_regs: &mut FxHashMap<asm::InlineAsmReg, usize>, - input| { - match used_regs.entry(r) { - Entry::Occupied(o) => { - if skip { - return; - } - skip = true; - let idx2 = *o.get(); - let (ref op2, op_sp2) = operands[idx2]; - let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() - else { - unreachable!(); - }; + let mut check = |used_regs: &mut FxHashMap<asm::InlineAsmReg, usize>, + input, + r: asm::InlineAsmReg| { + match used_regs.entry(r) { + Entry::Occupied(o) => { + if skip { + return; + } + skip = true; - let in_out = match (op, op2) { - ( - hir::InlineAsmOperand::In { .. }, - hir::InlineAsmOperand::Out { late, .. }, - ) - | ( - hir::InlineAsmOperand::Out { late, .. }, - hir::InlineAsmOperand::In { .. }, - ) => { - assert!(!*late); - let out_op_sp = if input { op_sp2 } else { op_sp }; - Some(out_op_sp) - } - _ => None, - }; + let idx2 = *o.get(); + let (ref op2, op_sp2) = operands[idx2]; - sess.emit_err(RegisterConflict { - op_span1: op_sp, - op_span2: op_sp2, - reg1_name: reg.name(), - reg2_name: reg2.name(), - in_out, - }); - } - Entry::Vacant(v) => { - if r == reg { - v.insert(idx); + let in_out = match (op, op2) { + ( + hir::InlineAsmOperand::In { .. }, + hir::InlineAsmOperand::Out { late, .. }, + ) + | ( + hir::InlineAsmOperand::Out { late, .. }, + hir::InlineAsmOperand::In { .. }, + ) => { + assert!(!*late); + let out_op_sp = if input { op_sp2 } else { op_sp }; + Some(out_op_sp) + } + _ => None, + }; + let reg_str = |idx| -> &str { + // HIR asm doesn't preserve the original alias string of the explicit register, + // so we have to retrieve it from AST + let (op, _): &(InlineAsmOperand, Span) = &asm.operands[idx]; + if let Some(ast::InlineAsmRegOrRegClass::Reg(reg_sym)) = + op.reg() + { + reg_sym.as_str() + } else { + unreachable!(); } + }; + + sess.emit_err(RegisterConflict { + op_span1: op_sp, + op_span2: op_sp2, + reg1_name: reg_str(idx), + reg2_name: reg_str(idx2), + in_out, + }); + } + Entry::Vacant(v) => { + if r == reg { + v.insert(idx); } } - }; + } + }; + let mut overlapping_with = vec![]; + reg.overlapping_regs(|r| { + overlapping_with.push(r); + }); + for r in overlapping_with { if input { - check(&mut used_input_regs, true); + check(&mut used_input_regs, true, r); } if output { - check(&mut used_output_regs, false); + check(&mut used_output_regs, false, r); } - }); + } } } } @@ -411,12 +425,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { continue; } - let mut output_used = false; + let mut overlapping_with = vec![]; clobber.overlapping_regs(|reg| { - if used_output_regs.contains_key(®) { - output_used = true; - } + overlapping_with.push(reg); }); + let output_used = + overlapping_with.iter().any(|reg| used_output_regs.contains_key(®)); if !output_used { operands.push(( diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index be5671f1bf7..5b07299d411 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -327,7 +327,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), ExprKind::Err => hir::ExprKind::Err( - self.tcx.sess.delay_span_bug(e.span, "lowered ExprKind::Err"), + self.tcx.sess.span_delayed_bug(e.span, "lowered ExprKind::Err"), ), ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), @@ -799,7 +799,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr_ident_mut(span, task_context_ident, task_context_hid) } else { // Use of `await` outside of an async context, we cannot use `task_context` here. - self.expr_err(span, self.tcx.sess.delay_span_bug(span, "no task_context hir id")) + self.expr_err(span, self.tcx.sess.span_delayed_bug(span, "no task_context hir id")) }; let new_unchecked = self.expr_call_lang_item_fn_mut( span, diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index b6202be4f52..8fa2cae43bf 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -267,7 +267,7 @@ fn make_count<'hir>( ctx.expr( sp, hir::ExprKind::Err( - ctx.tcx.sess.delay_span_bug(sp, "lowered bad format_args count"), + ctx.tcx.sess.span_delayed_bug(sp, "lowered bad format_args count"), ), ) } @@ -306,7 +306,7 @@ fn make_format_spec<'hir>( } Err(_) => ctx.expr( sp, - hir::ExprKind::Err(ctx.tcx.sess.delay_span_bug(sp, "lowered bad format_args count")), + hir::ExprKind::Err(ctx.tcx.sess.span_delayed_bug(sp, "lowered bad format_args count")), ), }; let &FormatOptions { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c47c5fc8fcc..fbbb9d7a52a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -256,7 +256,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { - let guar = this.tcx.sess.delay_span_bug( + let guar = this.tcx.sess.span_delayed_bug( span, "expected to lower type alias type, but it was missing", ); @@ -863,7 +863,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { - let guar = this.tcx.sess.delay_span_bug( + let guar = this.tcx.sess.span_delayed_bug( i.span, "expected to lower associated type, but it was missing", ); @@ -996,7 +996,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> { match block { Some(block) => self.lower_block_expr(block), - None => self.expr_err(span, self.tcx.sess.delay_span_bug(span, "no block")), + None => self.expr_err(span, self.tcx.sess.span_delayed_bug(span, "no block")), } } @@ -1006,7 +1006,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &[], match expr { Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span, this.tcx.sess.delay_span_bug(span, "no block")), + None => this.expr_err(span, this.tcx.sess.span_delayed_bug(span, "no block")), }, ) }) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4abd0f135c6..eb6d11a72e6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,7 +54,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; +use rustc_errors::{DiagnosticArgFromDisplay, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -763,10 +763,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_import_res(id).present_items() } - fn diagnostic(&self) -> &Handler { - self.tcx.sess.diagnostic() - } - /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. fn mark_span_with_reason( @@ -1326,7 +1322,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err => { - hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered")) + hir::TyKind::Err(self.tcx.sess.span_delayed_bug(t.span, "TyKind::Err lowered")) } // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS #[allow(rustc::untranslatable_diagnostic)] @@ -1510,7 +1506,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), TyKind::CVarArgs => { - let guar = self.tcx.sess.delay_span_bug( + let guar = self.tcx.sess.span_delayed_bug( t.span, "`TyKind::CVarArgs` should have been handled elsewhere", ); @@ -1653,7 +1649,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { self.tcx .sess - .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime"); + .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); continue; } } @@ -2515,9 +2511,10 @@ impl<'hir> GenericArgsCtor<'hir> { let hir_id = lcx.next_id(); let Some(host_param_id) = lcx.host_param_id else { - lcx.tcx - .sess - .delay_span_bug(span, "no host param id for call in const yet no errors reported"); + lcx.tcx.sess.span_delayed_bug( + span, + "no host param id for call in const yet no errors reported", + ); return; }; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 8050f5826aa..db8ca7c3643 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -139,7 +139,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We should've returned in the for loop above. - self.diagnostic().span_bug( + self.tcx.sess.diagnostic().span_bug( p.span, format!( "lower_qpath: no final extension segment in {}..{}", diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 8851fbd28f0..897f35a5c4a 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -102,7 +102,7 @@ impl<'a> PostExpansionVisitor<'a> { } Err(abi::AbiDisabled::Unrecognized) => { if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { - self.sess.parse_sess.span_diagnostic.delay_span_bug( + self.sess.diagnostic().span_delayed_bug( span, format!( "unrecognized ABI not caught in lowering: {}", @@ -515,7 +515,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { } }; } - gate_all!(c_str_literals, "`c\"..\"` literals are experimental"); gate_all!( if_let_guard, "`if let` guards are experimental", @@ -628,7 +627,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) if all_stable { err.sugg = Some(attr.span); } - sess.parse_sess.span_diagnostic.emit_err(err); + sess.diagnostic().emit_err(err); } } } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 609d75733b2..a6930fe0a17 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -945,7 +945,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}"); use ReprAttr::*; let mut acc = Vec::new(); - let diagnostic = &sess.parse_sess.span_diagnostic; + let diagnostic = sess.diagnostic(); if let Some(items) = attr.meta_item_list() { for item in items { @@ -1060,9 +1060,9 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { // Not a word we recognize. This will be caught and reported by // the `check_mod_attrs` pass, but this pass doesn't always run // (e.g. if we only pretty-print the source), so we have to gate - // the `delay_span_bug` call as follows: + // the `span_delayed_bug` call as follows: if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { - diagnostic.delay_span_bug(item.span(), "unrecognized representation hint"); + diagnostic.span_delayed_bug(item.span(), "unrecognized representation hint"); } } } diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs deleted file mode 100644 index 21d367c40cb..00000000000 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ /dev/null @@ -1,248 +0,0 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] -use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::visit::TyContext; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ - Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement, - StatementKind, Terminator, TerminatorKind, UserTypeProjection, -}; -use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -use crate::{ - borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict, - region_infer::values::LivenessValues, -}; - -pub(super) fn generate_constraints<'tcx>( - infcx: &InferCtxt<'tcx>, - liveness_constraints: &mut LivenessValues, - all_facts: &mut Option<AllFacts>, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - let mut cg = ConstraintGeneration { - borrow_set, - infcx, - liveness_constraints, - location_table, - all_facts, - body, - }; - - for (bb, data) in body.basic_blocks.iter_enumerated() { - cg.visit_basic_block_data(bb, data); - } -} - -/// 'cg = the duration of the constraint generation process itself. -struct ConstraintGeneration<'cg, 'tcx> { - infcx: &'cg InferCtxt<'tcx>, - all_facts: &'cg mut Option<AllFacts>, - location_table: &'cg LocationTable, - liveness_constraints: &'cg mut LivenessValues, - borrow_set: &'cg BorrowSet<'tcx>, - body: &'cg Body<'tcx>, -} - -impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> { - /// We sometimes have `args` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) { - self.add_regular_live_constraint(*args, location); - self.super_args(args); - } - - /// We sometimes have `region` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_region(&mut self, region: ty::Region<'tcx>, location: Location) { - self.add_regular_live_constraint(region, location); - self.super_region(region); - } - - /// We sometimes have `ty` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) { - match ty_context { - TyContext::ReturnTy(SourceInfo { span, .. }) - | TyContext::YieldTy(SourceInfo { span, .. }) - | TyContext::UserTy(span) - | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { - span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); - } - TyContext::Location(location) => { - self.add_regular_live_constraint(ty, location); - } - } - - self.super_ty(ty); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let Some(all_facts) = self.all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - all_facts.cfg_edge.push(( - self.location_table.start_index(location), - self.location_table.mid_index(location), - )); - - all_facts.cfg_edge.push(( - self.location_table.mid_index(location), - self.location_table.start_index(location.successor_within_block()), - )); - - // If there are borrows on this now dead local, we need to record them as `killed`. - if let StatementKind::StorageDead(local) = statement.kind { - record_killed_borrows_for_local( - all_facts, - self.borrow_set, - self.location_table, - local, - location, - ); - } - } - - self.super_statement(statement, location); - } - - fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - // When we see `X = ...`, then kill borrows of - // `(*X).foo` and so forth. - self.record_killed_borrows_for_place(*place, location); - - self.super_assign(place, rvalue, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - if let Some(all_facts) = self.all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - all_facts.cfg_edge.push(( - self.location_table.start_index(location), - self.location_table.mid_index(location), - )); - - let successor_blocks = terminator.successors(); - all_facts.cfg_edge.reserve(successor_blocks.size_hint().0); - for successor_block in successor_blocks { - all_facts.cfg_edge.push(( - self.location_table.mid_index(location), - self.location_table.start_index(successor_block.start_location()), - )); - } - } - - // A `Call` terminator's return value can be a local which has borrows, - // so we need to record those as `killed` as well. - if let TerminatorKind::Call { destination, .. } = terminator.kind { - self.record_killed_borrows_for_place(destination, location); - } - - self.super_terminator(terminator, location); - } - - fn visit_ascribe_user_ty( - &mut self, - _place: &Place<'tcx>, - _variance: ty::Variance, - _user_ty: &UserTypeProjection, - _location: Location, - ) { - } -} - -impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> { - /// Some variable with type `live_ty` is "regular live" at - /// `location` -- i.e., it may be used later. This means that all - /// regions appearing in the type `live_ty` must be live at - /// `location`. - fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location) - where - T: TypeVisitable<TyCtxt<'tcx>>, - { - debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location); - - self.infcx.tcx.for_each_free_region(&live_ty, |live_region| { - let vid = live_region.as_var(); - self.liveness_constraints.add_location(vid, location); - }); - } - - /// When recording facts for Polonius, records the borrows on the specified place - /// as `killed`. For example, when assigning to a local, or on a call's return destination. - fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) { - if let Some(all_facts) = self.all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - - // Depending on the `Place` we're killing: - // - if it's a local, or a single deref of a local, - // we kill all the borrows on the local. - // - if it's a deeper projection, we have to filter which - // of the borrows are killed: the ones whose `borrowed_place` - // conflicts with the `place`. - match place.as_ref() { - PlaceRef { local, projection: &[] } - | PlaceRef { local, projection: &[ProjectionElem::Deref] } => { - debug!( - "Recording `killed` facts for borrows of local={:?} at location={:?}", - local, location - ); - - record_killed_borrows_for_local( - all_facts, - self.borrow_set, - self.location_table, - local, - location, - ); - } - - PlaceRef { local, projection: &[.., _] } => { - // Kill conflicting borrows of the innermost local. - debug!( - "Recording `killed` facts for borrows of \ - innermost projected local={:?} at location={:?}", - local, location - ); - - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { - for &borrow_index in borrow_indices { - let places_conflict = places_conflict::places_conflict( - self.infcx.tcx, - self.body, - self.borrow_set[borrow_index].borrowed_place, - place, - places_conflict::PlaceConflictBias::NoOverlap, - ); - - if places_conflict { - let location_index = self.location_table.mid_index(location); - all_facts.loan_killed_at.push((borrow_index, location_index)); - } - } - } - } - } - } - } -} - -/// When recording facts for Polonius, records the borrows on the specified local as `killed`. -fn record_killed_borrows_for_local( - all_facts: &mut AllFacts, - borrow_set: &BorrowSet<'_>, - location_table: &LocationTable, - local: Local, - location: Location, -) { - if let Some(borrow_indices) = borrow_set.local_map.get(&local) { - all_facts.loan_killed_at.reserve(borrow_indices.len()); - for &borrow_index in borrow_indices { - let location_index = location_table.mid_index(location); - all_facts.loan_killed_at.push((borrow_index, location_index)); - } - } -} diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index b3d14c1beb5..54f161ea9b4 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -432,7 +432,8 @@ impl<'mir, 'tcx> Borrows<'mir, 'tcx> { assert_eq!( borrows_out_of_scope_at_location, polonius_prec.loans_out_of_scope_at_location, - "the loans out of scope must be the same as the borrows out of scope" + "polonius loan scopes differ from NLL borrow scopes, for body {:?}", + body.span, ); borrows_out_of_scope_at_location = polonius_prec.loans_out_of_scope_at_location; diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 03172ef34b9..924e68fa91d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -385,7 +385,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { // We generally shouldn't have errors here because the query was - // already run, but there's no point using `delay_span_bug` + // already run, but there's no point using `span_delayed_bug` // when we're going to emit an error here anyway. let _errors = ocx.select_all_or_error(); let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone()); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index ef4bf543454..7bcad92ff33 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1135,7 +1135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }); } else { issued_spans.var_subdiag( - Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic), + Some(self.infcx.tcx.sess.diagnostic()), &mut err, Some(issued_borrow.kind), |kind, var_span| { @@ -1152,7 +1152,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); borrow_spans.var_subdiag( - Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic), + Some(self.infcx.tcx.sess.diagnostic()), &mut err, Some(gen_borrow_kind), |kind, var_span| { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index e37457f48df..4deed98d002 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -124,7 +124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { diag.eager_subdiagnostic( - &self.infcx.tcx.sess.parse_sess.span_diagnostic, + self.infcx.tcx.sess.diagnostic(), OnClosureNote::InvokedTwice { place_name: &ty::place_to_string_for_capture( self.infcx.tcx, @@ -146,7 +146,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { diag.eager_subdiagnostic( - &self.infcx.tcx.sess.parse_sess.span_diagnostic, + self.infcx.tcx.sess.diagnostic(), OnClosureNote::MovedTwice { place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), span: *span, @@ -1119,7 +1119,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && self.infcx.can_eq(self.param_env, ty, self_ty) { err.eager_subdiagnostic( - &self.infcx.tcx.sess.parse_sess.span_diagnostic, + self.infcx.tcx.sess.diagnostic(), CaptureReasonSuggest::FreshReborrow { span: move_span.shrink_to_hi(), }, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 40bbc5e7c41..759f5e910f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -84,7 +84,7 @@ impl<'tcx> RegionErrors<'tcx> { #[track_caller] pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) { let val = val.into(); - self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}")); + self.1.sess.span_delayed_bug(DUMMY_SP, format!("{val:?}")); self.0.push(val); } pub fn is_empty(&self) -> bool { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 730b65898bc..977a5d5d50d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -619,8 +619,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { _, ) => { // HIR lowering sometimes doesn't catch this in erroneous - // programs, so we need to use delay_span_bug here. See #82126. - self.infcx.tcx.sess.delay_span_bug( + // programs, so we need to use span_delayed_bug here. See #82126. + self.infcx.tcx.sess.span_delayed_bug( hir_arg.span(), format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), ); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 6e44f44dc18..3d3fd412ae0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -65,19 +65,18 @@ use self::path_utils::*; pub mod borrow_set; mod borrowck_errors; -mod constraint_generation; mod constraints; mod dataflow; mod def_use; mod diagnostics; mod facts; -mod invalidation; mod location; mod member_constraints; mod nll; mod path_utils; mod place_ext; mod places_conflict; +mod polonius; mod prefixes; mod region_infer; mod renumber; @@ -195,8 +194,7 @@ fn do_mir_borrowck<'tcx>( nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes - let location_table_owned = LocationTable::new(body); - let location_table = &location_table_owned; + let location_table = LocationTable::new(body); let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); let promoted_move_data = promoted @@ -228,7 +226,7 @@ fn do_mir_borrowck<'tcx>( free_regions, body, &promoted, - location_table, + &location_table, param_env, &mut flow_inits, &mdpe.move_data, @@ -292,7 +290,7 @@ fn do_mir_borrowck<'tcx>( param_env, body: promoted_body, move_data: &move_data, - location_table, // no need to create a real one for the promoted, it is not used + location_table: &location_table, // no need to create a real one for the promoted, it is not used movable_coroutine, fn_self_span_reported: Default::default(), locals_are_invalidated_at_exit, @@ -333,7 +331,7 @@ fn do_mir_borrowck<'tcx>( param_env, body, move_data: &mdpe.move_data, - location_table, + location_table: &location_table, movable_coroutine, locals_are_invalidated_at_exit, fn_self_span_reported: Default::default(), @@ -435,7 +433,7 @@ fn do_mir_borrowck<'tcx>( promoted, borrow_set, region_inference_context: regioncx, - location_table: polonius_input.as_ref().map(|_| location_table_owned), + location_table: polonius_input.as_ref().map(|_| location_table), input_facts: polonius_input, output_facts, })) @@ -1020,9 +1018,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { flow_state: &Flows<'cx, 'tcx>, ) -> bool { let mut error_reported = false; - let tcx = self.infcx.tcx; - let body = self.body; - let borrow_set = self.borrow_set.clone(); + let borrow_set = Rc::clone(&self.borrow_set); // Use polonius output if it has been enabled. let mut polonius_output; @@ -1039,8 +1035,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { each_borrow_involving_path( self, - tcx, - body, + self.infcx.tcx, + self.body, location, (sd, place_span.0), &borrow_set, @@ -2134,11 +2130,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && !self.has_buffered_errors() { // rust-lang/rust#46908: In pure NLL mode this code path should be - // unreachable, but we use `delay_span_bug` because we can hit this when + // unreachable, but we use `span_delayed_bug` because we can hit this when // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug` // enabled. We don't want to ICE for that case, as other errors will have // been emitted (#52262). - self.infcx.tcx.sess.delay_span_bug( + self.infcx.tcx.sess.span_delayed_bug( span, format!( "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible", @@ -2432,7 +2428,7 @@ mod error { pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) { if let None = self.tainted_by_errors { - self.tainted_by_errors = Some(self.tcx.sess.delay_span_bug( + self.tainted_by_errors = Some(self.tcx.sess.span_delayed_bug( t.span.clone_ignoring_labels(), "diagnostic buffered but not emitted", )) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 480358ef997..c88d9d81fe1 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -2,16 +2,17 @@ #![deny(rustc::diagnostic_outside_of_impl)] //! The entry point of the NLL borrow checker. +use polonius_engine::{Algorithm, Output}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::LocalDefId; use rustc_index::IndexSlice; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; -use rustc_middle::mir::{ - Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, - START_BLOCK, -}; +use rustc_middle::mir::{Body, ClosureOutlivesSubject, ClosureRegionRequirements, Promoted}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::ResultsCursor; use rustc_span::symbol::sym; use std::env; use std::io; @@ -19,20 +20,13 @@ use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; -use polonius_engine::{Algorithm, Output}; - -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; -use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; -use rustc_mir_dataflow::ResultsCursor; - use crate::{ borrow_set::BorrowSet, - constraint_generation, consumers::ConsumerOptions, diagnostics::RegionErrors, facts::{AllFacts, AllFactsExt, RustcFacts}, - invalidation, location::LocationTable, + polonius, region_infer::{values::RegionValueElements, RegionInferenceContext}, renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, @@ -78,81 +72,6 @@ pub(crate) fn replace_regions_in_mir<'tcx>( universal_regions } -// This function populates an AllFacts instance with base facts related to -// MovePaths and needed for the move analysis. -fn populate_polonius_move_facts( - all_facts: &mut AllFacts, - move_data: &MoveData<'_>, - location_table: &LocationTable, - body: &Body<'_>, -) { - all_facts - .path_is_var - .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); - - for (child, move_path) in move_data.move_paths.iter_enumerated() { - if let Some(parent) = move_path.parent { - all_facts.child_path.push((child, parent)); - } - } - - let fn_entry_start = - location_table.start_index(Location { block: START_BLOCK, statement_index: 0 }); - - // initialized_at - for init in move_data.inits.iter() { - match init.location { - InitLocation::Statement(location) => { - let block_data = &body[location.block]; - let is_terminator = location.statement_index == block_data.statements.len(); - - if is_terminator && init.kind == InitKind::NonPanicPathOnly { - // We are at the terminator of an init that has a panic path, - // and where the init should not happen on panic - - for successor in block_data.terminator().successors() { - if body[successor].is_cleanup { - continue; - } - - // The initialization happened in (or rather, when arriving at) - // the successors, but not in the unwind block. - let first_statement = Location { block: successor, statement_index: 0 }; - all_facts - .path_assigned_at_base - .push((init.path, location_table.start_index(first_statement))); - } - } else { - // In all other cases, the initialization just happens at the - // midpoint, like any other effect. - all_facts - .path_assigned_at_base - .push((init.path, location_table.mid_index(location))); - } - } - // Arguments are initialized on function entry - InitLocation::Argument(local) => { - assert!(body.local_kind(local) == LocalKind::Arg); - all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); - } - } - } - - for (local, path) in move_data.rev_lookup.iter_locals_enumerated() { - if body.local_kind(local) != LocalKind::Arg { - // Non-arguments start out deinitialised; we simulate this with an - // initial move: - all_facts.path_moved_at_base.push((path, fn_entry_start)); - } - } - - // moved_out_at - // deinitialisation is assumed to always happen! - all_facts - .path_moved_at_base - .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); -} - /// Computes the (non-lexical) regions from the input MIR. /// /// This may result in errors being reported. @@ -182,67 +101,23 @@ pub(crate) fn compute_regions<'cx, 'tcx>( let elements = &Rc::new(RegionValueElements::new(body)); // Run the MIR type-checker. - let MirTypeckResults { - constraints, - universal_region_relations, - opaque_type_values, - live_loans, - } = type_check::type_check( - infcx, - param_env, - body, - promoted, - &universal_regions, - location_table, - borrow_set, - &mut all_facts, - flow_inits, - move_data, - elements, - upvars, - polonius_input, - ); - - if let Some(all_facts) = &mut all_facts { - let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); - all_facts.universal_region.extend(universal_regions.universal_regions()); - populate_polonius_move_facts(all_facts, move_data, location_table, body); - - // Emit universal regions facts, and their relations, for Polonius. - // - // 1: universal regions are modeled in Polonius as a pair: - // - the universal region vid itself. - // - a "placeholder loan" associated to this universal region. Since they don't exist in - // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index - // added to the existing number of loans, as if they succeeded them in the set. - // - let borrow_count = borrow_set.len(); - debug!( - "compute_regions: polonius placeholders, num_universals={}, borrow_count={}", - universal_regions.len(), - borrow_count + let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = + type_check::type_check( + infcx, + param_env, + body, + promoted, + &universal_regions, + location_table, + borrow_set, + &mut all_facts, + flow_inits, + move_data, + elements, + upvars, + polonius_input, ); - for universal_region in universal_regions.universal_regions() { - let universal_region_idx = universal_region.index(); - let placeholder_loan_idx = borrow_count + universal_region_idx; - all_facts.placeholder.push((universal_region, placeholder_loan_idx.into())); - } - - // 2: the universal region relations `outlives` constraints are emitted as - // `known_placeholder_subset` facts. - for (fr1, fr2) in universal_region_relations.known_outlives() { - if fr1 != fr2 { - debug!( - "compute_regions: emitting polonius `known_placeholder_subset` \ - fr1={:?}, fr2={:?}", - fr1, fr2 - ); - all_facts.known_placeholder_subset.push((fr1, fr2)); - } - } - } - // Create the region inference context, taking ownership of the // region inference data that was contained in `infcx`, and the // base constraints generated by the type-check. @@ -250,7 +125,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( let MirTypeckRegionConstraints { placeholder_indices, placeholder_index_to_region: _, - mut liveness_constraints, + liveness_constraints, outlives_constraints, member_constraints, universe_causes, @@ -258,13 +133,16 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } = constraints; let placeholder_indices = Rc::new(placeholder_indices); - constraint_generation::generate_constraints( - infcx, - &mut liveness_constraints, + // If requested, emit legacy polonius facts. + polonius::emit_facts( &mut all_facts, + infcx.tcx, location_table, body, borrow_set, + move_data, + &universal_regions, + &universal_region_relations, ); let mut regioncx = RegionInferenceContext::new( @@ -279,17 +157,12 @@ pub(crate) fn compute_regions<'cx, 'tcx>( type_tests, liveness_constraints, elements, - live_loans, ); - // Generate various additional constraints. - invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set); - - let def_id = body.source.def_id(); - - // Dump facts if requested. + // If requested: dump NLL facts, and run legacy polonius analysis. let polonius_output = all_facts.as_ref().and_then(|all_facts| { if infcx.tcx.sess.opts.unstable_opts.nll_facts { + let def_id = body.source.def_id(); let def_path = infcx.tcx.def_path(def_id); let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir) .join(def_path.to_filename_friendly_no_crate()); @@ -314,7 +187,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( if !nll_errors.is_empty() { // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(infcx.tcx.sess.delay_span_bug( + infcx.set_tainted_by_errors(infcx.tcx.sess.span_delayed_bug( body.span, "`compute_regions` tainted `infcx` with errors but did not emit any errors", )); @@ -407,7 +280,7 @@ pub(super) fn dump_annotation<'tcx>( let def_span = tcx.def_span(body.source.def_id()); let mut err = if let Some(closure_region_requirements) = closure_region_requirements { - let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "external requirements"); + let mut err = tcx.sess.diagnostic().struct_span_note(def_span, "external requirements"); regioncx.annotate(tcx, &mut err); @@ -426,7 +299,7 @@ pub(super) fn dump_annotation<'tcx>( err } else { - let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "no external requirements"); + let mut err = tcx.sess.diagnostic().struct_span_note(def_span, "no external requirements"); regioncx.annotate(tcx, &mut err); err diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index a3db101311f..232bd741825 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -14,34 +14,21 @@ use crate::{ ReadOrWrite, Reservation, Shallow, Write, WriteKind, }; -pub(super) fn generate_invalidates<'tcx>( +/// Emit `loan_invalidated_at` facts. +pub(super) fn emit_loan_invalidations<'tcx>( tcx: TyCtxt<'tcx>, - all_facts: &mut Option<AllFacts>, + all_facts: &mut AllFacts, location_table: &LocationTable, body: &Body<'tcx>, borrow_set: &BorrowSet<'tcx>, ) { - if all_facts.is_none() { - // Nothing to do if we don't have any facts - return; - } - - if let Some(all_facts) = all_facts { - let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - let dominators = body.basic_blocks.dominators(); - let mut ig = InvalidationGenerator { - all_facts, - borrow_set, - tcx, - location_table, - body: body, - dominators, - }; - ig.visit_body(body); - } + let dominators = body.basic_blocks.dominators(); + let mut visitor = + LoanInvalidationsGenerator { all_facts, borrow_set, tcx, location_table, body, dominators }; + visitor.visit_body(body); } -struct InvalidationGenerator<'cx, 'tcx> { +struct LoanInvalidationsGenerator<'cx, 'tcx> { tcx: TyCtxt<'tcx>, all_facts: &'cx mut AllFacts, location_table: &'cx LocationTable, @@ -52,7 +39,7 @@ struct InvalidationGenerator<'cx, 'tcx> { /// Visits the whole MIR and generates `invalidates()` facts. /// Most of the code implementing this was stolen from `borrow_check/mod.rs`. -impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { +impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { self.check_activations(location); @@ -214,7 +201,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } -impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { +impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { /// Simulates mutation of a place. fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) { self.access_place( @@ -348,20 +335,16 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { rw: ReadOrWrite, ) { debug!( - "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \ - rw={:?})", + "check_access_for_conflict(location={:?}, place={:?}, sd={:?}, rw={:?})", location, place, sd, rw, ); - let tcx = self.tcx; - let body = self.body; - let borrow_set = self.borrow_set; each_borrow_involving_path( self, - tcx, - body, + self.tcx, + self.body, location, (sd, place), - borrow_set, + self.borrow_set, |_| true, |this, borrow_index, borrow| { match (rw, borrow.kind) { diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs new file mode 100644 index 00000000000..5df94383702 --- /dev/null +++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs @@ -0,0 +1,147 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{ + Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, + Terminator, TerminatorKind, +}; +use rustc_middle::ty::TyCtxt; + +use crate::{borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict}; + +/// Emit `loan_killed_at` and `cfg_edge` facts at the same time. +pub(super) fn emit_loan_kills<'tcx>( + tcx: TyCtxt<'tcx>, + all_facts: &mut AllFacts, + location_table: &LocationTable, + body: &Body<'tcx>, + borrow_set: &BorrowSet<'tcx>, +) { + let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, all_facts, body }; + for (bb, data) in body.basic_blocks.iter_enumerated() { + visitor.visit_basic_block_data(bb, data); + } +} + +struct LoanKillsGenerator<'cx, 'tcx> { + tcx: TyCtxt<'tcx>, + all_facts: &'cx mut AllFacts, + location_table: &'cx LocationTable, + borrow_set: &'cx BorrowSet<'tcx>, + body: &'cx Body<'tcx>, +} + +impl<'cx, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'cx, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // Also record CFG facts here. + self.all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + self.all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table.start_index(location.successor_within_block()), + )); + + // If there are borrows on this now dead local, we need to record them as `killed`. + if let StatementKind::StorageDead(local) = statement.kind { + self.record_killed_borrows_for_local(local, location); + } + + self.super_statement(statement, location); + } + + fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + // When we see `X = ...`, then kill borrows of + // `(*X).foo` and so forth. + self.record_killed_borrows_for_place(*place, location); + self.super_assign(place, rvalue, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // Also record CFG facts here. + self.all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + let successor_blocks = terminator.successors(); + self.all_facts.cfg_edge.reserve(successor_blocks.size_hint().0); + for successor_block in successor_blocks { + self.all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table.start_index(successor_block.start_location()), + )); + } + + // A `Call` terminator's return value can be a local which has borrows, + // so we need to record those as `killed` as well. + if let TerminatorKind::Call { destination, .. } = terminator.kind { + self.record_killed_borrows_for_place(destination, location); + } + + self.super_terminator(terminator, location); + } +} + +impl<'tcx> LoanKillsGenerator<'_, 'tcx> { + /// Records the borrows on the specified place as `killed`. For example, when assigning to a + /// local, or on a call's return destination. + fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) { + // Depending on the `Place` we're killing: + // - if it's a local, or a single deref of a local, + // we kill all the borrows on the local. + // - if it's a deeper projection, we have to filter which + // of the borrows are killed: the ones whose `borrowed_place` + // conflicts with the `place`. + match place.as_ref() { + PlaceRef { local, projection: &[] } + | PlaceRef { local, projection: &[ProjectionElem::Deref] } => { + debug!( + "Recording `killed` facts for borrows of local={:?} at location={:?}", + local, location + ); + + self.record_killed_borrows_for_local(local, location); + } + + PlaceRef { local, projection: &[.., _] } => { + // Kill conflicting borrows of the innermost local. + debug!( + "Recording `killed` facts for borrows of \ + innermost projected local={:?} at location={:?}", + local, location + ); + + if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { + for &borrow_index in borrow_indices { + let places_conflict = places_conflict::places_conflict( + self.tcx, + self.body, + self.borrow_set[borrow_index].borrowed_place, + place, + places_conflict::PlaceConflictBias::NoOverlap, + ); + + if places_conflict { + let location_index = self.location_table.mid_index(location); + self.all_facts.loan_killed_at.push((borrow_index, location_index)); + } + } + } + } + } + } + + /// Records the borrows on the specified local as `killed`. + fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) { + if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { + let location_index = self.location_table.mid_index(location); + self.all_facts.loan_killed_at.reserve(borrow_indices.len()); + for &borrow_index in borrow_indices { + self.all_facts.loan_killed_at.push((borrow_index, location_index)); + } + } + } +} diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs new file mode 100644 index 00000000000..40126d50d57 --- /dev/null +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -0,0 +1,188 @@ +//! Functions dedicated to fact generation for the `-Zpolonius=legacy` datalog implementation. +//! +//! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature +//! parity. + +use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK}; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; + +use crate::borrow_set::BorrowSet; +use crate::facts::AllFacts; +use crate::location::LocationTable; +use crate::type_check::free_region_relations::UniversalRegionRelations; +use crate::universal_regions::UniversalRegions; + +mod loan_invalidations; +mod loan_kills; + +/// When requested, emit most of the facts needed by polonius: +/// - moves and assignments +/// - universal regions and their relations +/// - CFG points and edges +/// - loan kills +/// - loan invalidations +/// +/// The rest of the facts are emitted during typeck and liveness. +pub(crate) fn emit_facts<'tcx>( + all_facts: &mut Option<AllFacts>, + tcx: TyCtxt<'tcx>, + location_table: &LocationTable, + body: &Body<'tcx>, + borrow_set: &BorrowSet<'tcx>, + move_data: &MoveData<'_>, + universal_regions: &UniversalRegions<'_>, + universal_region_relations: &UniversalRegionRelations<'_>, +) { + let Some(all_facts) = all_facts else { + // We don't do anything if there are no facts to fill. + return; + }; + let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); + emit_move_facts(all_facts, move_data, location_table, body); + emit_universal_region_facts( + all_facts, + borrow_set, + &universal_regions, + &universal_region_relations, + ); + emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); + emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); +} + +/// Emit facts needed for move/init analysis: moves and assignments. +fn emit_move_facts( + all_facts: &mut AllFacts, + move_data: &MoveData<'_>, + location_table: &LocationTable, + body: &Body<'_>, +) { + all_facts + .path_is_var + .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); + + for (child, move_path) in move_data.move_paths.iter_enumerated() { + if let Some(parent) = move_path.parent { + all_facts.child_path.push((child, parent)); + } + } + + let fn_entry_start = + location_table.start_index(Location { block: START_BLOCK, statement_index: 0 }); + + // initialized_at + for init in move_data.inits.iter() { + match init.location { + InitLocation::Statement(location) => { + let block_data = &body[location.block]; + let is_terminator = location.statement_index == block_data.statements.len(); + + if is_terminator && init.kind == InitKind::NonPanicPathOnly { + // We are at the terminator of an init that has a panic path, + // and where the init should not happen on panic + + for successor in block_data.terminator().successors() { + if body[successor].is_cleanup { + continue; + } + + // The initialization happened in (or rather, when arriving at) + // the successors, but not in the unwind block. + let first_statement = Location { block: successor, statement_index: 0 }; + all_facts + .path_assigned_at_base + .push((init.path, location_table.start_index(first_statement))); + } + } else { + // In all other cases, the initialization just happens at the + // midpoint, like any other effect. + all_facts + .path_assigned_at_base + .push((init.path, location_table.mid_index(location))); + } + } + // Arguments are initialized on function entry + InitLocation::Argument(local) => { + assert!(body.local_kind(local) == LocalKind::Arg); + all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); + } + } + } + + for (local, path) in move_data.rev_lookup.iter_locals_enumerated() { + if body.local_kind(local) != LocalKind::Arg { + // Non-arguments start out deinitialised; we simulate this with an + // initial move: + all_facts.path_moved_at_base.push((path, fn_entry_start)); + } + } + + // moved_out_at + // deinitialisation is assumed to always happen! + all_facts + .path_moved_at_base + .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); +} + +/// Emit universal regions facts, and their relations. +fn emit_universal_region_facts( + all_facts: &mut AllFacts, + borrow_set: &BorrowSet<'_>, + universal_regions: &UniversalRegions<'_>, + universal_region_relations: &UniversalRegionRelations<'_>, +) { + // 1: universal regions are modeled in Polonius as a pair: + // - the universal region vid itself. + // - a "placeholder loan" associated to this universal region. Since they don't exist in + // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index + // added to the existing number of loans, as if they succeeded them in the set. + // + all_facts.universal_region.extend(universal_regions.universal_regions()); + let borrow_count = borrow_set.len(); + debug!( + "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}", + universal_regions.len(), + borrow_count + ); + + for universal_region in universal_regions.universal_regions() { + let universal_region_idx = universal_region.index(); + let placeholder_loan_idx = borrow_count + universal_region_idx; + all_facts.placeholder.push((universal_region, placeholder_loan_idx.into())); + } + + // 2: the universal region relations `outlives` constraints are emitted as + // `known_placeholder_subset` facts. + for (fr1, fr2) in universal_region_relations.known_outlives() { + if fr1 != fr2 { + debug!( + "emit_universal_region_facts: emitting polonius `known_placeholder_subset` \ + fr1={:?}, fr2={:?}", + fr1, fr2 + ); + all_facts.known_placeholder_subset.push((fr1, fr2)); + } + } +} + +/// Emit facts about loan invalidations. +fn emit_loan_invalidations_facts<'tcx>( + all_facts: &mut AllFacts, + tcx: TyCtxt<'tcx>, + location_table: &LocationTable, + body: &Body<'tcx>, + borrow_set: &BorrowSet<'tcx>, +) { + loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set); +} + +/// Emit facts about CFG points and edges, as well as locations where loans are killed. +fn emit_cfg_and_loan_kills_facts<'tcx>( + all_facts: &mut AllFacts, + tcx: TyCtxt<'tcx>, + location_table: &LocationTable, + body: &Body<'tcx>, + borrow_set: &BorrowSet<'tcx>, +) { + loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set); +} diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 1c082b7a56c..b308cd82e54 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_errors::Diagnostic; use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_index::bit_set::SparseBitMatrix; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::outlives::test_type_match; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; @@ -31,8 +30,8 @@ use crate::{ nll::PoloniusOutput, region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ - LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements, - RegionValues, ToElementIndex, + LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, + ToElementIndex, }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, @@ -120,9 +119,6 @@ pub struct RegionInferenceContext<'tcx> { /// Information about how the universally quantified regions in /// scope on this function relate to one another. universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - - /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`. - live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, } /// Each time that `apply_member_constraint` is successful, it appends @@ -335,7 +331,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { type_tests: Vec<TypeTest<'tcx>>, liveness_constraints: LivenessValues, elements: &Rc<RegionValueElements>, - live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); @@ -389,7 +384,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { type_tests, universal_regions, universal_region_relations, - live_loans, }; result.init_free_and_bound_regions(); @@ -2325,7 +2319,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`. pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool { let point = self.liveness_constraints.point_from_location(location); - self.live_loans.contains(point, loan_idx) + self.liveness_constraints.is_loan_live_at(loan_idx, point) } } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 41ae65268f2..dc3ee849d00 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -11,6 +11,8 @@ use rustc_middle::ty::{self, RegionVid}; use std::fmt::Debug; use std::rc::Rc; +use crate::dataflow::BorrowIndex; + /// Maps between a `Location` and a `PointIndex` (and vice versa). pub(crate) struct RegionValueElements { /// For each basic block, how many points are contained within? @@ -120,14 +122,45 @@ pub(crate) enum RegionElement { /// Records the CFG locations where each region is live. When we initially compute liveness, we use /// an interval matrix storing liveness ranges for each region-vid. pub(crate) struct LivenessValues { + /// The map from locations to points. elements: Rc<RegionValueElements>, + + /// For each region: the points where it is live. points: SparseIntervalMatrix<RegionVid, PointIndex>, + + /// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at + /// that point. + pub(crate) loans: Option<LiveLoans>, +} + +/// Data used to compute the loans that are live at a given point in the CFG, when using +/// `-Zpolonius=next`. +pub(crate) struct LiveLoans { + /// The set of loans that flow into a given region. When individual regions are marked as live + /// in the CFG, these inflowing loans are recorded as live. + pub(crate) inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>, + + /// The set of loans that are live at a given point in the CFG. + pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, +} + +impl LiveLoans { + pub(crate) fn new(num_loans: usize) -> Self { + LiveLoans { + live_loans: SparseBitMatrix::new(num_loans), + inflowing_loans: SparseBitMatrix::new(num_loans), + } + } } impl LivenessValues { /// Create an empty map of regions to locations where they're live. pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self { - Self { points: SparseIntervalMatrix::new(elements.num_points), elements } + LivenessValues { + points: SparseIntervalMatrix::new(elements.num_points), + elements, + loans: None, + } } /// Iterate through each region that has a value in this set. @@ -140,12 +173,30 @@ impl LivenessValues { debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); let point = self.elements.point_from_location(location); self.points.insert(region, point); + + // When available, record the loans flowing into this region as live at the given point. + if let Some(loans) = self.loans.as_mut() { + if let Some(inflowing) = loans.inflowing_loans.row(region) { + loans.live_loans.union_row(point, inflowing); + } + } } /// Records `region` as being live at all the given `points`. pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); self.points.union_row(region, points); + + // When available, record the loans flowing into this region as live at the given points. + if let Some(loans) = self.loans.as_mut() { + if let Some(inflowing) = loans.inflowing_loans.row(region) { + if !inflowing.is_empty() { + for point in points.iter() { + loans.live_loans.union_row(point, inflowing); + } + } + } + } } /// Records `region` as being live at all the control-flow points. @@ -185,6 +236,15 @@ impl LivenessValues { pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { self.elements.point_from_location(location) } + + /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`. + pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool { + self.loans + .as_ref() + .expect("Accessing live loans requires `-Zpolonius=next`") + .live_loans + .contains(point, loan_idx) + } } /// Maps from `ty::PlaceholderRegion` values that are used in the rest of diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 28cc8be8ac9..8e141bb3864 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if argument_index + 1 >= body.local_decls.len() { self.tcx() .sess - .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); + .span_delayed_bug(body.span, "found more normalized_input_ty than local_decls"); break; } @@ -101,10 +101,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); // We will not have a universal_regions.yield_ty if we yield (by accident) - // outside of a coroutine and return an `impl Trait`, so emit a delay_span_bug + // outside of a coroutine and return an `impl Trait`, so emit a span_delayed_bug // because we don't want to panic in an assert here if we've already got errors. if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() { - self.tcx().sess.delay_span_bug( + self.tcx().sess.span_delayed_bug( body.span, format!( "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})", diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index a970dadc479..dc4695fd2b0 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -1,7 +1,9 @@ use itertools::{Either, Itertools}; use rustc_data_structures::fx::FxHashSet; -use rustc_middle::mir::{Body, Local}; -use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_middle::mir::visit::{TyContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location, SourceInfo}; +use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; @@ -11,7 +13,7 @@ use crate::{ constraints::OutlivesConstraintSet, facts::{AllFacts, AllFactsExt}, location::LocationTable, - region_infer::values::RegionValueElements, + region_infer::values::{LivenessValues, RegionValueElements}, universal_regions::UniversalRegions, }; @@ -65,6 +67,14 @@ pub(super) fn generate<'mir, 'tcx>( boring_locals, polonius_drop_used, ); + + // Mark regions that should be live where they appear within rvalues or within a call: like + // args, regions, and types. + record_regular_live_regions( + typeck.tcx(), + &mut typeck.borrowck_context.constraints.liveness_constraints, + body, + ); } // The purpose of `compute_relevant_live_locals` is to define the subset of `Local` @@ -132,3 +142,71 @@ fn regions_that_outlive_free_regions<'tcx>( // Return the final set of things we visited. outlives_free_region } + +/// Some variables are "regular live" at `location` -- i.e., they may be used later. This means that +/// all regions appearing in their type must be live at `location`. +fn record_regular_live_regions<'tcx>( + tcx: TyCtxt<'tcx>, + liveness_constraints: &mut LivenessValues, + body: &Body<'tcx>, +) { + let mut visitor = LiveVariablesVisitor { tcx, liveness_constraints }; + for (bb, data) in body.basic_blocks.iter_enumerated() { + visitor.visit_basic_block_data(bb, data); + } +} + +/// Visitor looking for regions that should be live within rvalues or calls. +struct LiveVariablesVisitor<'cx, 'tcx> { + tcx: TyCtxt<'tcx>, + liveness_constraints: &'cx mut LivenessValues, +} + +impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { + /// We sometimes have `args` within an rvalue, or within a + /// call. Make them live at the location where they appear. + fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) { + self.record_regions_live_at(*args, location); + self.super_args(args); + } + + /// We sometimes have `region`s within an rvalue, or within a + /// call. Make them live at the location where they appear. + fn visit_region(&mut self, region: Region<'tcx>, location: Location) { + self.record_regions_live_at(region, location); + self.super_region(region); + } + + /// We sometimes have `ty`s within an rvalue, or within a + /// call. Make them live at the location where they appear. + fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) { + match ty_context { + TyContext::ReturnTy(SourceInfo { span, .. }) + | TyContext::YieldTy(SourceInfo { span, .. }) + | TyContext::UserTy(span) + | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { + span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); + } + TyContext::Location(location) => { + self.record_regions_live_at(ty, location); + } + } + + self.super_ty(ty); + } +} + +impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> { + /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that + /// all regions appearing in the type of `value` must be live at `location`. + fn record_regions_live_at<T>(&mut self, value: T, location: Location) + where + T: TypeVisitable<TyCtxt<'tcx>>, + { + debug!("record_regions_live_at(value={:?}, location={:?})", value, location); + self.tcx.for_each_free_region(&value, |live_region| { + let live_region_vid = live_region.as_var(); + self.liveness_constraints.add_location(live_region_vid, location); + }); + } +} diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 02ccf928d8e..c718d57bec3 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,12 +1,12 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::WithSuccessors; -use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; +use rustc_index::bit_set::HybridBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::for_liveness; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; -use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -16,9 +16,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::ResultsCursor; -use crate::dataflow::BorrowIndex; use crate::{ - region_infer::values::{self, PointIndex, RegionValueElements}, + region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements}, type_check::liveness::local_use_map::LocalUseMap, type_check::liveness::polonius, type_check::NormalizeLocation, @@ -49,22 +48,17 @@ pub(super) fn trace<'mir, 'tcx>( boring_locals: Vec<Local>, polonius_drop_used: Option<Vec<(Local, Location)>>, ) { - debug!("trace()"); - let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body); // When using `-Zpolonius=next`, compute the set of loans that can reach a given region. - let num_loans = typeck.borrowck_context.borrow_set.len(); - let mut inflowing_loans = SparseBitMatrix::new(num_loans); if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { - let borrowck_context = &typeck.borrowck_context; + let borrowck_context = &mut typeck.borrowck_context; let borrow_set = &borrowck_context.borrow_set; - let constraint_set = &borrowck_context.constraints.outlives_constraints; - - let num_region_vars = typeck.infcx.num_region_vars(); - let graph = constraint_set.graph(num_region_vars); + let mut live_loans = LiveLoans::new(borrow_set.len()); + let outlives_constraints = &borrowck_context.constraints.outlives_constraints; + let graph = outlives_constraints.graph(typeck.infcx.num_region_vars()); let region_graph = - graph.region_graph(constraint_set, borrowck_context.universal_regions.fr_static); + graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static); // Traverse each issuing region's constraints, and record the loan as flowing into the // outlived region. @@ -75,9 +69,13 @@ pub(super) fn trace<'mir, 'tcx>( continue; } - inflowing_loans.insert(succ, loan); + live_loans.inflowing_loans.insert(succ, loan); } } + + // Store the inflowing loans in the liveness constraints: they will be used to compute live + // loans when liveness data is recorded there. + borrowck_context.constraints.liveness_constraints.loans = Some(live_loans); }; let cx = LivenessContext { @@ -88,7 +86,6 @@ pub(super) fn trace<'mir, 'tcx>( local_use_map, move_data, drop_data: FxIndexMap::default(), - inflowing_loans, }; let mut results = LivenessResults::new(cx); @@ -126,9 +123,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { /// Index indicating where each variable is assigned, used, or /// dropped. local_use_map: &'me LocalUseMap, - - /// Set of loans that flow into a given region, when using `-Zpolonius=next`. - inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>, } struct DropData<'tcx> { @@ -519,14 +513,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { live_at: &IntervalSet<PointIndex>, ) { debug!("add_use_live_facts_for(value={:?})", value); - - Self::make_all_regions_live( - self.elements, - self.typeck, - value, - live_at, - &self.inflowing_loans, - ); + Self::make_all_regions_live(self.elements, self.typeck, value, live_at); } /// Some variable with type `live_ty` is "drop live" at `location` @@ -577,14 +564,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { // All things in the `outlives` array may be touched by // the destructor and must be live at this point. for &kind in &drop_data.dropck_result.kinds { - Self::make_all_regions_live( - self.elements, - self.typeck, - kind, - live_at, - &self.inflowing_loans, - ); - + Self::make_all_regions_live(self.elements, self.typeck, kind, live_at); polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind); } } @@ -594,7 +574,6 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeVisitable<TyCtxt<'tcx>>, live_at: &IntervalSet<PointIndex>, - inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>, ) { debug!("make_all_regions_live(value={:?})", value); debug!( @@ -602,12 +581,6 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { values::pretty_print_points(elements, live_at.iter()), ); - // When using `-Zpolonius=next`, we want to record the loans that flow into this value's - // regions as being live at the given `live_at` points: this will be used to compute the - // location where a loan goes out of scope. - let num_loans = typeck.borrowck_context.borrow_set.len(); - let value_loans = &mut HybridBitSet::new_empty(num_loans); - value.visit_with(&mut for_liveness::FreeRegionsVisitor { tcx: typeck.tcx(), param_env: typeck.param_env, @@ -619,21 +592,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { .constraints .liveness_constraints .add_points(live_region_vid, live_at); - - // There can only be inflowing loans for this region when we are using - // `-Zpolonius=next`. - if let Some(inflowing) = inflowing_loans.row(live_region_vid) { - value_loans.union(inflowing); - } }, }); - - // Record the loans reaching the value. - if !value_loans.is_empty() { - for point in live_at.iter() { - typeck.borrowck_context.live_loans.union_row(point, value_loans); - } - } } fn compute_drop_data( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d4fd1a3cf2a..ecc9905e33e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -14,7 +14,6 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::SparseBitMatrix; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -51,8 +50,6 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; -use crate::dataflow::BorrowIndex; -use crate::region_infer::values::PointIndex; use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; use crate::{ borrow_set::BorrowSet, @@ -166,9 +163,6 @@ pub(crate) fn type_check<'mir, 'tcx>( debug!(?normalized_inputs_and_output); - // When using `-Zpolonius=next`, liveness will record the set of live loans per point. - let mut live_loans = SparseBitMatrix::new(borrow_set.len()); - let mut borrowck_context = BorrowCheckContext { universal_regions, location_table, @@ -176,7 +170,6 @@ pub(crate) fn type_check<'mir, 'tcx>( all_facts, constraints: &mut constraints, upvars, - live_loans: &mut live_loans, }; let mut checker = TypeChecker::new( @@ -232,7 +225,7 @@ pub(crate) fn type_check<'mir, 'tcx>( let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); if hidden_type.has_non_region_infer() { - let reported = infcx.tcx.sess.delay_span_bug( + let reported = infcx.tcx.sess.span_delayed_bug( decl.hidden_type.span, format!("could not resolve {:#?}", hidden_type.ty.kind()), ); @@ -243,7 +236,7 @@ pub(crate) fn type_check<'mir, 'tcx>( }) .collect(); - MirTypeckResults { constraints, universal_region_relations, opaque_type_values, live_loans } + MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { @@ -274,9 +267,9 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { #[track_caller] fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) { // We sometimes see MIR failures (notably predicate failures) due to - // the fact that we check rvalue sized predicates here. So use `delay_span_bug` + // the fact that we check rvalue sized predicates here. So use `span_delayed_bug` // to avoid reporting bugs in those cases. - tcx.sess.diagnostic().delay_span_bug(span, msg); + tcx.sess.diagnostic().span_delayed_bug(span, msg); } enum FieldAccessError { @@ -858,10 +851,6 @@ struct BorrowCheckContext<'a, 'tcx> { borrow_set: &'a BorrowSet<'tcx>, pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, upvars: &'a [&'a ty::CapturedPlace<'tcx>], - - /// The set of loans that are live at a given point in the CFG, filled in by `liveness::trace`, - /// when using `-Zpolonius=next`. - pub(crate) live_loans: &'a mut SparseBitMatrix<PointIndex, BorrowIndex>, } /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions @@ -870,9 +859,6 @@ pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, - - /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`. - pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, } /// A collection of region constraints that must be satisfied for the @@ -1082,7 +1068,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); if result.is_err() { - self.infcx.tcx.sess.delay_span_bug( + self.infcx.tcx.sess.span_delayed_bug( self.body.span, "failed re-defining predefined opaques in mir typeck", ); diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 070d50708ff..e13d217ef01 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -31,10 +31,7 @@ pub fn expand( { (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else { - ecx.sess - .parse_sess - .span_diagnostic - .emit_err(errors::AllocErrorMustBeFn { span: item.span() }); + ecx.sess.diagnostic().emit_err(errors::AllocErrorMustBeFn { span: item.span() }); return vec![orig_item]; }; diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 5499852e177..96e9584c209 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -19,8 +19,8 @@ fn invalid_type_err( let snippet = cx.sess.source_map().span_to_snippet(span).ok(); match ast::LitKind::from_token_lit(token_lit) { Ok(ast::LitKind::CStr(_, _)) => { - // FIXME(c_str_literals): should concatenation of C string literals - // include the null bytes in the end? + // Avoid ambiguity in handling of terminal `NUL` by refusing to + // concatenate C string literals as bytes. cx.emit_err(errors::ConcatCStrLit { span: span }); } Ok(ast::LitKind::Char(_)) => { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 33392edf060..6dc75e3ba4c 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -34,10 +34,7 @@ pub fn expand( { (item, true, ecx.with_def_site_ctxt(ty.span)) } else { - ecx.sess - .parse_sess - .span_diagnostic - .emit_err(errors::AllocMustStatics { span: item.span() }); + ecx.sess.diagnostic().emit_err(errors::AllocMustStatics { span: item.span() }); return vec![orig_item]; }; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index c0055380c25..bf1e1ebf5dd 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -389,7 +389,7 @@ pub fn expand_test_or_bench( } fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) { - let diag = &cx.sess.parse_sess.span_diagnostic; + let diag = cx.sess.diagnostic(); let msg = "the `#[test]` attribute may only be used on a non-associated function"; let mut err = match item.map(|i| &i.kind) { // These were a warning before #92959 and need to continue being that to avoid breaking @@ -466,7 +466,7 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> { fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { match attr::find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { - let sd = &cx.sess.parse_sess.span_diagnostic; + let sd = cx.sess.diagnostic(); match attr.meta_item_list() { // Handle #[should_panic(expected = "foo")] @@ -535,7 +535,7 @@ fn check_test_signature( f: &ast::Fn, ) -> Result<(), ErrorGuaranteed> { let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); - let sd = &cx.sess.parse_sess.span_diagnostic; + let sd = cx.sess.diagnostic(); if let ast::Unsafe::Yes(span) = f.sig.header.unsafety { return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" })); @@ -579,7 +579,7 @@ fn check_bench_signature( // N.B., inadequate check, but we're running // well before resolve, can't get too deep. if f.sig.decl.inputs.len() != 1 { - return Err(cx.sess.parse_sess.span_diagnostic.emit_err(errors::BenchSig { span: i.span })); + return Err(cx.sess.diagnostic().emit_err(errors::BenchSig { span: i.span })); } Ok(()) } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 92ae59ad352..481741bb127 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -4,7 +4,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::OptLevel; +use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; @@ -118,6 +118,15 @@ pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value)) } +fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { + let function_return_attr = match cx.sess().opts.unstable_opts.function_return { + FunctionReturn::Keep => return None, + FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern, + }; + + Some(function_return_attr.create_attr(cx.llcx)) +} + /// Tell LLVM what instrument function to insert. #[inline] fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> { @@ -331,8 +340,9 @@ pub fn from_fn_attrs<'ll, 'tcx>( to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile")); } - // FIXME: none of these three functions interact with source level attributes. + // FIXME: none of these functions interact with source level attributes. to_add.extend(frame_pointer_type_attr(cx)); + to_add.extend(function_return_attr(cx)); to_add.extend(instrument_function_attr(cx)); to_add.extend(nojumptables_attr(cx)); to_add.extend(probestack_attr(cx)); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 3a8b8e1ad11..1a567c0fce8 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -571,7 +571,6 @@ pub(crate) unsafe fn llvm_optimize( unroll_loops, config.vectorize_slp, config.vectorize_loop, - config.no_builtins, config.emit_lifetime_markers, sanitizer_options.as_ref(), pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), @@ -686,7 +685,6 @@ pub(crate) unsafe fn codegen( unsafe fn with_codegen<'ll, F, R>( tm: &'ll llvm::TargetMachine, llmod: &'ll llvm::Module, - no_builtins: bool, f: F, ) -> R where @@ -694,7 +692,7 @@ pub(crate) unsafe fn codegen( { let cpm = llvm::LLVMCreatePassManager(); llvm::LLVMAddAnalysisPasses(tm, cpm); - llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); + llvm::LLVMRustAddLibraryInfo(cpm, llmod); f(cpm) } @@ -797,7 +795,7 @@ pub(crate) unsafe fn codegen( } else { llmod }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, |cpm| { write_output_file( diag_handler, tm, @@ -832,7 +830,7 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, |cpm| { write_output_file( diag_handler, tm, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index df4cd8ea0bd..6c3ccc9cf0d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -200,6 +200,7 @@ pub enum AttributeKind { AllocatedPointer = 38, AllocAlign = 39, SanitizeSafeStack = 40, + FnRetThunkExtern = 41, } /// LLVMIntPredicate @@ -2162,13 +2163,8 @@ extern "C" { ArgsCstrBuff: *const c_char, ArgsCstrBuffLen: usize, ) -> *mut TargetMachine; - pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine); - pub fn LLVMRustAddLibraryInfo<'a>( - PM: &PassManager<'a>, - M: &'a Module, - DisableSimplifyLibCalls: bool, - ); + pub fn LLVMRustAddLibraryInfo<'a>(PM: &PassManager<'a>, M: &'a Module); pub fn LLVMRustWriteOutputFile<'a>( T: &'a TargetMachine, PM: &PassManager<'a>, @@ -2190,7 +2186,6 @@ extern "C" { UnrollLoops: bool, SLPVectorize: bool, LoopVectorize: bool, - DisableSimplifyLibCalls: bool, EmitLifetimeMarkers: bool, SanitizerOptions: Option<&SanitizerOptions>, PGOGenPath: *const c_char, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index be895417bbe..000b2748e4f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -143,7 +143,7 @@ pub fn link_binary<'a>( } } if sess.opts.json_artifact_notifications { - sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link"); + sess.diagnostic().emit_artifact_notification(&out_filename, "link"); } if sess.prof.enabled() { @@ -270,8 +270,14 @@ pub fn each_linked_rlib( for &cnum in crates { match fmts.get(cnum.as_usize() - 1) { - Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue, - Some(_) => {} + Some(&Linkage::NotLinked | &Linkage::Dynamic) => continue, + Some(&Linkage::IncludedFromDylib) => { + // We always link crate `compiler_builtins` statically. When enabling LTO, we include it as well. + if info.compiler_builtins != Some(cnum) { + continue; + } + } + Some(&Linkage::Static) => {} None => return Err(errors::LinkRlibError::MissingFormat), } let crate_name = info.crate_name[&cnum]; @@ -520,8 +526,7 @@ fn link_staticlib<'a>( &codegen_results.crate_info, Some(CrateType::Staticlib), &mut |cnum, path| { - let lto = are_upstream_rust_objects_already_included(sess) - && !ignored_for_lto(sess, &codegen_results.crate_info, cnum); + let lto = are_upstream_rust_objects_already_included(sess); let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter(); let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); @@ -1256,24 +1261,6 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { } } -/// Returns a boolean indicating whether the specified crate should be ignored -/// during LTO. -/// -/// Crates ignored during LTO are not lumped together in the "massive object -/// file" that we create and are linked in their normal rlib states. See -/// comments below for what crates do not participate in LTO. -/// -/// It's unusual for a crate to not participate in LTO. Typically only -/// compiler-specific and unstable crates have a reason to not participate in -/// LTO. -pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool { - // If our target enables builtin function lowering in LLVM then the - // crates providing these functions don't participate in LTO (e.g. - // no_builtins or compiler builtins crates). - !sess.target.no_builtins - && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum)) -} - /// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { fn infer_from( @@ -1477,7 +1464,7 @@ fn print_native_static_libs( sess.emit_note(errors::StaticLibraryNativeArtifacts); // Prefix for greppability // Note: This must not be translated as tools are allowed to depend on this exact string. - sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" "))); + sess.note(format!("native-static-libs: {}", &lib_args.join(" "))); } } } @@ -2739,10 +2726,6 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf { // symbols). We must continue to include the rest of the rlib, however, as // it may contain static native libraries which must be linked in. // -// (*) Crates marked with `#![no_builtins]` don't participate in LTO and -// their bytecode wasn't included. The object files in those libraries must -// still be passed to the linker. -// // Note, however, that if we're not doing LTO we can just pass the rlib // blindly to the linker (fast) because it's fine if it's not actually // included as we're at the end of the dependency chain. @@ -2768,9 +2751,7 @@ fn add_static_crate<'a>( cmd.link_rlib(&rlib_path); }; - if !are_upstream_rust_objects_already_included(sess) - || ignored_for_lto(sess, &codegen_results.crate_info, cnum) - { + if !are_upstream_rust_objects_already_included(sess) { link_upstream(cratepath); return; } @@ -2784,8 +2765,6 @@ fn add_static_crate<'a>( let canonical_name = name.replace('-', "_"); let upstream_rust_objects_already_included = are_upstream_rust_objects_already_included(sess); - let is_builtins = - sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum); let mut archive = archive_builder_builder.new_archive_builder(sess); if let Err(error) = archive.add_archive( @@ -2802,9 +2781,8 @@ fn add_static_crate<'a>( // If we're performing LTO and this is a rust-generated object // file, then we don't need the object file as it's part of the - // LTO module. Note that `#![no_builtins]` is excluded from LTO, - // though, so we let that object file slide. - if upstream_rust_objects_already_included && is_rust_object && is_builtins { + // LTO module. + if upstream_rust_objects_already_included && is_rust_object { return true; } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d716774690a..3e26e3653ea 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -12,9 +12,9 @@ use object::{ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; +use rustc_metadata::creader::MetadataLoader; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; -use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_span::sym; use rustc_target::abi::Endian; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b12ac881100..5f2fad0536b 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -54,8 +54,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S // export level, however, as they're just implementation details. // Down below we'll hardwire all of the symbols to the `Rust` export // level instead. - let special_runtime_crate = - tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE); + let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE); + let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || is_compiler_builtins; let mut reachable_non_generics: DefIdMap<_> = tcx .reachable_set(()) @@ -107,7 +107,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S .map(|def_id| { // We won't link right if this symbol is stripped during LTO. let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; - let used = name == "rust_eh_personality"; + // We have to preserve the symbols of the built-in functions during LTO. + let is_builtin_fn = is_compiler_builtins + && symbol_export_level(tcx, def_id.to_def_id()) + .is_below_threshold(SymbolExportLevel::C); + let used = is_builtin_fn || name == "rust_eh_personality"; let export_level = if special_runtime_crate { SymbolExportLevel::Rust diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8f17e4ea0bd..618a72272e5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -148,23 +148,12 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None - } else if sess.target.obj_is_bitcode - || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) - { + } else if sess.target.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() { // This case is selected if the target uses objects as bitcode, or // if linker plugin LTO is enabled. In the linker plugin LTO case // the assumption is that the final link-step will read the bitcode // and convert it to object code. This may be done by either the // native linker or rustc itself. - // - // Note, however, that the linker-plugin-lto requested here is - // explicitly ignored for `#![no_builtins]` crates. These crates are - // specifically ignored by rustc's LTO passes and wouldn't work if - // loaded into the linker. These crates define symbols that LLVM - // lowers intrinsics to, and these symbol dependencies aren't known - // until after codegen. As a result any crate marked - // `#![no_builtins]` is assumed to not participate in LTO and - // instead goes on to generate object code. EmitObj::Bitcode } else if need_bitcode_in_object(tcx) { EmitObj::ObjectCode(BitcodeSection::Full) @@ -1037,9 +1026,6 @@ fn start_executing_work<B: ExtraBackendMethods>( let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { - if link::ignored_for_lto(sess, crate_info, cnum) { - return; - } each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); })); @@ -1870,7 +1856,7 @@ impl SharedEmitterMain { let mut err = match level { Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(), Level::Warning(_) => sess.struct_warn(msg), - Level::Note => sess.struct_note_without_error(msg), + Level::Note => sess.struct_note(msg), _ => bug!("Invalid inline asm diagnostic level"), }; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1d5205ac67a..b87f4b6bf89 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -858,7 +858,6 @@ impl CrateInfo { local_crate_name, compiler_builtins, profiler_runtime: None, - is_no_builtins: Default::default(), native_libraries: Default::default(), used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), crate_name: Default::default(), @@ -885,9 +884,6 @@ impl CrateInfo { if tcx.is_profiler_runtime(cnum) { info.profiler_runtime = Some(cnum); } - if tcx.is_no_builtins(cnum) { - info.is_no_builtins.insert(cnum); - } } // Handle circular dependencies in the standard library. @@ -895,9 +891,7 @@ impl CrateInfo { // If global LTO is enabled then almost everything (*) is glued into a single object file, // so this logic is not necessary and can cause issues on some targets (due to weak lang // item symbols being "privatized" to that object file), so we disable it. - // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued, - // and we assume that they cannot define weak lang items. This is not currently enforced - // by the compiler, but that's ok because all this stuff is unstable anyway. + // (*) Native libs are not glued, and we assume that they cannot define weak lang items. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { let missing_weak_lang_items: FxHashSet<Symbol> = info diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e2b36fbd65b..40a985cf255 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -91,7 +91,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { Some(tcx.fn_sig(did)) } else { tcx.sess - .delay_span_bug(attr.span, "this attribute can only be applied to functions"); + .span_delayed_bug(attr.span, "this attribute can only be applied to functions"); None } }; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index bfd0a458884..cd5eb77e06e 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -25,7 +25,7 @@ extern crate tracing; extern crate rustc_middle; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; @@ -157,7 +157,6 @@ pub struct CrateInfo { pub local_crate_name: Symbol, pub compiler_builtins: Option<CrateNum>, pub profiler_runtime: Option<CrateNum>, - pub is_no_builtins: FxHashSet<CrateNum>, pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>, pub crate_name: FxHashMap<CrateNum, Symbol>, pub used_libraries: Vec<NativeLib>, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 35744d9a167..8e9907ed8bb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -9,6 +9,7 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::ErrorGuaranteed; +use rustc_metadata::creader::MetadataLoaderDyn; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; @@ -16,7 +17,6 @@ use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::util::Providers; use rustc_session::{ config::{self, OutputFilenames, PrintRequest}, - cstore::MetadataLoaderDyn, Session, }; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index bf1e0a37073..4934fcc75ec 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -148,7 +148,7 @@ where let mut err = tcx.sess.create_err(err); let msg = error.diagnostic_message(); - error.add_args(&tcx.sess.parse_sess.span_diagnostic, &mut err); + error.add_args(tcx.sess.diagnostic(), &mut err); // Use *our* span to label the interp error err.span_label(our_span, msg); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4b13a3404a0..2d8ca67c3a5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -391,7 +391,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if ecx.tcx.is_ctfe_mir_available(def) { Ok(ecx.tcx.mir_for_ctfe(def)) } else if ecx.tcx.def_kind(def) == DefKind::AssocConst { - let guar = ecx.tcx.sess.delay_span_bug( + let guar = ecx.tcx.sess.span_delayed_bug( rustc_span::DUMMY_SP, "This is likely a const item that is missing from its impl", ); @@ -622,7 +622,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, let guard = ecx .tcx .sess - .delay_span_bug(span, "The deny lint should have already errored"); + .span_delayed_bug(span, "The deny lint should have already errored"); throw_inval!(AlreadyReported(guard.into())); } } else if new_steps > start && new_steps.is_power_of_two() { diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index cc8f3387238..8343dc2dd35 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -437,7 +437,7 @@ pub trait ReportErrorExt { { ty::tls::with(move |tcx| { let mut builder = tcx.sess.struct_allow(DiagnosticMessage::Str(String::new().into())); - let handler = &tcx.sess.parse_sess.span_diagnostic; + let handler = tcx.sess.diagnostic(); let message = self.diagnostic_message(); self.add_args(handler, &mut builder); let s = handler.eagerly_translate_to_string(message, builder.args()); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3bdfc1db913..c0a20e51482 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -173,6 +173,9 @@ impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> { } /// Current value of a local variable +/// +/// This does not store the type of the local; the type is given by `body.local_decls` and can never +/// change, so by not storing here we avoid having to maintain that as an invariant. #[derive(Copy, Clone, Debug)] // Miri debug-prints these pub(super) enum LocalValue<Prov: Provenance = AllocId> { /// This local is not currently alive, and cannot be used at all. @@ -284,9 +287,9 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { { write!(f, "inside closure") } else { - // Note: this triggers a `good_path_bug` state, which means that if we ever get here - // we must emit a diagnostic. We should never display a `FrameInfo` unless we - // actually want to emit a warning or error to the user. + // Note: this triggers a `good_path_delayed_bug` state, which means that if we ever + // get here we must emit a diagnostic. We should never display a `FrameInfo` unless + // we actually want to emit a warning or error to the user. write!(f, "inside `{}`", self.instance) } }) @@ -300,8 +303,8 @@ impl<'tcx> FrameInfo<'tcx> { errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 } } else { let instance = format!("{}", self.instance); - // Note: this triggers a `good_path_bug` state, which means that if we ever get here - // we must emit a diagnostic. We should never display a `FrameInfo` unless we + // Note: this triggers a `good_path_delayed_bug` state, which means that if we ever get + // here we must emit a diagnostic. We should never display a `FrameInfo` unless we // actually want to emit a warning or error to the user. errors::FrameNote { where_: "instance", span, instance, times: 0 } } @@ -470,7 +473,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { backtrace.print_backtrace(); // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the // label and arguments from the InterpError. - let handler = &self.tcx.sess.parse_sess.span_diagnostic; + let handler = self.tcx.sess.diagnostic(); #[allow(rustc::untranslatable_diagnostic)] let mut diag = self.tcx.sess.struct_allow(""); let msg = e.diagnostic_message(); diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 413963b2fdc..881df9b04ab 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -94,9 +94,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: // If the pointer is dangling (neither in local nor global memory), we leave it // to validation to error -- it has the much better error messages, pointing out where // in the value the dangling reference lies. - // The `delay_span_bug` ensures that we don't forget such a check in validation. + // The `span_delayed_bug` ensures that we don't forget such a check in validation. if tcx.try_get_global_alloc(alloc_id).is_none() { - tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer"); + tcx.sess.span_delayed_bug(ecx.tcx.span, "tried to intern dangling pointer"); } // treat dangling pointers like other statics // just to stop trying to recurse into them @@ -186,7 +186,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory // Validation will error (with a better message) on an invalid vtable pointer. // Let validation show the error message, but make sure it *does* error. tcx.sess - .delay_span_bug(tcx.span, "vtables pointers cannot be integer pointers"); + .span_delayed_bug(tcx.span, "vtables pointers cannot be integer pointers"); } } // Check if we have encountered this pointer+layout combination before. @@ -375,7 +375,7 @@ pub fn intern_const_alloc_recursive< match res { Ok(()) => {} Err(error) => { - ecx.tcx.sess.delay_span_bug( + ecx.tcx.sess.span_delayed_bug( ecx.tcx.span, format!( "error during interning should later cause validation failure: {}", diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 13742ad273b..bcc42a376ea 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -248,7 +248,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's // no need to emit duplicate errors here. if self.ccx.is_async() || body.coroutine.is_some() { - tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`"); + tcx.sess.span_delayed_bug(body.span, "`async` functions cannot be `const fn`"); return; } @@ -357,7 +357,9 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { fn check_static(&mut self, def_id: DefId, span: Span) { if self.tcx.is_thread_local_static(def_id) { - self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); + self.tcx + .sess + .span_delayed_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); } self.check_op_spanned(ops::StaticAccess, span) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 4c2492d1867..4f7e165c575 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -112,7 +112,7 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { None if is_parent_const_stable_trait(tcx, def_id) => { // Remove this when `#![feature(const_trait_impl)]` is stabilized, // returning `true` unconditionally. - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(def_id), "trait implementations cannot be const stable yet", ); diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 3e8a0a2b7df..eaf4abf39b7 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -128,9 +128,9 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { #[track_caller] fn fail(&self, location: Location, msg: impl AsRef<str>) { let span = self.body.source_info(location).span; - // We use `delay_span_bug` as we might see broken MIR when other errors have already + // We use `span_delayed_bug` as we might see broken MIR when other errors have already // occurred. - self.tcx.sess.diagnostic().delay_span_bug( + self.tcx.sess.diagnostic().span_delayed_bug( span, format!( "broken MIR in {:?} ({}) at {:?}:\n{}", @@ -571,7 +571,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { fn visit_source_scope(&mut self, scope: SourceScope) { if self.body.source_scopes.get(scope).is_none() { - self.tcx.sess.diagnostic().delay_span_bug( + self.tcx.sess.diagnostic().span_delayed_bug( self.body.span, format!( "broken MIR in {:?} ({}):\ninvalid source scope {:?}", diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 6af11ce8479..450e1ead0b2 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -33,10 +33,10 @@ use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; +use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType, TrimmedDefPaths}; -use rustc_session::cstore::MetadataLoader; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, EarlyErrorHandler, Session}; diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 85acf8ab5aa..3823a1707ec 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -351,18 +351,10 @@ impl<'a> DiagnosticBuilder<'a, !> { /// `struct_*` methods on [`Handler`]. #[track_caller] pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message); - Self::new_diagnostic_fatal(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic"); Self { inner: DiagnosticBuilderInner { state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), + diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, message)), }, _marker: PhantomData, } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6bd87f54140..5966fd80f97 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -431,10 +431,10 @@ struct HandlerInner { warn_count: usize, deduplicated_err_count: usize, emitter: Box<DynEmitter>, - delayed_span_bugs: Vec<DelayedDiagnostic>, - delayed_good_path_bugs: Vec<DelayedDiagnostic>, + span_delayed_bugs: Vec<DelayedDiagnostic>, + good_path_delayed_bugs: Vec<DelayedDiagnostic>, /// This flag indicates that an expected diagnostic was emitted and suppressed. - /// This is used for the `delayed_good_path_bugs` check. + /// This is used for the `good_path_delayed_bugs` check. suppressed_expected_diag: bool, /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid @@ -528,7 +528,7 @@ pub struct HandlerFlags { /// If true, immediately emit diagnostics that would otherwise be buffered. /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) pub dont_buffer_diagnostics: bool, - /// If true, immediately print bugs registered with `delay_span_bug`. + /// If true, immediately print bugs registered with `span_delayed_bug`. /// (rustc: see `-Z report-delayed-bugs`) pub report_delayed_bugs: bool, /// Show macro backtraces. @@ -545,20 +545,20 @@ impl Drop for HandlerInner { self.emit_stashed_diagnostics(); if !self.has_errors() { - let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new()); - self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); + let bugs = std::mem::replace(&mut self.span_delayed_bugs, Vec::new()); + self.flush_delayed(bugs, "no errors encountered even though `span_delayed_bug` issued"); } - // FIXME(eddyb) this explains what `delayed_good_path_bugs` are! - // They're `delayed_span_bugs` but for "require some diagnostic happened" + // FIXME(eddyb) this explains what `good_path_delayed_bugs` are! + // They're `span_delayed_bugs` but for "require some diagnostic happened" // instead of "require some error happened". Sadly that isn't ideal, as // lints can be `#[allow]`'d, potentially leading to this triggering. // Also, "good path" should be replaced with a better naming. if !self.has_any_message() && !self.suppressed_expected_diag && !std::thread::panicking() { - let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new()); + let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new()); self.flush_delayed( bugs, - "no warnings or errors encountered even though `delayed_good_path_bugs` issued", + "no warnings or errors encountered even though `good_path_delayed_bugs` issued", ); } @@ -609,8 +609,8 @@ impl Handler { deduplicated_err_count: 0, deduplicated_warn_count: 0, emitter, - delayed_span_bugs: Vec::new(), - delayed_good_path_bugs: Vec::new(), + span_delayed_bugs: Vec::new(), + good_path_delayed_bugs: Vec::new(), suppressed_expected_diag: false, taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), @@ -648,7 +648,7 @@ impl Handler { // This is here to not allow mutation of flags; // as of this writing it's only used in tests in librustc_middle. pub fn can_emit_warnings(&self) -> bool { - self.inner.lock().flags.can_emit_warnings + self.inner.borrow_mut().flags.can_emit_warnings } /// Resets the diagnostic error count as well as the cached emitted diagnostics. @@ -664,8 +664,8 @@ impl Handler { inner.deduplicated_warn_count = 0; // actually free the underlying memory (which `clear` would not do) - inner.delayed_span_bugs = Default::default(); - inner.delayed_good_path_bugs = Default::default(); + inner.span_delayed_bugs = Default::default(); + inner.good_path_delayed_bugs = Default::default(); inner.taught_diagnostics = Default::default(); inner.emitted_diagnostic_codes = Default::default(); inner.emitted_diagnostics = Default::default(); @@ -675,14 +675,13 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key. /// Retrieve a stashed diagnostic with `steal_diagnostic`. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { - let mut inner = self.inner.borrow_mut(); - inner.stash((span.with_parent(None), key), diag); + self.inner.borrow_mut().stash((span.with_parent(None), key), diag); } /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key. pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> { - let mut inner = self.inner.borrow_mut(); - inner + self.inner + .borrow_mut() .steal((span.with_parent(None), key)) .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) } @@ -927,10 +926,7 @@ impl Handler { /// Construct a builder at the `Note` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_note_without_error( - &self, - msg: impl Into<DiagnosticMessage>, - ) -> DiagnosticBuilder<'_, ()> { + pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Note, msg) } @@ -970,11 +966,12 @@ impl Handler { span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, - ) { + ) -> ErrorGuaranteed { self.emit_diag_at_span( Diagnostic::new_with_code(Error { lint: false }, Some(code), msg), span, - ); + ) + .unwrap() } #[rustc_lint_diagnostics] @@ -998,20 +995,20 @@ impl Handler { self.inner.borrow_mut().span_bug(span, msg) } - /// For documentation on this, see `Session::delay_span_bug`. + /// For documentation on this, see `Session::span_delayed_bug`. #[track_caller] - pub fn delay_span_bug( + pub fn span_delayed_bug( &self, span: impl Into<MultiSpan>, msg: impl Into<String>, ) -> ErrorGuaranteed { - self.inner.borrow_mut().delay_span_bug(span, msg) + self.inner.borrow_mut().span_delayed_bug(span, msg) } // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's // where the explanation of what "good path" is (also, it should be renamed). - pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) { - self.inner.borrow_mut().delay_good_path_bug(msg) + pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) { + self.inner.borrow_mut().good_path_delayed_bug(msg) } #[track_caller] @@ -1021,17 +1018,13 @@ impl Handler { #[track_caller] #[rustc_lint_diagnostics] - pub fn span_note_without_error( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - ) { + pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) { self.emit_diag_at_span(Diagnostic::new(Note, msg), span); } #[track_caller] #[rustc_lint_diagnostics] - pub fn span_note_diag( + pub fn struct_span_note( &self, span: Span, msg: impl Into<DiagnosticMessage>, @@ -1054,12 +1047,11 @@ impl Handler { #[rustc_lint_diagnostics] pub fn warn(&self, msg: impl Into<DiagnosticMessage>) { - let mut db = DiagnosticBuilder::new(self, Warning(None), msg); - db.emit(); + DiagnosticBuilder::new(self, Warning(None), msg).emit(); } #[rustc_lint_diagnostics] - pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) { + pub fn note(&self, msg: impl Into<DiagnosticMessage>) { DiagnosticBuilder::new(self, Note, msg).emit(); } @@ -1085,8 +1077,8 @@ impl Handler { ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } - pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> { - self.inner.borrow().has_errors_or_delayed_span_bugs().then(|| { + pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> { + self.inner.borrow().has_errors_or_span_delayed_bugs().then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) @@ -1204,8 +1196,7 @@ impl Handler { mut diag: Diagnostic, sp: impl Into<MultiSpan>, ) -> Option<ErrorGuaranteed> { - let mut inner = self.inner.borrow_mut(); - inner.emit_diagnostic(diag.set_span(sp)) + self.inner.borrow_mut().emit_diagnostic(diag.set_span(sp)) } pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { @@ -1273,9 +1264,9 @@ impl Handler { } pub fn flush_delayed(&self) { - let mut inner = self.inner.lock(); - let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new()); - inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); + let mut inner = self.inner.borrow_mut(); + let bugs = std::mem::replace(&mut inner.span_delayed_bugs, Vec::new()); + inner.flush_delayed(bugs, "no errors encountered even though `span_delayed_bug` issued"); } } @@ -1332,11 +1323,11 @@ impl HandlerInner { if diagnostic.level == Level::DelayedBug { // FIXME(eddyb) this should check for `has_errors` and stop pushing - // once *any* errors were emitted (and truncate `delayed_span_bugs` + // once *any* errors were emitted (and truncate `span_delayed_bugs` // when an error is first emitted, also), but maybe there's a case // in which that's not sound? otherwise this is really inefficient. let backtrace = std::backtrace::Backtrace::capture(); - self.delayed_span_bugs + self.span_delayed_bugs .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); if !self.flags.report_delayed_bugs { @@ -1451,7 +1442,7 @@ impl HandlerInner { } fn delayed_bug_count(&self) -> usize { - self.delayed_span_bugs.len() + self.delayed_good_path_bugs.len() + self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len() } fn print_error_count(&mut self, registry: &Registry) { @@ -1502,18 +1493,18 @@ impl HandlerInner { error_codes.sort(); if error_codes.len() > 1 { let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; - self.failure(format!( + self.failure_note(format!( "Some errors have detailed explanations: {}{}", error_codes[..limit].join(", "), if error_codes.len() > 9 { "..." } else { "." } )); - self.failure(format!( + self.failure_note(format!( "For more information about an error, try \ `rustc --explain {}`.", &error_codes[0] )); } else { - self.failure(format!( + self.failure_note(format!( "For more information about this error, try \ `rustc --explain {}`.", &error_codes[0] @@ -1572,15 +1563,15 @@ impl HandlerInner { fn has_errors_or_lint_errors(&self) -> bool { self.has_errors() || self.lint_err_count > 0 } - fn has_errors_or_delayed_span_bugs(&self) -> bool { - self.has_errors() || !self.delayed_span_bugs.is_empty() + fn has_errors_or_span_delayed_bugs(&self) -> bool { + self.has_errors() || !self.span_delayed_bugs.is_empty() } fn has_any_message(&self) -> bool { self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0 } fn is_compilation_going_to_fail(&self) -> bool { - self.has_errors() || self.lint_err_count > 0 || !self.delayed_span_bugs.is_empty() + self.has_errors() || self.lint_err_count > 0 || !self.span_delayed_bugs.is_empty() } fn abort_if_errors(&mut self) { @@ -1601,14 +1592,17 @@ impl HandlerInner { self.emit_diagnostic(diag.set_span(sp)); } - /// For documentation on this, see `Session::delay_span_bug`. + /// For documentation on this, see `Session::span_delayed_bug`. + /// + /// Note: this function used to be called `delay_span_bug`. It was renamed + /// to match similar functions like `span_bug`, `span_err`, etc. #[track_caller] - fn delay_span_bug( + fn span_delayed_bug( &mut self, sp: impl Into<MultiSpan>, msg: impl Into<String>, ) -> ErrorGuaranteed { - // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before + // This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before // incrementing `err_count` by one, so we need to +1 the comparing. // FIXME: Would be nice to increment err_count in a more coherent way. if self.flags.treat_err_as_bug.is_some_and(|c| { @@ -1624,16 +1618,16 @@ impl HandlerInner { // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's // where the explanation of what "good path" is (also, it should be renamed). - fn delay_good_path_bug(&mut self, msg: impl Into<DiagnosticMessage>) { + fn good_path_delayed_bug(&mut self, msg: impl Into<DiagnosticMessage>) { let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); if self.flags.report_delayed_bugs { self.emit_diagnostic(&mut diagnostic); } let backtrace = std::backtrace::Backtrace::capture(); - self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); + self.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } - fn failure(&mut self, msg: impl Into<DiagnosticMessage>) { + fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) { self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg)); } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 88e90a3b3d1..91f3ca1d115 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1119,7 +1119,7 @@ impl<'a> ExtCtxt<'a> { sp: S, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg) + self.sess.diagnostic().struct_span_err(sp, msg) } #[track_caller] @@ -1143,15 +1143,15 @@ impl<'a> ExtCtxt<'a> { #[rustc_lint_diagnostics] #[track_caller] pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { - self.sess.parse_sess.span_diagnostic.span_err(sp, msg); + self.sess.diagnostic().span_err(sp, msg); } #[rustc_lint_diagnostics] #[track_caller] pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { - self.sess.parse_sess.span_diagnostic.span_warn(sp, msg); + self.sess.diagnostic().span_warn(sp, msg); } pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! { - self.sess.parse_sess.span_diagnostic.span_bug(sp, msg); + self.sess.diagnostic().span_bug(sp, msg); } pub fn trace_macros_diag(&mut self) { for (span, notes) in self.expansions.iter() { @@ -1165,7 +1165,7 @@ impl<'a> ExtCtxt<'a> { self.expansions.clear(); } pub fn bug(&self, msg: &'static str) -> ! { - self.sess.parse_sess.span_diagnostic.bug(msg); + self.sess.diagnostic().bug(msg); } pub fn trace_macros(&self) -> bool { self.ecfg.trace_mac @@ -1286,9 +1286,8 @@ pub fn expr_to_string( /// Non-fatally assert that `tts` is empty. Note that this function /// returns even when `tts` is non-empty, macros that *need* to stop -/// compilation should call -/// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be -/// done as rarely as possible). +/// compilation should call `cx.diagnostic().abort_if_errors()` +/// (this should be done as rarely as possible). pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) { if !tts.is_empty() { cx.emit_err(errors::TakesNoArguments { span, name }); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1b51d80fb38..ad21a73f063 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -435,7 +435,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invocations = mem::take(&mut undetermined_invocations); force = !mem::replace(&mut progress, false); if force && self.monotonic { - self.cx.sess.delay_span_bug( + self.cx.sess.span_delayed_bug( invocations.last().unwrap().0.span(), "expansion entered force mode without producing any errors", ); diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 64cf9ced9c1..8f80e6e2927 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -34,7 +34,7 @@ pub(super) fn failed_to_match_macro<'cx>( if try_success_result.is_ok() { // Nonterminal parser recovery might turn failed matches into successful ones, // but for that it must have emitted an error already - tracker.cx.sess.delay_span_bug(sp, "Macro matching returned a success on the second try"); + tracker.cx.sess.span_delayed_bug(sp, "Macro matching returned a success on the second try"); } if let Some(result) = tracker.result { @@ -151,7 +151,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, Success(_) => { // Nonterminal parser recovery might turn failed matches into successful ones, // but for that it must have emitted an error already - self.cx.sess.delay_span_bug( + self.cx.sess.span_delayed_bug( self.root_span, "should not collect detailed info for successful macro match", ); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index bc3f0ce5a70..19734394382 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -475,17 +475,14 @@ pub fn compile_declarative_macro( let s = parse_failure_msg(&token); let sp = token.span.substitute_dummy(def.span); - let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, s); + let mut err = sess.diagnostic().struct_span_err(sp, s); err.span_label(sp, msg); annotate_doc_comment(&mut err, sess.source_map(), sp); err.emit(); return dummy_syn_ext(); } Error(sp, msg) => { - sess.parse_sess - .span_diagnostic - .struct_span_err(sp.substitute_dummy(def.span), msg) - .emit(); + sess.diagnostic().struct_span_err(sp.substitute_dummy(def.span), msg).emit(); return dummy_syn_ext(); } ErrorReported(_) => { @@ -514,10 +511,10 @@ pub fn compile_declarative_macro( valid &= check_lhs_nt_follows(&sess.parse_sess, def, &tt); return tt; } - sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + sess.diagnostic().span_bug(def.span, "wrong-structured lhs") }) .collect::<Vec<mbe::TokenTree>>(), - _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), + _ => sess.diagnostic().span_bug(def.span, "wrong-structured lhs"), }; let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { @@ -536,10 +533,10 @@ pub fn compile_declarative_macro( .pop() .unwrap(); } - sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") + sess.diagnostic().span_bug(def.span, "wrong-structured rhs") }) .collect::<Vec<mbe::TokenTree>>(), - _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), + _ => sess.diagnostic().span_bug(def.span, "wrong-structured rhs"), }; for rhs in &rhses { @@ -595,7 +592,7 @@ pub fn compile_declarative_macro( mbe::TokenTree::Delimited(_, delimited) => { mbe::macro_parser::compute_locs(&delimited.tts) } - _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "malformed macro lhs"), + _ => sess.diagnostic().span_bug(def.span, "malformed macro lhs"), } }) .collect() @@ -648,10 +645,8 @@ fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool iter.next(); } let span = t.span.to(now.span); - sess.span_diagnostic.span_note_without_error( - span, - "doc comments are ignored in matcher position", - ); + sess.span_diagnostic + .span_note(span, "doc comments are ignored in matcher position"); } mbe::TokenTree::Sequence(_, sub_seq) if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 6c6dfe53305..6a99412fc5b 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -357,7 +357,7 @@ fn parse_sep_and_kleene_op<'a>( fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &ParseSess, token: &Token) { sess.span_diagnostic .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token))); - sess.span_diagnostic.span_note_without_error( + sess.span_diagnostic.span_note( token.span, "`$$` and meta-variable expressions are not allowed inside macro parameter definitions", ); diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 39a16259fa6..d08026b9c14 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -156,7 +156,7 @@ impl MultiItemModifier for DeriveProcMacro { } }; - let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); + let error_count_before = ecx.sess.diagnostic().err_count(); let mut parser = rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive")); let mut items = vec![]; @@ -179,7 +179,7 @@ impl MultiItemModifier for DeriveProcMacro { } // fail if there have been errors emitted - if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { + if ecx.sess.diagnostic().err_count() > error_count_before { ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span }); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 37ef4d86989..94e79144593 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -77,6 +77,8 @@ declare_features! ( (accepted, bindings_after_at, "1.56.0", Some(65490), None), /// Allows empty structs and enum variants with braces. (accepted, braced_empty_structs, "1.8.0", Some(29720), None), + /// Allows `c"foo"` literals. + (accepted, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None), /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 214de3ca402..9754f7acaae 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -813,7 +813,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!( TEST, rustc_error, Normal, - template!(Word, List: "delay_span_bug_from_inside_query"), WarnFollowingWordOnly + template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly ), rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 87acb6f27c5..dee68bff21d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -354,8 +354,6 @@ declare_features! ( (unstable, async_fn_track_caller, "1.73.0", Some(110011), None), /// Allows builtin # foo() syntax (unstable, builtin_syntax, "1.71.0", Some(110680), None), - /// Allows `c"foo"` literals. - (unstable, c_str_literals, "1.71.0", Some(105723), None), /// Treat `extern "C"` function as nounwind. (unstable, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index b9a4806e6c2..fd3e6bd44e7 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -720,9 +720,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // since we should have emitten an error for them earlier, and they will // not be well-formed! if polarity == ty::ImplPolarity::Negative { - self.tcx() - .sess - .delay_span_bug(binding.span, "negative trait bounds should not have bindings"); + self.tcx().sess.span_delayed_bug( + binding.span, + "negative trait bounds should not have bindings", + ); continue; } @@ -1419,7 +1420,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // trait reference. let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { // A cycle error occurred, most likely. - let guar = tcx.sess.delay_span_bug(span, "expected cycle error"); + let guar = tcx.sess.span_delayed_bug(span, "expected cycle error"); return Err(guar); }; @@ -2376,7 +2377,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let e = self .tcx() .sess - .delay_span_bug(path.span, "path with `Res::Err` but no error emitted"); + .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); self.set_tainted_by_errors(e); Ty::new_error(self.tcx(), e) } diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 78c5809f8b4..6cb38c741b7 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -325,7 +325,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { false }); if references_self { - let guar = tcx.sess.delay_span_bug( + let guar = tcx.sess.span_delayed_bug( span, "trait object projection bounds reference `Self`", ); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index fbed6f33e59..56e272b14bd 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -130,7 +130,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b for field in &def.non_enum_variant().fields { let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args)) else { - tcx.sess.delay_span_bug(span, "could not normalize field type"); + tcx.sess.span_delayed_bug(span, "could not normalize field type"); continue; }; @@ -151,7 +151,8 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b return false; } else if field_ty.needs_drop(tcx, param_env) { // This should never happen. But we can get here e.g. in case of name resolution errors. - tcx.sess.delay_span_bug(span, "we should never accept maybe-dropping union fields"); + tcx.sess + .span_delayed_bug(span, "we should never accept maybe-dropping union fields"); } } } else { @@ -181,7 +182,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { } // Generic statics are rejected, but we still reach this case. Err(e) => { - tcx.sess.delay_span_bug(span, format!("{e:?}")); + tcx.sess.span_delayed_bug(span, format!("{e:?}")); return; } }; @@ -204,7 +205,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { let item = tcx.hir().item(id); let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { - tcx.sess.delay_span_bug(item.span, "expected opaque item"); + tcx.sess.span_delayed_bug(item.span, "expected opaque item"); return; }; @@ -313,7 +314,7 @@ fn check_opaque_meets_bounds<'tcx>( Ok(()) => {} Err(ty_err) => { let ty_err = ty_err.to_string(tcx); - return Err(tcx.sess.delay_span_bug( + return Err(tcx.sess.span_delayed_bug( span, format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), )); @@ -655,7 +656,7 @@ pub(super) fn check_specialization_validity<'tcx>( if !tcx.is_impl_trait_in_trait(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, format!("parent item: {parent_impl:?} not marked as default"), ); @@ -703,7 +704,7 @@ fn check_impl_items_against_trait<'tcx>( tcx.associated_item(trait_item_id) } else { // Checked in `associated_item`. - tcx.sess.delay_span_bug(tcx.def_span(impl_item), "missing associated item in trait"); + tcx.sess.span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait"); continue; }; match ty_impl_item.kind { 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 16fd1a951b5..1412fd1a987 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -439,7 +439,7 @@ fn compare_method_predicate_entailment<'tcx>( } return Err(tcx .sess - .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")); + .span_delayed_bug(rustc_span::DUMMY_SP, "error should have been emitted")); } } } @@ -937,7 +937,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( remapped_types.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { - let reported = tcx.sess.delay_span_bug( + let reported = tcx.sess.span_delayed_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); @@ -1114,7 +1114,9 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { .note(format!("hidden type inferred to be `{}`", self.ty)) .emit() } - _ => self.tcx.sess.delay_span_bug(DUMMY_SP, "should've been able to remap region"), + _ => { + self.tcx.sess.span_delayed_bug(DUMMY_SP, "should've been able to remap region") + } }; return Err(guar); }; @@ -1473,7 +1475,7 @@ fn compare_number_of_generics<'tcx>( // inheriting the generics from will also have mismatched arguments, and // we'll report an error for that instead. Delay a bug for safety, though. if trait_.is_impl_trait_in_trait() { - return Err(tcx.sess.delay_span_bug( + return Err(tcx.sess.span_delayed_bug( rustc_span::DUMMY_SP, "errors comparing numbers of generics of trait/impl functions were not emitted", )); 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 index bcd317f78ef..86c38480d57 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -153,7 +153,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( trait_m_sig.inputs_and_output, )); if !ocx.select_all_or_error().is_empty() { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, "encountered errors when checking RPITIT refinement (selection)", ); @@ -165,7 +165,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, "encountered errors when checking RPITIT refinement (regions)", ); @@ -173,7 +173,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( } // 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( + tcx.sess.span_delayed_bug( DUMMY_SP, "encountered errors when checking RPITIT refinement (resolution)", ); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 0a05c1039b6..58c77bb45cb 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -66,7 +66,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro // already checked by coherence, but compilation may // not have been terminated. let span = tcx.def_span(drop_impl_did); - let reported = tcx.sess.delay_span_bug( + let reported = tcx.sess.span_delayed_bug( span, format!("should have been rejected by coherence check: {dtor_self_type}"), ); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index ba627c740df..2428fe6ae79 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -281,7 +281,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id()); let Some(asm_arch) = self.tcx.sess.asm_arch else { - self.tcx.sess.delay_span_bug(DUMMY_SP, "target architecture does not support asm"); + self.tcx.sess.span_delayed_bug(DUMMY_SP, "target architecture does not support asm"); return; }; for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 177e4611cc9..92619ae417b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -118,10 +118,10 @@ where if tcx.sess.err_count() > 0 { return Err(err); } else { - // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs causes an - // error (delay_span_bug) during normalization, without reporting an error, so we need to act as if - // no error happened, in order to let our callers continue and report an error later in - // check_impl_items_against_trait. + // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs + // causes an error (span_delayed_bug) during normalization, without reporting an error, + // so we need to act as if no error happened, in order to let our callers continue and + // report an error later in check_impl_items_against_trait. return Ok(()); } } @@ -1040,7 +1040,7 @@ fn check_type_defn<'tcx>( let ty = tcx.erase_regions(ty); if ty.has_infer() { tcx.sess - .delay_span_bug(item.span, format!("inference variables in {ty:?}")); + .span_delayed_bug(item.span, format!("inference variables in {ty:?}")); // Just treat unresolved type expression as if it needs drop. true } else { @@ -1812,8 +1812,10 @@ fn check_variances_for_type_defn<'tcx>( // // if they aren't in the same order, then the user has written invalid code, and already // got an error about it (or I'm wrong about this) - tcx.sess - .delay_span_bug(hir_param.span, "hir generics and ty generics in different order"); + tcx.sess.span_delayed_bug( + hir_param.span, + "hir generics and ty generics in different order", + ); continue; } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 46f77780a52..45100457629 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -453,7 +453,7 @@ fn lint_auto_trait_impl<'tcx>( impl_def_id: LocalDefId, ) { if trait_ref.args.len() != 1 { - tcx.sess.diagnostic().delay_span_bug( + tcx.sess.diagnostic().span_delayed_bug( tcx.def_span(impl_def_id), "auto traits cannot have generic parameters", ); diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 6b18b0ebe9d..42e2818b63f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -82,7 +82,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { // Reported in AST validation - tcx.sess.delay_span_bug(item.span, "unsafe negative impl"); + tcx.sess.span_delayed_bug(item.span, "unsafe negative impl"); } (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_)) | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) 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 e49bd0917a8..c6ea853b9ba 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -335,7 +335,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // though this may happen when we call `poly_trait_ref_binder_info` with // an (erroneous, #113423) associated return type bound in an impl header. if !supertrait_bound_vars.is_empty() { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( DUMMY_SP, format!( "found supertrait lifetimes without a binder to append \ @@ -1363,7 +1363,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( lifetime_ref.ident.span, format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), ); @@ -1493,7 +1493,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( self.tcx.hir().span(hir_id), format!("could not resolve {param_def_id:?}"), ); @@ -1724,7 +1724,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } else { self.tcx .sess - .delay_span_bug(binding.ident.span, "bad return type notation here"); + .span_delayed_bug(binding.ident.span, "bad return type notation here"); vec![] }; self.with(scope, |this| { @@ -2057,7 +2057,7 @@ fn is_late_bound_map( Some(true) => Some(arg), Some(false) => None, None => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( *span, format!( "Incorrect generic arg count for alias {alias_def:?}" diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index f22b836b42b..4ed1377e7fc 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -29,7 +29,7 @@ fn diagnostic_hir_wf_check<'tcx>( // HIR wfcheck should only ever happen as part of improving an existing error tcx.sess - .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); + .span_delayed_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); let icx = ItemCtxt::new(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 788121f7a30..fff4a919e91 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -74,7 +74,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) if impl_self_ty.references_error() { // Don't complain about unconstrained type params when self ty isn't known due to errors. // (#36836) - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(impl_def_id), format!( "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}", diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1c3ac297457..91cdffbbe4f 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -209,8 +209,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); - // HACK: `check_mod_type_wf` may spuriously emit errors due to `delay_span_bug`, even if those errors - // only actually get emitted in `check_mod_item_types`. + // HACK: `check_mod_type_wf` may spuriously emit errors due to `span_delayed_bug`, even if + // those errors only actually get emitted in `check_mod_item_types`. errs?; if tcx.features().rustc_attrs { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d3abe0d7e1a..a907acba0e0 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // Check for `self` receiver on the method, otherwise we can't use this as a `Fn*` trait. if !self.tcx.associated_item(ok.value.def_id).fn_has_self_parameter { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( call_expr.span, "input to overloaded call fn is not a self receiver", ); @@ -259,9 +259,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() else { // The `fn`/`fn_mut` lang item is ill-formed, which should have // caused an error elsewhere. - self.tcx - .sess - .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref"); + self.tcx.sess.span_delayed_bug( + call_expr.span, + "input to call/call_mut is not a ref", + ); return None; }; diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 00af6d46213..d89af297560 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -142,7 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let reported = self .tcx .sess - .delay_span_bug(span, format!("`{t:?}` should be sized but is not?")); + .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?")); return Err(reported); } }) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 587038d57bd..f39d795f0ed 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1549,7 +1549,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // any superfluous errors we might encounter while trying to // emit or provide suggestions on how to fix the initial error. fcx.set_tainted_by_errors( - fcx.tcx.sess.delay_span_bug(cause.span, "coercion error but no error emitted"), + fcx.tcx + .sess + .span_delayed_bug(cause.span, "coercion error but no error emitted"), ); let (expected, found) = if label_expression_as_expected { // In the case where this is a "forced unit", like diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 33d14476b2c..8f633834885 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr); - self.set_tainted_by_errors(self.tcx.sess.delay_span_bug( + self.set_tainted_by_errors(self.tcx.sess.span_delayed_bug( expr.span, "`TypeError` when attempting coercion but no error emitted", )); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c2a8eb3bc8e..7c157c0eae0 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -75,7 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // coercions from ! to `expected`. if ty.is_never() { if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { - let reported = self.tcx().sess.delay_span_bug( + let reported = self.tcx().sess.span_delayed_bug( expr.span, "expression with never type wound up being adjusted", ); @@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Err => { self.suggest_assoc_method_call(segs); let e = - self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + self.tcx.sess.span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); Ty::new_error(tcx, e) } @@ -623,7 +623,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Set expectation to error in that case and set tainted // by error (#114529) let coerce_to = opt_coerce_to.unwrap_or_else(|| { - let guar = tcx.sess.delay_span_bug( + let guar = tcx.sess.span_delayed_bug( expr.span, "illegal break with value found but no error reported", ); @@ -1292,7 +1292,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // permit break with a value [1]. if ctxt.coerce.is_none() && !ctxt.may_break { // [1] - self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break"); + self.tcx.sess.span_delayed_bug(body.span, "no coercion, but loop may not break"); } ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx)) } @@ -2187,7 +2187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = self .tcx .sess - .delay_span_bug(expr.span, "parser recovered but no error was emitted"); + .span_delayed_bug(expr.span, "parser recovered but no error was emitted"); self.set_tainted_by_errors(guar); return guar; } @@ -2403,7 +2403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let guar = if field.name == kw::Empty { - self.tcx.sess.delay_span_bug(field.span, "field name with no name") + self.tcx.sess.span_delayed_bug(field.span, "field name with no name") } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) { self.ban_take_value_of_method(expr, base_ty, field) } else if !base_ty.is_primitive_ty() { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 9991050d7b2..c22b15231a1 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -538,7 +538,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // The struct path probably didn't resolve if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() { - self.tcx().sess.delay_span_bug(field.span, "couldn't resolve index for field"); + self.tcx().sess.span_delayed_bug(field.span, "couldn't resolve index for field"); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 23b9ac4139d..e1a2a260df7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -277,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. _ => { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( expr.span, format!( "while adjusting {:?}, can't compose {:?} and {:?}", @@ -866,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = self .tcx .sess - .delay_span_bug(span, "method resolution should've emitted an error"); + .span_delayed_bug(span, "method resolution should've emitted an error"); let result = match error { method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), _ => Err(guar), @@ -1440,7 +1440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( span, format!( "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index f1720dc98e6..509596c1e90 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -517,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` self.set_tainted_by_errors( - tcx.sess.delay_span_bug(call_span, "no errors reported for args"), + tcx.sess.span_delayed_bug(call_span, "no errors reported for args"), ); // Get the argument span in the context of the call span so that @@ -1361,7 +1361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let variant = match def { Res::Err => { let guar = - self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"); + self.tcx.sess.span_delayed_bug(path_span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(guar); return Err(guar); } diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 5d516eaf507..a3c77af62a7 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let to = normalize(to); trace!(?from, ?to); if from.has_non_region_infer() || to.has_non_region_infer() { - tcx.sess.delay_span_bug(span, "argument to transmute has inference variables"); + tcx.sess.span_delayed_bug(span, "argument to transmute has inference variables"); return; } // Transmutes that are only changing lifetimes are always ok. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index a22c95ac8ff..29e4fd9239a 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -420,20 +420,16 @@ fn fatally_break_rust(tcx: TyCtxt<'_>) { MultiSpan::new(), "It looks like you're trying to break rust; would you like some ICE?", ); - handler.note_without_error("the compiler expectedly panicked. this is a feature."); - handler.note_without_error( + handler.note("the compiler expectedly panicked. this is a feature."); + handler.note( "we would appreciate a joke overview: \ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", ); - handler.note_without_error(format!( - "rustc {} running on {}", - tcx.sess.cfg_version, - config::host_triple(), - )); + handler.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),)); if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() { - handler.note_without_error(format!("compiler flags: {}", flags.join(" "))); + handler.note(format!("compiler flags: {}", flags.join(" "))); if excluded_cargo_defaults { - handler.note_without_error("some of the compiler flags provided by cargo are hidden"); + handler.note("some of the compiler flags provided by cargo are hidden"); } } } diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 0bcb7c7b5d7..ebb15e072aa 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -540,7 +540,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let ty::Adt(adt_def, _) = ty.kind() else { self.tcx() .sess - .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"); return Err(()); }; @@ -575,7 +575,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { _ => { self.tcx() .sess - .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"); Err(()) } } @@ -588,7 +588,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { match ty.kind() { ty::Tuple(args) => Ok(args.len()), _ => { - self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); + self.tcx().sess.span_delayed_bug(span, "tuple pattern not applied to a tuple"); Err(()) } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index d69d2529b18..f820835acef 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type parameters or early-bound regions. let tcx = self.tcx; let Some(method_item) = self.associated_value(trait_def_id, m_name) else { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( obligation.cause.span, "operator trait does not have corresponding operator method", ); @@ -393,7 +393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if method_item.kind != ty::AssocKind::Fn { - self.tcx.sess.delay_span_bug(tcx.def_span(method_item.def_id), "not a method"); + self.tcx.sess.span_delayed_bug(tcx.def_span(method_item.def_id), "not a method"); return None; } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 7d83f4a12b1..4243bce377f 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -802,7 +802,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { if new_trait_ref.has_non_region_bound_vars() { - this.tcx.sess.delay_span_bug( + this.tcx.sess.span_delayed_bug( this.span, "tried to select method from HRTB with non-lifetime bound vars", ); @@ -1799,9 +1799,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .iter() .find(|cand| self.matches_by_doc_alias(cand.def_id)) .map(|cand| cand.name) - }) - .unwrap(); - Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name)) + }); + Ok(best_name.and_then(|best_name| { + applicable_close_candidates.into_iter().find(|method| method.name == best_name) + })) } }) } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a7764f4ff96..858385246dd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -813,7 +813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: item_span, .. })) => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( *item_span, "auto trait is invoked with no method error, but no error reported?", ); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index fcb3f8f47bd..1e9387ef041 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -900,7 +900,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { self.tcx .sess - .delay_span_bug(span, "operator didn't have the right number of generic args"); + .span_delayed_bug(span, "operator didn't have the right number of generic args"); return Err(vec![]); } @@ -933,7 +933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This path may do some inference, so make sure we've really // doomed compilation so as to not accidentally stabilize new // inference or something here... - self.tcx.sess.delay_span_bug(span, "this path really should be doomed..."); + self.tcx.sess.span_delayed_bug(span, "this path really should be doomed..."); // Guide inference for the RHS expression if it's provided -- // this will allow us to better error reporting, at the expense // of making some error messages a bit more specific. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 1ecf553d71d..b63bb1e00cb 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -899,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = path_resolution; match res { Res::Err => { - let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + let e = tcx.sess.span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); return Ty::new_error(tcx, e); } @@ -1068,7 +1068,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None); if res == Res::Err { - let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); + let e = tcx.sess.span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); return Ty::new_error(tcx, e); @@ -1084,7 +1084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let variant = match res { Res::Err => { - let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); + let e = tcx.sess.span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); return Ty::new_error(tcx, e); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 3a0f46c3a8c..c0a5818b9e5 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -725,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( closure_span, format!( "two identical projections: ({:?}, {:?})", diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index fc635a8da2e..cc617fd2d0b 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -218,7 +218,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been // emitted, so we delay an ICE if none have. (#64638) - self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{base:?}`")); + self.tcx().sess.span_delayed_bug(e.span, format!("bad base: `{base:?}`")); } if let Some(base_ty) = base_ty && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() @@ -311,7 +311,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { // Nothing to write back here } hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { - self.tcx().sess.delay_span_bug(p.span, format!("unexpected generic param: {p:?}")); + self.tcx() + .sess + .span_delayed_bug(p.span, format!("unexpected generic param: {p:?}")); } } } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 2d809030e58..92297a27a63 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -262,7 +262,7 @@ pub(crate) fn prepare_session_directory( directory." ); - sess.init_incr_comp_session(session_dir, directory_lock, false); + sess.init_incr_comp_session(session_dir, directory_lock); return Ok(()); }; @@ -276,7 +276,7 @@ pub(crate) fn prepare_session_directory( sess.emit_warning(errors::HardLinkFailed { path: &session_dir }); } - sess.init_incr_comp_session(session_dir, directory_lock, true); + sess.init_incr_comp_session(session_dir, directory_lock); return Ok(()); } else { debug!("copying failed - trying next directory"); @@ -312,7 +312,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) { let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone(); - if let Some(_) = sess.has_errors_or_delayed_span_bugs() { + if let Some(_) = sess.has_errors_or_span_delayed_bugs() { // If there have been any errors during compilation, we don't want to // publish this session directory. Rather, we'll just delete it. diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index d6320d680e7..ff0953e9f7b 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -32,7 +32,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { return; } // This is going to be deleted in finalize_session_directory, so let's not create it - if let Some(_) = sess.has_errors_or_delayed_span_bugs() { + if let Some(_) = sess.has_errors_or_span_delayed_bugs() { return; } @@ -87,7 +87,7 @@ pub fn save_work_product_index( return; } // This is going to be deleted in finalize_session_directory, so let's not create it - if let Some(_) = sess.has_errors_or_delayed_span_bugs() { + if let Some(_) = sess.has_errors_or_span_delayed_bugs() { return; } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 6fbab0ef299..473a3965885 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -194,8 +194,8 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { // // rust-lang/rust#57464: `impl Trait` can leak local // scopes (in manner violating typeck). Therefore, use - // `delay_span_bug` to allow type error over an ICE. - canonicalizer.tcx.sess.delay_span_bug( + // `span_delayed_bug` to allow type error over an ICE. + canonicalizer.tcx.sess.span_delayed_bug( rustc_span::DUMMY_SP, format!("unexpected region in query response: `{r:?}`"), ); diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 2a9e20b9f8f..c3d07415bb8 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -175,7 +175,7 @@ impl<'tcx> InferCtxt<'tcx> { &mut OriginalQueryValues::default(), ); self.tcx.check_tys_might_be_eq(canonical).map_err(|_| { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( DUMMY_SP, format!("cannot relate consts of different types (a={a:?}, b={b:?})",), ) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3be23796550..9cdf78484d4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -131,13 +131,13 @@ pub struct TypeErrCtxt<'a, 'tcx> { impl Drop for TypeErrCtxt<'_, '_> { fn drop(&mut self) { - if let Some(_) = self.infcx.tcx.sess.has_errors_or_delayed_span_bugs() { + if let Some(_) = self.infcx.tcx.sess.has_errors_or_span_delayed_bugs() { // ok, emitted an error. } else { self.infcx .tcx .sess - .delay_good_path_bug("used a `TypeErrCtxt` without raising an error or lint"); + .good_path_delayed_bug("used a `TypeErrCtxt` without raising an error or lint"); } } } @@ -517,7 +517,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.tcx .sess - .delay_span_bug(self.tcx.def_span(generic_param_scope), "expected region errors") + .span_delayed_bug(self.tcx.def_span(generic_param_scope), "expected region errors") } // This method goes through all the errors and try to group certain types diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 7dd19c8e15f..8fe6c1b0d86 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -374,7 +374,7 @@ impl<'tcx> InferCtxt<'tcx> { multi_suggestions, bad_label, } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + .into_diagnostic(self.tcx.sess.diagnostic()), TypeAnnotationNeeded::E0283 => AmbiguousImpl { span, source_kind, @@ -384,7 +384,7 @@ impl<'tcx> InferCtxt<'tcx> { multi_suggestions, bad_label, } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + .into_diagnostic(self.tcx.sess.diagnostic()), TypeAnnotationNeeded::E0284 => AmbiguousReturn { span, source_kind, @@ -394,7 +394,7 @@ impl<'tcx> InferCtxt<'tcx> { multi_suggestions, bad_label, } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + .into_diagnostic(self.tcx.sess.diagnostic()), } } } @@ -581,7 +581,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { multi_suggestions, bad_label: None, } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + .into_diagnostic(self.tcx.sess.diagnostic()), TypeAnnotationNeeded::E0283 => AmbiguousImpl { span, source_kind, @@ -591,7 +591,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { multi_suggestions, bad_label: None, } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + .into_diagnostic(self.tcx.sess.diagnostic()), TypeAnnotationNeeded::E0284 => AmbiguousReturn { span, source_kind, @@ -601,7 +601,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { multi_suggestions, bad_label: None, } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), + .into_diagnostic(self.tcx.sess.diagnostic()), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 781cc192ae5..fed76cd65cf 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -140,7 +140,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, notes: reference_valid.into_iter().chain(content_valid).collect(), } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + .into_diagnostic(self.tcx.sess.diagnostic()) } infer::RelateObjectBound(span) => { let object_valid = note_and_explain::RegionExplanation::new( @@ -161,7 +161,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, notes: object_valid.into_iter().chain(pointer_valid).collect(), } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + .into_diagnostic(self.tcx.sess.diagnostic()) } infer::RelateParamBound(span, ty, opt_span) => { let prefix = match *sub { @@ -177,7 +177,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.tcx, sub, opt_span, prefix, suffix, ); FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + .into_diagnostic(self.tcx.sess.diagnostic()) } infer::RelateRegionParamBound(span) => { let param_instantiated = note_and_explain::RegionExplanation::new( @@ -198,7 +198,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + .into_diagnostic(self.tcx.sess.diagnostic()) } infer::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( @@ -220,7 +220,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty: self.resolve_vars_if_possible(ty), notes: pointer_valid.into_iter().chain(data_valid).collect(), } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + .into_diagnostic(self.tcx.sess.diagnostic()) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { let mut err = self.report_extra_impl_obligation( @@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, notes: instantiated.into_iter().chain(must_outlive).collect(), } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + .into_diagnostic(self.tcx.sess.diagnostic()) } }; if sub.is_error() || sup.is_error() { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index b0e82a92674..b6e86e2b676 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -798,7 +798,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Errors in earlier passes can yield error variables without // resolution errors here; delay ICE in favor of those errors. - self.tcx().sess.delay_span_bug( + self.tcx().sess.span_delayed_bug( self.var_infos[node_idx].origin.span(), format!( "collect_error_for_expanding_node() could not find \ diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index bb16d97eb85..32c09e491c7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1433,7 +1433,7 @@ impl<'tcx> InferCtxt<'tcx> { let guar = self .tcx .sess - .delay_span_bug(DUMMY_SP, format!("`{value:?}` is not fully resolved")); + .span_delayed_bug(DUMMY_SP, format!("`{value:?}` is not fully resolved")); Ok(self.tcx.fold_regions(value, |re, _| { if re.is_var() { ty::Region::new_error(self.tcx, guar) } else { re } })) diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index ee6a3fd0c82..77c1d6a7313 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -494,7 +494,7 @@ where // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. assert!(!self.infcx.next_trait_solver()); - self.tcx().sess.delay_span_bug( + self.tcx().sess.span_delayed_bug( self.delegate.span(), "failure to relate an opaque to itself should result in an error later on", ); @@ -552,7 +552,7 @@ where match b.kind() { ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { // Forbid inference variables in the RHS. - self.infcx.tcx.sess.delay_span_bug( + self.infcx.tcx.sess.span_delayed_bug( self.delegate.span(), format!("unexpected inference var {b:?}",), ); diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index a737761ba22..715006a50d3 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -41,7 +41,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { fn drop(&mut self) { if !self.opaque_types.is_empty() { ty::tls::with(|tcx| { - tcx.sess.delay_span_bug(DUMMY_SP, format!("{:?}", self.opaque_types)) + tcx.sess.span_delayed_bug(DUMMY_SP, format!("{:?}", self.opaque_types)) }); } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index c6cbde4dba9..395830d937b 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -254,7 +254,7 @@ where // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( origin.span(), format!("unresolved inference variable in outlives: {v:?}"), ); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 35a8fe6dc47..ce619ae8a0d 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -180,7 +180,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( rustc_span::DUMMY_SP, format!("unresolved inference variable in outlives: {v:?}"), ); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 88212d164bc..fab8a18f2dc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -519,9 +519,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P match result { Ok(_) => { if sess.opts.json_artifact_notifications { - sess.parse_sess - .span_diagnostic - .emit_artifact_notification(deps_filename, "dep-info"); + sess.diagnostic().emit_artifact_notification(deps_filename, "dep-info"); } } Err(error) => { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index e81c3f42a16..e9611c74a68 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -194,16 +194,16 @@ impl<'tcx> Queries<'tcx> { let Some((def_id, _)) = tcx.entry_fn(()) else { return }; for attr in tcx.get_attrs(def_id, sym::rustc_error) { match attr.meta_item_list() { - // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`. + // Check if there is a `#[rustc_error(span_delayed_bug_from_inside_query)]`. Some(list) if list.iter().any(|list_item| { matches!( list_item.ident().map(|i| i.name), - Some(sym::delay_span_bug_from_inside_query) + Some(sym::span_delayed_bug_from_inside_query) ) }) => { - tcx.ensure().trigger_delay_span_bug(def_id); + tcx.ensure().trigger_span_delayed_bug(def_id); } // Bare `#[rustc_error]`. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index e6e132978ed..714af977fb5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -5,10 +5,11 @@ use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, - InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, - LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, OutFileName, - OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, - SwitchWithOptPath, SymbolManglingVersion, TraitSolver, WasiExecModel, + FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, + OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, + ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, + WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -758,6 +759,7 @@ fn test_unstable_options_tracking_hash() { tracked!(flatten_format_args, false); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); + tracked!(function_return, FunctionReturn::ThunkExtern); tracked!(function_sections, Some(false)); tracked!(human_readable_cgu_names, true); tracked!(incremental_ignore_spans, true); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 9bc9f88d3f7..024e542d4af 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -926,6 +926,10 @@ pub trait LintContext { if elided { "'static " } else { "'static" }, Applicability::MachineApplicable ); + }, + BuiltinLintDiagnostics::RedundantImportVisibility { max_vis, span } => { + db.span_note(span, format!("the most public imported item is `{max_vis}`")); + db.help("reduce the glob import's visibility or increase visibility of imported items"); } } // Rewrap `db`, and pass control to the user. diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 36aa959ddc9..4cccaeeca84 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -430,7 +430,7 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>( // that was not lint-checked (perhaps it doesn't exist?). This is a bug. for (id, lints) in cx.context.buffered.map { for early_lint in lints { - sess.delay_span_bug( + sess.span_delayed_bug( early_lint.span, format!( "failed to process buffered lint here (dummy = {})", diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 878c1a65dbf..de0abe04611 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -583,6 +583,10 @@ pub enum BuiltinLintDiagnostics { elided: bool, span: Span, }, + RedundantImportVisibility { + span: Span, + max_vis: String, + }, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index ad97ede8e9c..834120efa67 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -89,6 +89,7 @@ enum LLVMRustAttribute { AllocatedPointer = 38, AllocAlign = 39, SanitizeSafeStack = 40, + FnRetThunkExtern = 41, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7f033265136..0edcac93b62 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -525,12 +525,9 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. -extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M, - bool DisableSimplifyLibCalls) { +extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M) { Triple TargetTriple(unwrap(M)->getTargetTriple()); TargetLibraryInfoImpl TLII(TargetTriple); - if (DisableSimplifyLibCalls) - TLII.disableAllFunctions(); unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII)); } @@ -697,7 +694,7 @@ LLVMRustOptimize( bool IsLinkerPluginLTO, bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, - bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, + bool EmitLifetimeMarkers, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, const char *InstrProfileOutput, @@ -795,8 +792,6 @@ LLVMRustOptimize( Triple TargetTriple(TheModule->getTargetTriple()); std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple)); - if (DisableSimplifyLibCalls) - TLII->disableAllFunctions(); FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); PB.registerModuleAnalyses(MAM); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index bf870e28acd..b227dd76f02 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -278,6 +278,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::AllocAlign; case SanitizeSafeStack: return Attribute::SafeStack; + case FnRetThunkExtern: + return Attribute::FnRetThunkExtern; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 169b56d40fa..301e3f2620d 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -7,8 +7,9 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, AllocatorKind}; use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; +use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; @@ -16,16 +17,14 @@ use rustc_hir::definitions::Definitions; use rustc_index::IndexVec; use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, CrateType, ExternLocation}; -use rustc_session::cstore::{ - CrateDepKind, CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn, -}; +use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; use rustc_session::lint; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::spec::{PanicStrategy, TargetTriple}; +use rustc_target::spec::{PanicStrategy, Target, TargetTriple}; use proc_macro::bridge::client::ProcMacro; use std::error::Error; @@ -34,6 +33,17 @@ use std::path::Path; use std::time::Duration; use std::{cmp, iter}; +/// The backend's way to give the crate store access to the metadata in a library. +/// Note that it returns the raw metadata bytes stored in the library file, whether +/// it is compressed, uncompressed, some weird mix, etc. +/// rmeta files are backend independent and not handled here. +pub trait MetadataLoader { + fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; +} + +pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; + pub struct CStore { metadata_loader: Box<MetadataLoaderDyn>, @@ -257,7 +267,7 @@ impl CStore { let unused_externs = self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>(); let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>(); - tcx.sess.parse_sess.span_diagnostic.emit_unused_externs( + tcx.sess.diagnostic().emit_unused_externs( level, json_unused_externs.is_loud(), &unused_externs, diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index 4b451253f2b..c95ef01faa7 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -91,10 +91,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { } }; if tcx.sess.opts.json_artifact_notifications { - tcx.sess - .parse_sess - .span_diagnostic - .emit_artifact_notification(out_filename.as_path(), "metadata"); + tcx.sess.diagnostic().emit_artifact_notification(out_filename.as_path(), "metadata"); } (filename, None) } else { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2b5773320b4..bcc124524eb 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -212,7 +212,7 @@ //! no means all of the necessary details. Take a look at the rest of //! metadata::locator or metadata::creader for all the juicy details! -use crate::creader::Library; +use crate::creader::{Library, MetadataLoader}; use crate::errors; use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; @@ -223,7 +223,7 @@ use rustc_data_structures::svh::Svh; use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_fs_util::try_canonicalize; use rustc_session::config; -use rustc_session::cstore::{CrateSource, MetadataLoader}; +use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index c1884bb8068..8c1e58fefc5 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -4,9 +4,10 @@ /// /// If you have a span available, you should use [`span_bug`] instead. /// -/// If the bug should only be emitted when compilation didn't fail, [`Session::delay_span_bug`] may be useful. +/// If the bug should only be emitted when compilation didn't fail, [`Session::span_delayed_bug`] +/// may be useful. /// -/// [`Session::delay_span_bug`]: rustc_session::Session::delay_span_bug +/// [`Session::span_delayed_bug`]: rustc_session::Session::span_delayed_bug /// [`span_bug`]: crate::span_bug #[macro_export] macro_rules! bug { @@ -23,9 +24,10 @@ macro_rules! bug { /// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger /// ICEs. /// -/// If the bug should only be emitted when compilation didn't fail, [`Session::delay_span_bug`] may be useful. +/// If the bug should only be emitted when compilation didn't fail, [`Session::span_delayed_bug`] +/// may be useful. /// -/// [`Session::delay_span_bug`]: rustc_session::Session::delay_span_bug +/// [`Session::span_delayed_bug`]: rustc_session::Session::span_delayed_bug #[macro_export] macro_rules! span_bug { ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) }); diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index f7a55fa95b6..27d82f5fefc 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -566,7 +566,7 @@ impl<'tcx> TyCtxt<'tcx> { |span, def_id| { // The API could be uncallable for other reasons, for example when a private module // was referenced. - self.sess.delay_span_bug(span, format!("encountered unmarked API: {def_id:?}")); + self.sess.span_delayed_bug(span, format!("encountered unmarked API: {def_id:?}")); }, ) } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index aded3e495d9..09e56b2e4a8 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -315,7 +315,7 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> { Self::uninit_inner(size, align, || { ty::tls::with(|tcx| { - tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation") + tcx.sess.span_delayed_bug(DUMMY_SP, "exhausted memory during interpretation") }); InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into() }) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index e360fb3eaaf..e5f891fcc91 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -199,7 +199,7 @@ pub struct LitToConstInput<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)] pub enum LitToConstError { /// The literal's inferred type did not match the expected `ty` in the input. - /// This is used for graceful error handling (`delay_span_bug`) in + /// This is used for graceful error handling (`span_delayed_bug`) in /// type checking (`Const::from_anon_const`). TypeError, Reported(ErrorGuaranteed), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 29decd0f050..03f3ceb8d17 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -108,9 +108,9 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { - /// This exists purely for testing the interactions between delay_span_bug and incremental. - query trigger_delay_span_bug(key: DefId) -> () { - desc { "triggering a delay span bug for testing incremental" } + /// This exists purely for testing the interactions between span_delayed_bug and incremental. + query trigger_span_delayed_bug(key: DefId) -> () { + desc { "triggering a span delayed bug for testing incremental" } } /// Collects the list of all tools registered using `#![register_tool]`. diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 9a6eba89655..0d1f3c1f8b5 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -551,7 +551,7 @@ macro_rules! define_feedable { // We have an inconsistency. This can happen if one of the two // results is tainted by errors. In this case, delay a bug to // ensure compilation is doomed, and keep the `old` value. - tcx.sess.delay_span_bug(DUMMY_SP, format!( + tcx.sess.span_delayed_bug(DUMMY_SP, format!( "Trying to feed an already recorded value for query {} key={key:?}:\n\ old value: {old:?}\nnew value: {value:?}", stringify!($name), diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 7650389415c..1d9a25628b0 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -481,7 +481,7 @@ impl<'tcx> AdtDef<'tcx> { ErrorHandled::Reported(..) => "enum discriminant evaluation failed", ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics", }; - tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg); + tcx.sess.span_delayed_bug(tcx.def_span(expr_did), msg); None } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index d0a1c943292..a216cc28c8a 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -144,7 +144,7 @@ impl<'tcx> Const<'tcx> { span: S, msg: &'static str, ) -> Const<'tcx> { - let reported = tcx.sess.delay_span_bug(span, msg); + let reported = tcx.sess.span_delayed_bug(span, msg); Const::new_error(tcx, reported, ty) } @@ -208,7 +208,7 @@ impl<'tcx> Const<'tcx> { match tcx.at(expr.span).lit_to_const(lit_input) { Ok(c) => return Some(c), Err(e) => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( expr.span, format!("Const::from_anon_const: couldn't lit_to_const {e:?}"), ); @@ -304,8 +304,16 @@ impl<'tcx> Const<'tcx> { let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?; - Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type")) + let Some(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)? + else { + // This can happen when we run on ill-typed code. + let e = tcx.sess.span_delayed_bug( + span.unwrap_or(DUMMY_SP), + "`ty::Const::eval` called on a non-valtree-compatible type", + ); + return Err(e.into()); + }; + Ok(c) } ConstKind::Value(val) => Ok(val), ConstKind::Error(g) => Err(g.into()), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bb02c6e0c78..ff690db7bee 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -714,8 +714,10 @@ impl<'tcx> TyCtxt<'tcx> { { Bound::Included(a) } else { - self.sess - .delay_span_bug(attr.span, "invalid rustc_layout_scalar_valid_range attribute"); + self.sess.span_delayed_bug( + attr.span, + "invalid rustc_layout_scalar_valid_range attribute", + ); Bound::Unbounded } }; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4d8ac19dbe2..e1d1f361091 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -282,8 +282,8 @@ pub struct LayoutCx<'tcx, C> { impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { type TargetDataLayoutRef = &'tcx TargetDataLayout; - fn delay_bug(&self, txt: String) { - self.tcx.sess.delay_span_bug(DUMMY_SP, txt); + fn delayed_bug(&self, txt: String) { + self.tcx.sess.span_delayed_bug(DUMMY_SP, txt); } fn current_data_layout(&self) -> Self::TargetDataLayoutRef { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 24cba913bb8..9feda4d205e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -296,6 +296,23 @@ pub enum Visibility<Id = LocalDefId> { Restricted(Id), } +impl Visibility { + pub fn to_string(self, def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { + match self { + ty::Visibility::Restricted(restricted_id) => { + if restricted_id.is_top_level_module() { + "pub(crate)".to_string() + } else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() { + "pub(self)".to_string() + } else { + format!("pub({})", tcx.item_name(restricted_id.to_def_id())) + } + } + ty::Visibility::Public => "pub".to_string(), + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub enum BoundConstness { /// `T: Trait` diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d50743bc207..68dd8dee87c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3025,7 +3025,7 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> { // // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths` // wrapper can be used to suppress this query, in exchange for full paths being formatted. - tcx.sess.delay_good_path_bug( + tcx.sess.good_path_delayed_bug( "trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging", ); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f12a512da31..e10b5706b48 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1545,7 +1545,7 @@ impl<'tcx> Region<'tcx> { tcx.intern_region(ty::ReError(reported)) } - /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` to ensure it + /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it /// gets used. #[track_caller] pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { @@ -1556,7 +1556,7 @@ impl<'tcx> Region<'tcx> { ) } - /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` with the given + /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given /// `msg` to ensure it gets used. #[track_caller] pub fn new_error_with_message<S: Into<MultiSpan>>( @@ -1564,7 +1564,7 @@ impl<'tcx> Region<'tcx> { span: S, msg: &'static str, ) -> Region<'tcx> { - let reported = tcx.sess.delay_span_bug(span, msg); + let reported = tcx.sess.span_delayed_bug(span, msg); Region::new_error(tcx, reported) } @@ -1997,13 +1997,13 @@ impl<'tcx> Ty<'tcx> { Ty::new(tcx, Error(reported)) } - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. + /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` to ensure it gets used. #[track_caller] pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { Ty::new_error_with_message(tcx, DUMMY_SP, "TyKind::Error constructed but no error reported") } - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to + /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg` to /// ensure it gets used. #[track_caller] pub fn new_error_with_message<S: Into<MultiSpan>>( @@ -2011,7 +2011,7 @@ impl<'tcx> Ty<'tcx> { span: S, msg: impl Into<String>, ) -> Ty<'tcx> { - let reported = tcx.sess.delay_span_bug(span, msg); + let reported = tcx.sess.span_delayed_bug(span, msg); Ty::new(tcx, Error(reported)) } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 4a5c89411da..d372c1cd604 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -391,7 +391,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> { self.pat_binding_modes().get(id).copied().or_else(|| { - s.delay_span_bug(sp, "missing binding mode"); + s.span_delayed_bug(sp, "missing binding mode"); None }) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 40d592ddef0..70252a4dc67 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -361,7 +361,7 @@ impl<'tcx> TyCtxt<'tcx> { let Some(item_id) = self.associated_item_def_ids(impl_did).first() else { self.sess - .delay_span_bug(self.def_span(impl_did), "Drop impl without drop function"); + .span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function"); return; }; diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index 634ed5ec54b..21c1a93fde8 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -38,16 +38,16 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>( }) } -/// A query to trigger a `delay_span_bug`. Clearly, if one has a `tcx` one can already trigger a -/// `delay_span_bug`, so what is the point of this? It exists to help us test `delay_span_bug`'s +/// A query to trigger a `span_delayed_bug`. Clearly, if one has a `tcx` one can already trigger a +/// `span_delayed_bug`, so what is the point of this? It exists to help us test `span_delayed_bug`'s /// interactions with the query system and incremental. -pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { - tcx.sess.delay_span_bug( +pub fn trigger_span_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { + tcx.sess.span_delayed_bug( tcx.def_span(key), - "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]", + "delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]", ); } pub fn provide(providers: &mut crate::query::Providers) { - *providers = crate::query::Providers { trigger_delay_span_bug, ..*providers }; + *providers = crate::query::Providers { trigger_span_delayed_bug, ..*providers }; } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 4ed49e78738..3bfffa7354d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -114,7 +114,7 @@ fn lit_to_mir_constant<'tcx>( let width = tcx .layout_of(param_ty) .map_err(|_| { - LitToConstError::Reported(tcx.sess.delay_span_bug( + LitToConstError::Reported(tcx.sess.span_delayed_bug( DUMMY_SP, format!("couldn't compute width of literal: {:?}", lit_input.lit), )) @@ -158,7 +158,7 @@ fn lit_to_mir_constant<'tcx>( } (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg) .ok_or_else(|| { - LitToConstError::Reported(tcx.sess.delay_span_bug( + LitToConstError::Reported(tcx.sess.span_delayed_bug( DUMMY_SP, format!("couldn't parse float literal: {:?}", lit_input.lit), )) @@ -167,7 +167,7 @@ fn lit_to_mir_constant<'tcx>( (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), (ast::LitKind::Err, _) => { return Err(LitToConstError::Reported( - tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"), + tcx.sess.span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"), )); } _ => return Err(LitToConstError::TypeError), diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c17fdf71b55..1f7c6d7875b 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -470,7 +470,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if let Some((assigned_ty, assignment_span)) = self.assignment_info { if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. - self.tcx.sess.delay_span_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}")); + self.tcx.sess.span_delayed_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}")); } } else { self.requires_unsafe(expr.span, AccessToUnionField); diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index fbb74650faa..240aa10ac91 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -16,7 +16,7 @@ pub(crate) fn lit_to_const<'tcx>( let width = tcx .layout_of(param_ty) .map_err(|_| { - LitToConstError::Reported(tcx.sess.delay_span_bug( + LitToConstError::Reported(tcx.sess.span_delayed_bug( DUMMY_SP, format!("couldn't compute width of literal: {:?}", lit_input.lit), )) @@ -62,7 +62,7 @@ pub(crate) fn lit_to_const<'tcx>( (ast::LitKind::Float(n, _), ty::Float(fty)) => { let bits = parse_float_into_scalar(*n, *fty, neg) .ok_or_else(|| { - LitToConstError::Reported(tcx.sess.delay_span_bug( + LitToConstError::Reported(tcx.sess.span_delayed_bug( DUMMY_SP, format!("couldn't parse float literal: {:?}", lit_input.lit), )) @@ -73,7 +73,7 @@ pub(crate) fn lit_to_const<'tcx>( (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), (ast::LitKind::Err, _) => { return Err(LitToConstError::Reported( - tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"), + tcx.sess.span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"), )); } _ => return Err(LitToConstError::TypeError), diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 5edb2054fd4..eb548ad29eb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let msg = format!( "found bad range pattern endpoint `{expr:?}` outside of error recovery" ); - return Err(self.tcx.sess.delay_span_bug(expr.span, msg)); + return Err(self.tcx.sess.span_delayed_bug(expr.span, msg)); }; Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const)) } @@ -178,7 +178,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ) -> Result<PatKind<'tcx>, ErrorGuaranteed> { if lo_expr.is_none() && hi_expr.is_none() { let msg = format!("found twice-open range pattern (`..`) outside of error recovery"); - return Err(self.tcx.sess.delay_span_bug(span, msg)); + return Err(self.tcx.sess.span_delayed_bug(span, msg)); } let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?; diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 84e7362c3d0..f246de55ca8 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -242,7 +242,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( self.source_info.span, format!("union fields that need dropping should be impossible: {assigned_ty}") ); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index d626fed3275..1373596fd2b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1510,8 +1510,10 @@ impl<'tcx> MirPass<'tcx> for StateTransform { (args.discr_ty(tcx), movability == hir::Movability::Movable) } _ => { - tcx.sess - .delay_span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}")); + tcx.sess.span_delayed_bug( + body.span, + format!("unexpected coroutine type {coroutine_ty}"), + ); return; } }; diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 83517aef7e2..f7188ea83fc 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -316,7 +316,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.init_data.seek_before(self.body.terminator_loc(bb)); let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); if maybe_dead { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( terminator.source_info.span, format!( "drop of untracked, uninitialized value {bb:?}, place {place:?} ({path:?})" @@ -381,7 +381,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { LookupResult::Parent(None) => {} LookupResult::Parent(Some(_)) => { if !replace { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( terminator.source_info.span, format!("drop of untracked value {bb:?}"), ); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index fff760ba399..89e897191e8 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -266,7 +266,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { let body = &tcx.mir_const(def).borrow(); if body.return_ty().references_error() { - tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors"); + tcx.sess.span_delayed_bug(body.span, "mir_const_qualif: MIR had errors"); return Default::default(); } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 6e0765f74fe..92df2da8710 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -223,9 +223,6 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::Literal { kind, suffix_start } => { let suffix_start = start + BytePos(suffix_start); let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); - if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind { - self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos)); - } let suffix = if suffix_start < self.pos { let string = self.str_from(suffix_start); if string == "_" { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index bad7c19cc27..422bb79308d 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -56,7 +56,7 @@ impl<'a> Parser<'a> { } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style != ast::AttrStyle::Outer { let span = self.token.span; - let mut err = self.sess.span_diagnostic.struct_span_err_with_code( + let mut err = self.diagnostic().struct_span_err_with_code( span, fluent::parse_inner_doc_comment_not_permitted, error_code!(E0753), @@ -418,7 +418,7 @@ impl<'a> Parser<'a> { } Err(InvalidMetaItem { span: self.token.span, token: self.token.clone() } - .into_diagnostic(&self.sess.span_diagnostic)) + .into_diagnostic(self.diagnostic())) } } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index c4e8d9006e6..c66a7176aab 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -41,7 +41,7 @@ impl AttrWrapper { } pub(crate) fn take_for_recovery(self, sess: &ParseSess) -> AttrVec { - sess.span_diagnostic.delay_span_bug( + sess.span_diagnostic.span_delayed_bug( self.attrs.get(0).map(|attr| attr.span).unwrap_or(DUMMY_SP), "AttrVec is taken for recovery but no error is produced", ); @@ -266,9 +266,8 @@ impl<'a> Parser<'a> { if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) { inner_attr_replace_ranges.push(attr_range); } else { - self.sess - .span_diagnostic - .delay_span_bug(inner_attr.span, "Missing token range for attribute"); + self.diagnostic() + .span_delayed_bug(inner_attr.span, "Missing token range for attribute"); } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 8921c1c6a03..98e68e682ab 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -18,7 +18,6 @@ use crate::errors::{ UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; - use crate::fluent_generated as fluent; use crate::parser; use crate::parser::attr::InnerAttrPolicy; @@ -247,11 +246,11 @@ impl<'a> Parser<'a> { sp: S, m: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - self.sess.span_diagnostic.struct_span_err(sp, m) + self.diagnostic().struct_span_err(sp, m) } pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: impl Into<String>) -> ! { - self.sess.span_diagnostic.span_bug(sp, m) + self.diagnostic().span_bug(sp, m) } pub(super) fn diagnostic(&self) -> &'a Handler { @@ -285,7 +284,7 @@ impl<'a> Parser<'a> { span: self.prev_token.span, missing_comma: None, } - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } let valid_follow = &[ @@ -348,7 +347,7 @@ impl<'a> Parser<'a> { suggest_remove_comma, help_cannot_start_number, }; - let mut err = err.into_diagnostic(&self.sess.span_diagnostic); + let mut err = err.into_diagnostic(self.diagnostic()); // if the token we have is a `<` // it *might* be a misplaced generic @@ -772,8 +771,10 @@ impl<'a> Parser<'a> { && let ast::AttrKind::Normal(attr_kind) = &attr.kind && let [segment] = &attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg + && let Some(args_span) = attr_kind.item.args.span() && let Ok(next_attr) = snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind + && let Some(next_attr_args_span) = next_attr_kind.item.args.span() && let [next_segment] = &next_attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg && let Ok(next_expr) = snapshot.parse_expr() @@ -787,23 +788,14 @@ impl<'a> Parser<'a> { let margin = self.sess.source_map().span_to_margin(next_expr.span).unwrap_or(0); let sugg = vec![ (attr.span.with_hi(segment.span().hi()), "if cfg!".to_string()), - ( - attr_kind.item.args.span().unwrap().shrink_to_hi().with_hi(attr.span.hi()), - " {".to_string(), - ), + (args_span.shrink_to_hi().with_hi(attr.span.hi()), " {".to_string()), (expr.span.shrink_to_lo(), " ".to_string()), ( next_attr.span.with_hi(next_segment.span().hi()), "} else if cfg!".to_string(), ), ( - next_attr_kind - .item - .args - .span() - .unwrap() - .shrink_to_hi() - .with_hi(next_attr.span.hi()), + next_attr_args_span.shrink_to_hi().with_hi(next_attr.span.hi()), " {".to_string(), ), (next_expr.span.shrink_to_lo(), " ".to_string()), @@ -1426,7 +1418,7 @@ impl<'a> Parser<'a> { // Not entirely sure now, but we bubble the error up with the // suggestion. self.restore_snapshot(snapshot); - Err(err.into_diagnostic(&self.sess.span_diagnostic)) + Err(err.into_diagnostic(self.diagnostic())) } } } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind { @@ -1441,7 +1433,7 @@ impl<'a> Parser<'a> { } // Consume the fn call arguments. match self.consume_fn_args() { - Err(()) => Err(err.into_diagnostic(&self.sess.span_diagnostic)), + Err(()) => Err(err.into_diagnostic(self.diagnostic())), Ok(()) => { self.sess.emit_err(err); // FIXME: actually check that the two expressions in the binop are @@ -1467,7 +1459,7 @@ impl<'a> Parser<'a> { mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } else { // These cases cause too many knock-down errors, bail out (#61329). - Err(err.into_diagnostic(&self.sess.span_diagnostic)) + Err(err.into_diagnostic(self.diagnostic())) } }; } @@ -2522,8 +2514,7 @@ impl<'a> Parser<'a> { Ok(Some(GenericArg::Const(self.parse_const_arg()?))) } else { let after_kw_const = self.token.span; - self.recover_const_arg(after_kw_const, err.into_diagnostic(&self.sess.span_diagnostic)) - .map(Some) + self.recover_const_arg(after_kw_const, err.into_diagnostic(self.diagnostic())).map(Some) } } @@ -2886,7 +2877,7 @@ impl<'a> Parser<'a> { span: path.span.shrink_to_hi(), between: between_span, } - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b1b77305e4f..f8444881d1a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1269,7 +1269,7 @@ impl<'a> Parser<'a> { .collect(), }, } - .into_diagnostic(&self.sess.span_diagnostic); + .into_diagnostic(self.diagnostic()); replacement_err.emit(); let old_err = mem::replace(err, replacement_err); @@ -1691,7 +1691,7 @@ impl<'a> Parser<'a> { err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, ) -> L { if let Some(mut diag) = - self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) + self.diagnostic().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { diag.span_suggestion_verbose( lifetime.span.shrink_to_hi(), @@ -1882,7 +1882,7 @@ impl<'a> Parser<'a> { let Some((ident, false)) = self.token.ident() else { let err = errors::ExpectedBuiltinIdent { span: self.token.span } - .into_diagnostic(&self.sess.span_diagnostic); + .into_diagnostic(self.diagnostic()); return Err(err); }; self.sess.gated_spans.gate(sym::builtin_syntax, ident.span); @@ -1893,7 +1893,7 @@ impl<'a> Parser<'a> { Ok(res) } else { let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name } - .into_diagnostic(&self.sess.span_diagnostic); + .into_diagnostic(self.diagnostic()); return Err(err); }; self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?; @@ -1957,7 +1957,7 @@ impl<'a> Parser<'a> { && matches!(e.kind, ExprKind::Err) { let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } - .into_diagnostic(&self.sess.span_diagnostic); + .into_diagnostic(self.diagnostic()); err.downgrade_to_delayed_bug(); return Err(err); } @@ -2169,7 +2169,7 @@ impl<'a> Parser<'a> { return Err(errors::MissingSemicolonBeforeArray { open_delim: open_delim_span, semicolon: prev_span.shrink_to_hi(), - }.into_diagnostic(&self.sess.span_diagnostic)); + }.into_diagnostic(self.diagnostic())); } Ok(_) => (), Err(err) => err.cancel(), @@ -2309,7 +2309,7 @@ impl<'a> Parser<'a> { if self.check_keyword(kw::Async) { let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); Err(errors::AsyncMoveOrderIncorrect { span: move_async_span } - .into_diagnostic(&self.sess.span_diagnostic)) + .into_diagnostic(self.diagnostic())) } else { Ok(CaptureBy::Value { move_kw: move_kw_span }) } @@ -2499,7 +2499,7 @@ impl<'a> Parser<'a> { }; if self.prev_token.kind == token::BinOp(token::Or) { // This was part of a closure, the that part of the parser recover. - return Err(err.into_diagnostic(&self.sess.span_diagnostic)); + return Err(err.into_diagnostic(self.diagnostic())); } else { Some(self.sess.emit_err(err)) } @@ -3148,7 +3148,7 @@ impl<'a> Parser<'a> { let (attrs, body) = self.parse_inner_attrs_and_block()?; if self.eat_keyword(kw::Catch) { Err(errors::CatchAfterTry { span: self.prev_token.span } - .into_diagnostic(&self.sess.span_diagnostic)) + .into_diagnostic(self.diagnostic())) } else { let span = span_lo.to(body.span); self.sess.gated_spans.gate(sym::try_blocks, span); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ab18e40482e..a737f37a104 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -444,11 +444,7 @@ impl<'a> Parser<'a> { None }; - if let Some(err) = err { - Err(err.into_diagnostic(&self.sess.span_diagnostic)) - } else { - Ok(()) - } + if let Some(err) = err { Err(err.into_diagnostic(self.diagnostic())) } else { Ok(()) } } fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> { @@ -1382,8 +1378,7 @@ impl<'a> Parser<'a> { let span = self.prev_token.span.shrink_to_hi(); let err: DiagnosticBuilder<'_, ErrorGuaranteed> = - errors::MissingConstType { span, colon, kind } - .into_diagnostic(&self.sess.span_diagnostic); + errors::MissingConstType { span, colon, kind }.into_diagnostic(self.diagnostic()); err.stash(span, StashKey::ItemNoType); // The user intended that the type be inferred, @@ -1400,7 +1395,7 @@ impl<'a> Parser<'a> { self.bump(); self.sess.emit_err(err); } else { - return Err(err.into_diagnostic(&self.sess.span_diagnostic)); + return Err(err.into_diagnostic(self.diagnostic())); } } @@ -1600,7 +1595,7 @@ impl<'a> Parser<'a> { } else { let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone()); - return Err(err.into_diagnostic(&self.sess.span_diagnostic)); + return Err(err.into_diagnostic(self.diagnostic())); }; Ok((class_name, ItemKind::Struct(vdata, generics))) @@ -1796,7 +1791,7 @@ impl<'a> Parser<'a> { let sp = previous_span.shrink_to_hi(); err.missing_comma = Some(sp); } - return Err(err.into_diagnostic(&self.sess.span_diagnostic)); + return Err(err.into_diagnostic(self.diagnostic())); } } _ => { @@ -1846,7 +1841,7 @@ impl<'a> Parser<'a> { // Make sure an error was emitted (either by recovering an angle bracket, // or by finding an identifier as the next token), since we're // going to continue parsing - assert!(self.sess.span_diagnostic.has_errors().is_some()); + assert!(self.diagnostic().has_errors().is_some()); } else { return Err(err); } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 06cc39fbb5a..4360a69e501 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -115,7 +115,7 @@ impl<'a> Parser<'a> { Some(item) => NtItem(item), None => { return Err(UnexpectedNonterminal::Item(self.token.span) - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } }, NonterminalKind::Block => { @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { Some(s) => NtStmt(P(s)), None => { return Err(UnexpectedNonterminal::Statement(self.token.span) - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { @@ -163,7 +163,7 @@ impl<'a> Parser<'a> { span: self.token.span, token: self.token.clone(), } - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } NonterminalKind::Path => { NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) @@ -181,7 +181,7 @@ impl<'a> Parser<'a> { span: self.token.span, token: self.token.clone(), } - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } } }; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 3d1d1ec8108..bd1bf2c7859 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -877,7 +877,7 @@ impl<'a> Parser<'a> { // will direct us over to `parse_enum_variant()`. if self.token == token::OpenDelim(Delimiter::Parenthesis) { return Err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span } - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(self.diagnostic())); } Ok(PatKind::Ident(binding_annotation, ident, sub)) @@ -991,7 +991,7 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { let mut err = ExpectedCommaAfterPatternField { span: self.token.span } - .into_diagnostic(&self.sess.span_diagnostic); + .into_diagnostic(self.diagnostic()); if let Some(mut delayed) = delayed_err { delayed.emit(); } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index f825363ae39..18a80aa34f8 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -31,7 +31,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if !errors.is_empty() { let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, message); + tcx.sess.span_delayed_bug(rustc_span::DUMMY_SP, message); } } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index a0ba4e481f6..c9e5eb50b3a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -592,7 +592,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match self.successors[ln] { Some(successor) => self.assigned_on_entry(successor, var), None => { - self.ir.tcx.sess.delay_span_bug(DUMMY_SP, "no successor"); + self.ir.tcx.sess.span_delayed_bug(DUMMY_SP, "no successor"); true } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index b8109d5bb06..e7ec4749efe 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -888,21 +888,6 @@ pub struct TestReachabilityVisitor<'tcx, 'a> { effective_visibilities: &'a EffectiveVisibilities, } -fn vis_to_string<'tcx>(def_id: LocalDefId, vis: ty::Visibility, tcx: TyCtxt<'tcx>) -> String { - match vis { - ty::Visibility::Restricted(restricted_id) => { - if restricted_id.is_top_level_module() { - "pub(crate)".to_string() - } else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() { - "pub(self)".to_string() - } else { - format!("pub({})", tcx.item_name(restricted_id.to_def_id())) - } - } - ty::Visibility::Public => "pub".to_string(), - } -} - impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { @@ -910,7 +895,7 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { let span = self.tcx.def_span(def_id.to_def_id()); if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) { for level in Level::all_levels() { - let vis_str = vis_to_string(def_id, *effective_vis.at_level(level), self.tcx); + let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx); if level != Level::Direct { error_msg.push_str(", "); } @@ -1268,7 +1253,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } else { self.tcx .sess - .delay_span_bug(expr.span, "no type-dependent def for method call"); + .span_delayed_bug(expr.span, "no type-dependent def for method call"); } } _ => {} @@ -1506,11 +1491,11 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { tcx: self.tcx, }) .into(), - item_vis_descr: &vis_to_string(self.item_def_id, reachable_at_vis, self.tcx), + item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx), ty_span: vis_span, ty_kind: kind, ty_descr: descr.into(), - ty_vis_descr: &vis_to_string(local_def_id, vis, self.tcx), + ty_vis_descr: &vis.to_string(local_def_id, self.tcx), }, ); } @@ -1589,8 +1574,8 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> { span, kind: self.tcx.def_descr(def_id.to_def_id()), descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(), - reachable_vis: &vis_to_string(def_id, *reachable_at_vis, self.tcx), - reexported_vis: &vis_to_string(def_id, *reexported_at_vis, self.tcx), + reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx), + reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx), }, ); } @@ -1843,7 +1828,7 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { .. }) => tr.path.res.opt_def_id().map_or_else( || { - tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id"); + tcx.sess.span_delayed_bug(tr.path.span, "trait without a def-id"); ty::Visibility::Public }, |def_id| tcx.visibility(def_id).expect_local(), diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 5acd012ef04..bc09972185a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -818,7 +818,7 @@ impl<D: Deps> DepGraphData<D> { None => {} } - if let None = qcx.dep_context().sess().has_errors_or_delayed_span_bugs() { + if let None = qcx.dep_context().sess().has_errors_or_span_delayed_bugs() { panic!("try_mark_previous_green() - Forcing the DepNode should have set its color") } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 2a55ec72c5f..d933f897833 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -605,7 +605,7 @@ pub(crate) fn report_cycle<'a>( note_span: (), }; - cycle_diag.into_diagnostic(&sess.parse_sess.span_diagnostic) + cycle_diag.into_diagnostic(sess.diagnostic()) } pub fn print_query_stack<Qcx: QueryContext>( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 2f9f094dae2..41638b38c74 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -138,7 +138,7 @@ where && let Some(span) = root.query.span { error.stash(span, StashKey::Cycle); - qcx.dep_context().sess().delay_span_bug(span, "delayed cycle error") + qcx.dep_context().sess().span_delayed_bug(span, "delayed cycle error") } else { error.emit() }; @@ -421,7 +421,7 @@ where // We have an inconsistency. This can happen if one of the two // results is tainted by errors. In this case, delay a bug to // ensure compilation is doomed. - qcx.dep_context().sess().delay_span_bug( + qcx.dep_context().sess().span_delayed_bug( DUMMY_SP, format!( "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 272483d4a98..a5faaaab639 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -127,8 +127,6 @@ resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here resolve_generic_params_from_outer_item_ty_param = type parameter from outer item -resolve_glob_import_doesnt_reexport = - glob import doesn't reexport anything because no candidate is public enough resolve_ident_bound_more_than_once_in_parameter_list = identifier `{$identifier}` is bound more than once in this parameter list @@ -200,7 +198,7 @@ resolve_param_in_non_trivial_anon_const = .label = cannot perform const operation using `{$name}` resolve_param_in_non_trivial_anon_const_help = - use `#![feature(generic_const_exprs)]` to allow generic const expressions + add `#![feature(generic_const_exprs)]` to allow generic const expressions resolve_param_in_ty_of_const_param = the type of const parameters must not depend on other generic parameters diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index a069c6f8e04..a9f7002e564 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1201,7 +1201,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; self.report_error(span, error); - self.tcx.sess.delay_span_bug(span, CG_BUG_STR); + self.tcx.sess.span_delayed_bug(span, CG_BUG_STR); } return Res::Err; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3774ae66420..b28ad671f12 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -8,7 +8,7 @@ use crate::errors::{ ItemsInTraitsAreNotImportable, }; use crate::Determinacy::{self, *}; -use crate::{fluent_generated as fluent, Namespace::*}; +use crate::Namespace::*; use crate::{module_to_string, names_to_string, ImportSuggestion}; use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; @@ -987,13 +987,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !is_prelude && let Some(max_vis) = max_vis.get() - && !max_vis.is_at_least(import.expect_vis(), self.tcx) + && let import_vis = import.expect_vis() + && !max_vis.is_at_least(import_vis, self.tcx) { - self.lint_buffer.buffer_lint( + let def_id = self.local_def_id(id); + let msg = format!( + "glob import doesn't reexport anything with visibility `{}` because no imported item is public enough", + import_vis.to_string(def_id, self.tcx) + ); + self.lint_buffer.buffer_lint_with_diagnostic( UNUSED_IMPORTS, id, import.span, - fluent::resolve_glob_import_doesnt_reexport, + msg.to_string(), + BuiltinLintDiagnostics::RedundantImportVisibility { + max_vis: max_vis.to_string(def_id, self.tcx), + span: import.span, + }, ); } return None; @@ -1059,7 +1069,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if res == Res::Err || has_ambiguity_error { this.tcx .sess - .delay_span_bug(import.span, "some error happened for an import"); + .span_delayed_bug(import.span, "some error happened for an import"); return; } if let Ok(initial_res) = initial_res { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 75a0541b89b..f20d5829030 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3544,7 +3544,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Res::SelfCtor(_) => { // We resolve `Self` in pattern position as an ident sometimes during recovery, // so delay a bug instead of ICEing. - self.r.tcx.sess.delay_span_bug( + self.r.tcx.sess.span_delayed_bug( ident.span, "unexpected `SelfCtor` in pattern, expected identifier" ); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5f21741223b..ca225416e36 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -710,7 +710,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Make sure compilation does not succeed if preferred macro resolution // has changed after the macro had been expanded. In theory all such // situations should be reported as errors, so this is a bug. - this.tcx.sess.delay_span_bug(span, "inconsistent resolution for a macro"); + this.tcx.sess.span_delayed_bug(span, "inconsistent resolution for a macro"); } } else { // It's possible that the macro was unresolved (indeterminate) and silently diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index fa1b6f9f13d..3a7959c332e 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -26,6 +26,10 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models + session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d6e7afb7d09..e694e150b31 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -8,23 +8,19 @@ use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{lint, HashStableContext}; use crate::{EarlyErrorHandler, Session}; - use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; -use rustc_target::abi::Align; -use rustc_target::spec::LinkSelfContainedComponents; -use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; -use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; - +use rustc_errors::emitter::HumanReadableErrorType; +use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; - -use rustc_errors::emitter::HumanReadableErrorType; -use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg}; - +use rustc_target::abi::Align; +use rustc_target::spec::LinkSelfContainedComponents; +use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; +use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -555,12 +551,15 @@ impl Default for ErrorOutputType { /// Parameter to control path trimming. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub enum TrimmedDefPaths { - /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query + /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive + /// query. #[default] Never, - /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug` + /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call + /// `good_path_delayed_bug`. Always, - /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug` + /// `try_print_trimmed_def_path` calls the expensive query, the query calls + /// `good_path_delayed_bug`. GoodPath, } @@ -1250,7 +1249,7 @@ fn default_configuration(sess: &Session) -> Cfg { // NOTE: This should be kept in sync with `CheckCfg::fill_well_known` below. let end = &sess.target.endian; let arch = &sess.target.arch; - let wordsz = sess.target.pointer_width.to_string(); + let wordsz = sess.target.pointer_width as u64; let os = &sess.target.os; let env = &sess.target.env; let abi = &sess.target.abi; @@ -1277,7 +1276,7 @@ fn default_configuration(sess: &Session) -> Cfg { } ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str())))); - ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); + ret.insert((sym::target_pointer_width, Some(sym::integer(wordsz)))); ret.insert((sym::target_env, Some(Symbol::intern(env)))); ret.insert((sym::target_abi, Some(Symbol::intern(abi)))); if sess.is_nightly_build() { @@ -1297,19 +1296,18 @@ fn default_configuration(sess: &Session) -> Cfg { ] { if i >= min_atomic_width && i <= max_atomic_width { has_atomic = true; - let mut insert_atomic = |s, align: Align| { - ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); + let mut insert_atomic = |sym, align: Align| { + ret.insert((sym::target_has_atomic_load_store, Some(sym))); if atomic_cas { - ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); + ret.insert((sym::target_has_atomic, Some(sym))); } if align.bits() == i { - ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); + ret.insert((sym::target_has_atomic_equal_alignment, Some(sym))); } }; - let s = i.to_string(); - insert_atomic(&s, align); - if s == wordsz { - insert_atomic("ptr", layout.pointer_align.abi); + insert_atomic(sym::integer(i), align); + if wordsz == i { + insert_atomic(sym::ptr, layout.pointer_align.abi); } } } @@ -2150,25 +2148,27 @@ fn collect_print_requests( } const PRINT_KINDS: &[(&str, PrintKind)] = &[ + // tidy-alphabetical-start + ("all-target-specs-json", PrintKind::AllTargetSpecs), + ("calling-conventions", PrintKind::CallingConventions), + ("cfg", PrintKind::Cfg), + ("code-models", PrintKind::CodeModels), ("crate-name", PrintKind::CrateName), + ("deployment-target", PrintKind::DeploymentTarget), ("file-names", PrintKind::FileNames), + ("link-args", PrintKind::LinkArgs), + ("native-static-libs", PrintKind::NativeStaticLibs), + ("relocation-models", PrintKind::RelocationModels), + ("split-debuginfo", PrintKind::SplitDebuginfo), + ("stack-protector-strategies", PrintKind::StackProtectorStrategies), ("sysroot", PrintKind::Sysroot), - ("target-libdir", PrintKind::TargetLibdir), - ("cfg", PrintKind::Cfg), - ("calling-conventions", PrintKind::CallingConventions), - ("target-list", PrintKind::TargetList), ("target-cpus", PrintKind::TargetCPUs), ("target-features", PrintKind::TargetFeatures), - ("relocation-models", PrintKind::RelocationModels), - ("code-models", PrintKind::CodeModels), - ("tls-models", PrintKind::TlsModels), - ("native-static-libs", PrintKind::NativeStaticLibs), - ("stack-protector-strategies", PrintKind::StackProtectorStrategies), + ("target-libdir", PrintKind::TargetLibdir), + ("target-list", PrintKind::TargetList), ("target-spec-json", PrintKind::TargetSpec), - ("all-target-specs-json", PrintKind::AllTargetSpecs), - ("link-args", PrintKind::LinkArgs), - ("split-debuginfo", PrintKind::SplitDebuginfo), - ("deployment-target", PrintKind::DeploymentTarget), + ("tls-models", PrintKind::TlsModels), + // tidy-alphabetical-end ]; // We disallow reusing the same path in multiple prints, such as `--print @@ -2297,14 +2297,7 @@ 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( +fn parse_assert_incr_state( handler: &EarlyErrorHandler, opt_assertion: &Option<String>, ) -> Option<IncrementalStateAssertion> { @@ -2460,6 +2453,17 @@ pub fn parse_externs( matches: &getopts::Matches, unstable_opts: &UnstableOptions, ) -> Externs { + fn is_ascii_ident(string: &str) -> bool { + let mut chars = string.chars(); + if let Some(start) = chars.next() + && (start.is_ascii_alphabetic() || start == '_') + { + chars.all(|char| char.is_ascii_alphanumeric() || char == '_') + } else { + false + } + } + let is_unstable_enabled = unstable_opts.unstable_options; let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new(); for arg in matches.opt_strs("extern") { @@ -2472,12 +2476,12 @@ pub fn parse_externs( Some((opts, name)) => (Some(opts), name.to_string()), }; - if !crate::utils::is_ascii_ident(&name) { + if !is_ascii_ident(&name) { let mut error = handler.early_struct_error(format!( "crate name `{name}` passed to `--extern` is not a valid ASCII identifier" )); let adjusted_name = name.replace('-', "_"); - if crate::utils::is_ascii_ident(&adjusted_name) { + if is_ascii_ident(&adjusted_name) { error.help(format!( "consider replacing the dashes with underscores: `{adjusted_name}`" )); @@ -2791,8 +2795,7 @@ 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 debuginfo_compression = unstable_opts.debuginfo_compression; let mut search_paths = vec![]; for s in &matches.opt_strs("L") { @@ -3143,6 +3146,12 @@ impl PpMode { } } +#[derive(Clone, Hash, PartialEq, Eq, Debug)] +pub enum WasiExecModel { + Command, + Reactor, +} + /// Command-line arguments passed to the compiler have to be incorporated with /// the dependency tracking system for incremental compilation. This module /// provides some utilities to make this more convenient. @@ -3164,13 +3173,13 @@ impl PpMode { pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, - ErrorOutputType, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, - LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, + ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, + LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, + OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, + WasiExecModel, }; use crate::lint; - use crate::options::WasiExecModel; use crate::utils::NativeLib; use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::LanguageIdentifier; @@ -3273,6 +3282,7 @@ pub(crate) mod dep_tracking { TraitSolver, Polonius, InliningThreshold, + FunctionReturn, ); impl<T1, T2> DepTrackingHash for (T1, T2) @@ -3451,3 +3461,14 @@ impl Default for InliningThreshold { Self::Sometimes(100) } } + +/// The different settings that the `-Zfunction-return` flag can have. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub enum FunctionReturn { + /// Keep the function return unmodified. + #[default] + Keep, + + /// Replace returns with jumps to thunk, without emitting the thunk. + ThunkExtern, +} diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index d816842b02b..a0f5eb59b6a 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,7 +6,6 @@ use crate::search_paths::PathKind; 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, FreezeLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; @@ -14,10 +13,9 @@ use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::abi::Abi; -use rustc_target::spec::Target; use std::any::Any; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; // lonely orphan structs and enums looking for a better home @@ -197,21 +195,6 @@ pub enum ExternCrateSource { Path, } -/// The backend's way to give the crate store access to the metadata in a library. -/// Note that it returns the raw metadata bytes stored in the library file, whether -/// it is compressed, uncompressed, some weird mix, etc. -/// rmeta files are backend independent and not handled here. -/// -/// At the time of this writing, there is only one backend and one way to store -/// metadata in library -- this trait just serves to decouple rustc_metadata from -/// the archive reader, which depends on LLVM. -pub trait MetadataLoader: std::fmt::Debug { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; -} - -pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; - /// A store of Rust crates, through which their metadata can be accessed. /// /// Note that this trait should probably not be expanding today. All new diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 31094e0d266..70ee46ea902 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -436,3 +436,11 @@ pub struct IncompatibleLinkerFlavor { pub flavor: &'static str, pub compatible_list: String, } + +#[derive(Diagnostic)] +#[diag(session_function_return_requires_x86_or_x86_64)] +pub(crate) struct FunctionReturnRequiresX86OrX8664; + +#[derive(Diagnostic)] +#[diag(session_function_return_thunk_extern_requires_non_large_code_model)] +pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 3988416d0c7..6e459ac45d3 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -9,12 +9,6 @@ use std::path::{Path, PathBuf}; use crate::search_paths::{PathKind, SearchPath}; use rustc_fs_util::fix_windows_verbatim_for_gcc; -#[derive(Copy, Clone)] -pub enum FileMatch { - FileMatches, - FileDoesntMatch, -} - #[derive(Clone)] pub struct FileSearch<'a> { sysroot: &'a Path, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index ffc2a250681..0b55af2f73b 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,4 @@ -#![feature(if_let_guard)] #![feature(let_chains)] -#![feature(min_specialization)] #![feature(never_type)] #![feature(lazy_cell)] #![feature(option_get_or_insert_default)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4e669c81bf3..7a6108bfbe2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -430,6 +430,7 @@ mod desc { pub const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; + pub const parse_function_return: &str = "`keep` or `thunk-extern`"; } mod parse { @@ -1359,6 +1360,15 @@ mod parse { slot.push((key.to_string(), value, behavior)); true } + + pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool { + match v { + Some("keep") => *slot = FunctionReturn::Keep, + Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern, + _ => return false, + } + true + } } options! { @@ -1603,6 +1613,8 @@ options! { "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], + "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"), function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), future_incompat_test: bool = (false, parse_bool, [UNTRACKED], @@ -1801,7 +1813,7 @@ options! { "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), report_delayed_bugs: bool = (false, parse_bool, [TRACKED], - "immediately print bugs registered with `delay_span_bug` (default: no)"), + "immediately print bugs registered with `span_delayed_bug` (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED], @@ -1973,9 +1985,3 @@ written to standard error output)"), // - compiler/rustc_interface/src/tests.rs // - src/doc/unstable-book/src/compiler-flags } - -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub enum WasiExecModel { - Command, - Reactor, -} diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 9cd96895a61..2ff32b5bb9a 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,4 +1,4 @@ -//! Related to out filenames of compilation (e.g. save analysis, binaries). +//! Related to out filenames of compilation (e.g. binaries). use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use crate::errors::{ CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 4d20d6d4187..f7b33cb598b 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -214,7 +214,7 @@ pub struct ParseSess { pub assume_incomplete_release: bool, /// Spans passed to `proc_macro::quote_span`. Each span has a numerical /// identifier represented by its position in the vector. - pub proc_macro_quoted_spans: AppendOnlyVec<Span>, + proc_macro_quoted_spans: AppendOnlyVec<Span>, /// Used to generate new `AttrId`s. Every `AttrId` is unique. pub attr_id_generator: AttrIdGenerator, } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 20a67d6d036..c6f435a8f92 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,7 +1,7 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, + self, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath, }; use crate::config::{ErrorOutputType, Input}; @@ -10,8 +10,6 @@ use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; -pub use rustc_ast::attr::MarkedAttrs; -pub use rustc_ast::Attribute; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::jobserver::{self, Client}; @@ -48,7 +46,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::{atomic::AtomicBool, Arc}; -pub struct OptimizationFuel { +struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. remaining: u64, /// We're rejecting all further optimizations. @@ -304,7 +302,7 @@ impl Session { if diags.is_empty() { return; } - self.parse_sess.span_diagnostic.emit_future_breakage_report(diags); + self.diagnostic().emit_future_breakage_report(diags); } /// Returns true if the crate is a testing one. @@ -480,7 +478,7 @@ impl Session { sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, - ) { + ) -> ErrorGuaranteed { self.diagnostic().span_err_with_code(sp, msg, code) } #[rustc_lint_diagnostics] @@ -553,8 +551,8 @@ impl Session { pub fn has_errors(&self) -> Option<ErrorGuaranteed> { self.diagnostic().has_errors() } - pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> { - self.diagnostic().has_errors_or_delayed_span_bugs() + pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> { + self.diagnostic().has_errors_or_span_delayed_bugs() } pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> { self.diagnostic().is_compilation_going_to_fail() @@ -580,7 +578,7 @@ impl Session { if self.err_count() == old_count { Ok(result) } else { - Err(self.delay_span_bug( + Err(self.span_delayed_bug( rustc_span::DUMMY_SP, "`self.err_count()` changed but an error was not emitted", )) @@ -621,24 +619,28 @@ impl Session { /// /// This can be used in code paths that should never run on successful compilations. /// For example, it can be used to create an [`ErrorGuaranteed`] - /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission directly). + /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission + /// directly). /// /// If no span is available, use [`DUMMY_SP`]. /// /// [`DUMMY_SP`]: rustc_span::DUMMY_SP + /// + /// Note: this function used to be called `delay_span_bug`. It was renamed + /// to match similar functions like `span_err`, `span_warn`, etc. #[track_caller] - pub fn delay_span_bug<S: Into<MultiSpan>>( + pub fn span_delayed_bug<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<String>, ) -> ErrorGuaranteed { - self.diagnostic().delay_span_bug(sp, msg) + self.diagnostic().span_delayed_bug(sp, msg) } /// Used for code paths of expensive computations that should only take place when /// warnings or errors are emitted. If no messages are emitted ("good path"), then /// it's likely a bug. - pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) { + pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) { if self.opts.unstable_opts.print_type_sizes || self.opts.unstable_opts.query_dep_graph || self.opts.unstable_opts.dump_mir.is_some() @@ -649,40 +651,33 @@ impl Session { return; } - self.diagnostic().delay_good_path_bug(msg) + self.diagnostic().good_path_delayed_bug(msg) } #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) { - self.diagnostic().note_without_error(msg) + pub fn note(&self, msg: impl Into<DiagnosticMessage>) { + self.diagnostic().note(msg) } #[track_caller] #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn span_note_without_error<S: Into<MultiSpan>>( - &self, - sp: S, - msg: impl Into<DiagnosticMessage>, - ) { - self.diagnostic().span_note_without_error(sp, msg) + pub fn span_note<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { + self.diagnostic().span_note(sp, msg) } #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn struct_note_without_error( - &self, - msg: impl Into<DiagnosticMessage>, - ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_note_without_error(msg) + pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_note(msg) } #[inline] - pub fn diagnostic(&self) -> &rustc_errors::Handler { + pub fn diagnostic(&self) -> &Handler { &self.parse_sess.span_diagnostic } @@ -816,12 +811,7 @@ impl Session { if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } } - pub fn init_incr_comp_session( - &self, - session_dir: PathBuf, - lock_file: flock::Lock, - load_dep_graph: bool, - ) { + pub fn init_incr_comp_session(&self, session_dir: PathBuf, lock_file: flock::Lock) { let mut incr_comp_session = self.incr_comp_session.borrow_mut(); if let IncrCompSession::NotInitialized = *incr_comp_session { @@ -830,7 +820,7 @@ impl Session { } *incr_comp_session = - IncrCompSession::Active { session_directory: session_dir, lock_file, load_dep_graph }; + IncrCompSession::Active { session_directory: session_dir, _lock_file: lock_file }; } pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) { @@ -893,7 +883,7 @@ impl Session { if fuel.remaining == 0 && !fuel.out_of_fuel { if self.diagnostic().can_emit_warnings() { // We only call `msg` in case we can actually emit warnings. - // Otherwise, this could cause a `delay_good_path_bug` to + // Otherwise, this could cause a `good_path_delayed_bug` to // trigger (issue #79546). self.emit_warning(errors::OptimisationFuelExhausted { msg: msg() }); } @@ -1417,7 +1407,7 @@ pub fn build_session( ); let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle); - let mut span_diagnostic = rustc_errors::Handler::with_emitter(emitter) + let mut span_diagnostic = Handler::with_emitter(emitter) .with_flags(sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings)); if let Some(ice_file) = ice_file { span_diagnostic = span_diagnostic.with_ice_file(ice_file); @@ -1678,17 +1668,41 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list }); } } + + if sess.opts.unstable_opts.function_return != FunctionReturn::default() { + if sess.target.arch != "x86" && sess.target.arch != "x86_64" { + sess.emit_err(errors::FunctionReturnRequiresX86OrX8664); + } + } + + // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is + // kept as a `match` to force a change if new ones are added, even if we currently only support + // `thunk-extern` like Clang. + match sess.opts.unstable_opts.function_return { + FunctionReturn::Keep => (), + FunctionReturn::ThunkExtern => { + // FIXME: In principle, the inherited base LLVM target code model could be large, + // but this only checks whether we were passed one explicitly (like Clang does). + if let Some(code_model) = sess.code_model() + && code_model == CodeModel::Large + { + sess.emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel); + } + } + } } /// Holds data on the current incremental compilation session, if there is one. #[derive(Debug)] -pub enum IncrCompSession { +enum IncrCompSession { /// This is the state the session will be in until the incr. comp. dir is /// needed. NotInitialized, /// This is the state during which the session directory is private and can - /// be modified. - Active { session_directory: PathBuf, lock_file: flock::Lock, load_dep_graph: bool }, + /// be modified. `_lock_file` is never directly used, but its presence + /// alone has an effect, because the file will unlock when the session is + /// dropped. + Active { session_directory: PathBuf, _lock_file: flock::Lock }, /// This is the state after the session directory has been finalized. In this /// state, the contents of the directory must not be modified any more. Finalized { session_directory: PathBuf }, @@ -1706,7 +1720,7 @@ pub struct EarlyErrorHandler { impl EarlyErrorHandler { pub fn new(output: ErrorOutputType) -> Self { let emitter = mk_emitter(output); - Self { handler: rustc_errors::Handler::with_emitter(emitter) } + Self { handler: Handler::with_emitter(emitter) } } pub fn abort_if_errors(&self) { @@ -1726,7 +1740,7 @@ impl EarlyErrorHandler { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) { - self.handler.struct_note_without_error(msg).emit() + self.handler.struct_note(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] @@ -1750,7 +1764,7 @@ impl EarlyErrorHandler { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub(crate) fn early_struct_error( + pub fn early_struct_error( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, !> { diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 3ed044ad769..f76c69af526 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -158,14 +158,3 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> { if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None } } - -pub(crate) fn is_ascii_ident(string: &str) -> bool { - let mut chars = string.chars(); - if let Some(start) = chars.next() - && (start.is_ascii_alphabetic() || start == '_') - { - chars.all(|char| char.is_ascii_alphanumeric() || char == '_') - } else { - false - } -} diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 3449176f729..0bd640ee1e3 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -3,6 +3,7 @@ //! This trait is currently the main interface between the Rust compiler, //! and the `stable_mir` crate. +use rustc_middle::ty; use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{GenericPredicates, Instance, ParamEnv, ScalarInt, ValTree}; use rustc_span::def_id::LOCAL_CRATE; @@ -12,9 +13,9 @@ use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::Body; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, LineInfo, - RigidTy, Span, TyKind, + PolyFnSig, RigidTy, Span, TyKind, }; -use stable_mir::{self, Crate, CrateItem, Error, Filename, ItemKind, Symbol}; +use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; use crate::rustc_internal::{internal, RustcInternal}; @@ -39,6 +40,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.instance_mir(rustc_middle::ty::InstanceDef::Item(def_id)).stable(&mut tables) } + fn has_body(&self, def: DefId) -> bool { + let tables = self.0.borrow(); + let def_id = tables[def]; + tables.tcx.is_mir_available(def_id) + } + fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); tables @@ -195,6 +202,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { def.internal(&mut *tables).is_box() } + fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { + let mut tables = self.0.borrow_mut(); + let def_id = def.0.internal(&mut *tables); + let sig = tables.tcx.fn_sig(def_id).instantiate(tables.tcx, args.internal(&mut *tables)); + sig.stable(&mut *tables) + } + fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> { let mut tables = self.0.borrow_mut(); let mir_const = cnst.internal(&mut *tables); @@ -266,6 +280,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.symbol_name(instance).name.to_string() } + fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { + let tables = self.0.borrow_mut(); + let instance = tables.instances[def]; + matches!(instance.def, ty::InstanceDef::DropGlue(_, None)) + } + fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); let def_id = tables[item.0]; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index e9b835f90db..165b8c50e70 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -579,13 +579,12 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt { discr: discr.stable(tables), targets: { - let (value_vec, mut target_vec): (Vec<_>, Vec<_>) = - targets.iter().map(|(value, target)| (value, target.as_usize())).unzip(); - // We need to push otherwise as last element to ensure it's same as in MIR. - target_vec.push(targets.otherwise().as_usize()); - stable_mir::mir::SwitchTargets { value: value_vec, targets: target_vec } + let branches = targets.iter().map(|(val, target)| (val, target.as_usize())); + stable_mir::mir::SwitchTargets::new( + branches.collect(), + targets.otherwise().as_usize(), + ) }, - otherwise: targets.otherwise().as_usize(), }, mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 32ee928ddd4..f837f28e11e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -777,7 +777,9 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { let kind = match self.def { ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item, ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, - ty::InstanceDef::Virtual(..) => stable_mir::mir::mono::InstanceKind::Virtual, + ty::InstanceDef::Virtual(_def_id, idx) => { + stable_mir::mir::mono::InstanceKind::Virtual { idx } + } ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrAddrShim(..) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 76be546e945..cc3f0962d6c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2247,7 +2247,7 @@ pub struct ErrorGuaranteed(()); impl ErrorGuaranteed { /// To be used only if you really know what you are doing... ideally, we would find a way to /// eliminate all calls to this method. - #[deprecated = "`Session::delay_span_bug` should be preferred over this function"] + #[deprecated = "`Session::span_delayed_bug` should be preferred over this function"] pub fn unchecked_claim_error_was_emitted() -> Self { ErrorGuaranteed(()) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f1a1f23e6dd..d7e822382ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -641,7 +641,6 @@ symbols! { default_method_body_is_const, default_type_parameter_fallback, default_type_params, - delay_span_bug_from_inside_query, deny, deprecated, deprecated_safe, @@ -1557,6 +1556,7 @@ symbols! { slice_patterns, slicing_syntax, soft, + span_delayed_bug_from_inside_query, specialization, speed, spotlight, diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs index 37bbf32c768..03823569669 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs @@ -196,7 +196,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }; let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| { - let guar = tcx.sess.delay_span_bug(tcx.def_span(assoc_def.item.def_id), reason); + let guar = tcx.sess.span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); let error_term = match assoc_def.item.kind { ty::AssocKind::Const => ty::Const::new_error( tcx, @@ -286,7 +286,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.tcx().sess.delay_span_bug( + ecx.tcx().sess.span_delayed_bug( ecx.tcx().def_span(goal.predicate.def_id()), "associated types not allowed on auto traits", ); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 62ab1e1049b..aee51320792 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -65,7 +65,7 @@ pub fn is_const_evaluatable<'tcx>( // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it // is evaluatable or not. For now we just ICE until this is implemented. - Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug( + Err(NotConstEvaluatable::Error(tcx.sess.span_delayed_bug( span, "evaluating `ConstKind::Expr` is not currently supported", ))) @@ -74,7 +74,7 @@ pub fn is_const_evaluatable<'tcx>( let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { Err(ErrorHandled::TooGeneric(_)) => { - Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( + Err(NotConstEvaluatable::Error(infcx.tcx.sess.span_delayed_bug( span, "Missing value for constant, but no error reported?", ))) @@ -138,10 +138,10 @@ pub fn is_const_evaluatable<'tcx>( } else if uv.has_non_region_param() { NotConstEvaluatable::MentionsParam } else { - let guar = infcx - .tcx - .sess - .delay_span_bug(span, "Missing value for constant, but no error reported?"); + let guar = infcx.tcx.sess.span_delayed_bug( + span, + "Missing value for constant, but no error reported?", + ); NotConstEvaluatable::Error(guar) }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index feeeaa51f81..ba019c4ff6f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -677,8 +677,9 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } else { - let reported = - tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); + let reported = tcx + .sess + .span_delayed_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); return Err(reported); }; debug!("of_item({:?}) = {:?}", item_def_id, result); 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 e4cb99727fc..d5e1efb9663 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -17,7 +17,7 @@ use rustc_errors::{ ErrorGuaranteed, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; @@ -36,7 +36,7 @@ use rustc_middle::ty::{ TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::borrow::Cow; @@ -222,6 +222,15 @@ pub trait TypeErrCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn note_conflicting_fn_args( + &self, + err: &mut Diagnostic, + cause: &ObligationCauseCode<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ); + fn note_conflicting_closure_bounds( &self, cause: &ObligationCauseCode<'tcx>, @@ -1034,7 +1043,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; - let hir::def::Res::Local(hir_id) = path.res else { + let Res::Local(hir_id) = path.res else { return; }; let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { @@ -1618,7 +1627,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::def::Res::Local(hir_id) = path.res + && let Res::Local(hir_id) = path.res && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) && let None = local.ty @@ -2005,6 +2014,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let signature_kind = format!("{argument_kind} signature"); err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str); + self.note_conflicting_fn_args(&mut err, cause, expected, found, param_env); self.note_conflicting_closure_bounds(cause, &mut err); if let Some(found_node) = found_node { @@ -2014,6 +2024,151 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err } + fn note_conflicting_fn_args( + &self, + err: &mut Diagnostic, + cause: &ObligationCauseCode<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) { + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = cause else { + return; + }; + let ty::FnPtr(expected) = expected.kind() else { + return; + }; + let ty::FnPtr(found) = found.kind() else { + return; + }; + let Some(Node::Expr(arg)) = self.tcx.hir().find(*arg_hir_id) else { + return; + }; + let hir::ExprKind::Path(path) = arg.kind else { + return; + }; + let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(*expected).inputs(); + let found_inputs = self.tcx.instantiate_bound_regions_with_erased(*found).inputs(); + let both_tys = expected_inputs.iter().copied().zip(found_inputs.iter().copied()); + + let arg_expr = |infcx: &InferCtxt<'tcx>, name, expected: Ty<'tcx>, found: Ty<'tcx>| { + let (expected_ty, expected_refs) = get_deref_type_and_refs(expected); + let (found_ty, found_refs) = get_deref_type_and_refs(found); + + if infcx.can_eq(param_env, found_ty, expected_ty) { + if found_refs.len() == expected_refs.len() + && found_refs.iter().eq(expected_refs.iter()) + { + name + } else if found_refs.len() > expected_refs.len() { + let refs = &found_refs[..found_refs.len() - expected_refs.len()]; + if found_refs[..expected_refs.len()].iter().eq(expected_refs.iter()) { + format!( + "{}{name}", + refs.iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::<Vec<_>>() + .join(""), + ) + } else { + // The refs have different mutability. + format!( + "{}*{name}", + refs.iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::<Vec<_>>() + .join(""), + ) + } + } else if expected_refs.len() > found_refs.len() { + format!( + "{}{name}", + (0..(expected_refs.len() - found_refs.len())) + .map(|_| "*") + .collect::<Vec<_>>() + .join(""), + ) + } else { + format!( + "{}{name}", + found_refs + .iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .chain(found_refs.iter().map(|_| "*".to_string())) + .collect::<Vec<_>>() + .join(""), + ) + } + } else { + format!("/* {found} */") + } + }; + let args_have_same_underlying_type = both_tys.clone().all(|(expected, found)| { + let (expected_ty, _) = get_deref_type_and_refs(expected); + let (found_ty, _) = get_deref_type_and_refs(found); + self.can_eq(param_env, found_ty, expected_ty) + }); + let (closure_names, call_names): (Vec<_>, Vec<_>) = if args_have_same_underlying_type + && !expected_inputs.is_empty() + && expected_inputs.len() == found_inputs.len() + && let Some(typeck) = &self.typeck_results + && let Res::Def(_, fn_def_id) = typeck.qpath_res(&path, *arg_hir_id) + { + let closure: Vec<_> = self + .tcx + .fn_arg_names(fn_def_id) + .iter() + .enumerate() + .map(|(i, ident)| { + if ident.name.is_empty() || ident.name == kw::SelfLower { + format!("arg{i}") + } else { + format!("{ident}") + } + }) + .collect(); + let args = closure + .iter() + .zip(both_tys) + .map(|(name, (expected, found))| { + arg_expr(self.infcx, name.to_owned(), expected, found) + }) + .collect(); + (closure, args) + } else { + let closure_args = expected_inputs + .iter() + .enumerate() + .map(|(i, _)| format!("arg{i}")) + .collect::<Vec<_>>(); + let call_args = both_tys + .enumerate() + .map(|(i, (expected, found))| { + arg_expr(self.infcx, format!("arg{i}"), expected, found) + }) + .collect::<Vec<_>>(); + (closure_args, call_args) + }; + let closure_names: Vec<_> = closure_names + .into_iter() + .zip(expected_inputs.iter()) + .map(|(name, ty)| { + format!( + "{name}{}", + if ty.has_infer_types() { String::new() } else { format!(": {ty}") } + ) + }) + .collect(); + err.multipart_suggestion( + format!("consider wrapping the function in a closure"), + vec![ + (arg.span.shrink_to_lo(), format!("|{}| ", closure_names.join(", "))), + (arg.span.shrink_to_hi(), format!("({})", call_names.join(", "))), + ], + Applicability::MaybeIncorrect, + ); + } + // Add a note if there are two `Fn`-family bounds that have conflicting argument // requirements, which will always cause a closure to have a type error. fn note_conflicting_closure_bounds( @@ -3634,7 +3789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let hir::Path { res: Res::Local(hir_id), .. } = path && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id) && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) @@ -3894,7 +4049,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let hir::Path { res: Res::Local(hir_id), .. } = path && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) { @@ -4349,17 +4504,6 @@ fn hint_missing_borrow<'tcx>( let args = fn_decl.inputs.iter(); - fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { - let mut refs = vec![]; - - while let ty::Ref(_, new_ty, mutbl) = ty.kind() { - ty = *new_ty; - refs.push(*mutbl); - } - - (ty, refs) - } - let mut to_borrow = Vec::new(); let mut remove_borrow = Vec::new(); @@ -4519,7 +4663,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { if let hir::TyKind::Path(hir::QPath::Resolved( None, - hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, + hir::Path { res: Res::Def(_, segment_did), .. }, )) = t.kind { if self.param_did == *segment_did { @@ -4652,3 +4796,14 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( Some(sugg) } + +fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { + let mut refs = vec![]; + + while let ty::Ref(_, new_ty, mutbl) = ty.kind() { + ty = *new_ty; + refs.push(*mutbl); + } + + (ty, refs) +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index b28bff1ca2a..b3910a2770b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -218,7 +218,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors") + self.tcx.sess.span_delayed_bug(DUMMY_SP, "expected fulfillment errors") } /// Reports that an overflow has occurred and halts compilation. We @@ -369,7 +369,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut span = obligation.cause.span; // FIXME: statically guarantee this by tainting after the diagnostic is emitted self.set_tainted_by_errors( - tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"), + tcx.sess.span_delayed_bug(span, "`report_selection_error` did not emit an error"), ); let mut err = match *error { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 08544b4a93a..fd39fce9dd1 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,5 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::traits::error_reporting::TypeErrCtxtExt; use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; @@ -410,6 +411,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } + ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") + } + + // General case overflow check. Allow `process_trait_obligation` + // and `process_projection_obligation` to handle checking for + // the recursion limit themselves. Also don't check some + // predicate kinds that don't give further obligations. + _ if !self + .selcx + .tcx() + .recursion_limit() + .value_within_limit(obligation.recursion_depth) => + { + self.selcx.infcx.err_ctxt().report_overflow_error( + &obligation.predicate, + obligation.cause.span, + false, + |_| {}, + ); + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { match wf::obligations( self.selcx.infcx, @@ -440,7 +464,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)]; ProcessResult::Unchanged } - Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Ok(Ok(mut ok)) => { + for subobligation in &mut ok.obligations { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } + ProcessResult::Changed(mk_pending(ok.obligations)) + } Ok(Err(err)) => { let expected_found = ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b); @@ -611,10 +640,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } - ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, - ty::PredicateKind::AliasRelate(..) => { - bug!("AliasRelate is only used for new solver") - } ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index ab07b10c65f..2f2411310a9 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -173,7 +173,7 @@ pub fn all_fields_implement_trait<'tcx>( // between expected and found const-generic types. Don't report an // additional copy error here, since it's not typically useful. if !normalization_errors.is_empty() || ty.references_error() { - tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id))); + tcx.sess.span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id))); continue; } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2c004c65929..64d2b5fc159 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -215,7 +215,7 @@ fn do_normalize_predicates<'tcx>( // the normalized predicates. let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( span, format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), ); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 8268273884d..fbde7455145 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -509,7 +509,7 @@ fn virtual_call_violations_for_method<'tcx>( Ok(layout) => Some(layout.abi), Err(err) => { // #78372 - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(method.def_id), format!("error: {err}\n while computing layout for type {ty:?}"), ); @@ -525,7 +525,7 @@ fn virtual_call_violations_for_method<'tcx>( match abi_of_ty(unit_receiver_ty) { Some(Abi::Scalar(..)) => (), abi => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(method.def_id), format!( "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}" @@ -543,7 +543,7 @@ fn virtual_call_violations_for_method<'tcx>( match abi_of_ty(trait_object_receiver) { Some(Abi::ScalarPair(..)) => (), abi => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(method.def_id), format!( "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}" @@ -597,7 +597,7 @@ fn virtual_call_violations_for_method<'tcx>( if pred_trait_ref.args.len() != 1 { tcx.sess .diagnostic() - .delay_span_bug(span, "auto traits cannot have generic parameters"); + .span_delayed_bug(span, "auto traits cannot have generic parameters"); } return false; } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 1c2966bb3e5..7513f88cfc3 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { let errors = ocx.select_all_or_error(); if !errors.is_empty() { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( span, "implied_outlives_bounds failed to solve obligations from instantiation", ); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 3be14951703..45bdff09dee 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1469,7 +1469,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) { Ok(mut ok) => obligations.append(&mut ok.obligations), Err(_) => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( cause.span, format!( "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not" @@ -1974,7 +1974,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // These traits have no associated types. - selcx.tcx().sess.delay_span_bug( + selcx.tcx().sess.span_delayed_bug( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 06d41243e75..ec80df1d658 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -237,7 +237,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // By the time this code runs, all type variables ought to // be fully resolved. - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( span, format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), ); @@ -286,7 +286,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( if !args.is_valid() { // By the time this code runs, all type variables ought to // be fully resolved. - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( span, format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",), ); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 8faaa6be9f5..4728fcf3301 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -292,7 +292,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> // Rustdoc normalizes possibly not well-formed types, so only // treat this as a bug if we're not in rustdoc. if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, format!("unexpected ambiguity: {c_data:?} {result:?}"), ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index c81bc579003..18bb56ba4eb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -82,13 +82,13 @@ where let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); let value = op(&ocx).map_err(|_| { - infcx.tcx.sess.delay_span_bug(span, format!("error performing operation: {name}")) + infcx.tcx.sess.span_delayed_bug(span, format!("error performing operation: {name}")) })?; let errors = ocx.select_all_or_error(); if errors.is_empty() { Ok(value) } else { - Err(infcx.tcx.sess.delay_span_bug( + Err(infcx.tcx.sess.span_delayed_bug( DUMMY_SP, format!("errors selecting obligation during MIR typeck: {errors:?}"), )) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index a5ccf62608e..e87e585ef0b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -160,14 +160,14 @@ where let (output, error_info, mut obligations) = Q::fully_perform_into(self, infcx, &mut region_constraints) .map_err(|_| { - infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}")) + infcx.tcx.sess.span_delayed_bug(span, format!("error performing {self:?}")) }) .and_then(|(output, error_info, obligations, certainty)| match certainty { Certainty::Proven => Ok((output, error_info, obligations)), Certainty::Ambiguous => Err(infcx .tcx .sess - .delay_span_bug(span, format!("ambiguity performing {self:?}"))), + .span_delayed_bug(span, format!("ambiguity performing {self:?}"))), })?; // Typically, instantiating NLL query results does not @@ -196,7 +196,7 @@ where } } if !progress { - return Err(infcx.tcx.sess.delay_span_bug( + return Err(infcx.tcx.sess.span_delayed_bug( span, format!("ambiguity processing {obligations:?} from {self:?}"), )); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4763a906172..a33160b7c43 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -553,7 +553,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let defs: &ty::Generics = tcx.generics_of(assoc_type); if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( obligation.cause.span, "GATs in trait object shouldn't have been considered", ); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0c884b7c16a..b26c781100a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2419,7 +2419,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the placeholder trait ref may fail due the Generalizer relation // raising a CyclicalTy error due to a sub_root_var relation // for a variable being generalized... - let guar = self.infcx.tcx.sess.delay_span_bug( + let guar = self.infcx.tcx.sess.span_delayed_bug( obligation.cause.span, format!( "Impl {impl_def_id:?} was matchable against {obligation:?} but now is not" diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 73ba03a3610..56f5057608f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -202,7 +202,7 @@ fn fulfill_implication<'tcx>( { Ok(source_trait_ref) => source_trait_ref, Err(_errors) => { - infcx.tcx.sess.delay_span_bug( + infcx.tcx.sess.span_delayed_bug( infcx.tcx.def_span(source_impl), format!("failed to fully normalize {source_trait_ref}"), ); @@ -431,7 +431,10 @@ fn report_conflicting_impls<'tcx>( decorate(tcx, &overlap, impl_span, &mut err); Some(err.emit()) } else { - Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check")) + Some( + tcx.sess + .span_delayed_bug(impl_span, "impl should have failed the orphan check"), + ) }; sg.has_errored = reported; } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 5960415a88d..f8e47caccb7 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -135,7 +135,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { bug!("unexpected type during structural-match checking: {:?}", ty); } ty::Error(_) => { - self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check"); + self.tcx.sess.span_delayed_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. return ControlFlow::Continue(()); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 31f6a56eaeb..a0f01d9eca9 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -79,7 +79,7 @@ fn resolve_associated_item<'tcx>( let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) { Ok(vtbl) => vtbl, Err(CodegenObligationError::Ambiguity) => { - let reported = tcx.sess.delay_span_bug( + let reported = tcx.sess.span_delayed_bug( tcx.def_span(trait_item_id), format!( "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \ @@ -171,7 +171,7 @@ fn resolve_associated_item<'tcx>( // Any final impl is required to define all associated items. if !leaf_def.item.defaultness(tcx).has_value() { - let guard = tcx.sess.delay_span_bug( + let guard = tcx.sess.span_delayed_bug( tcx.def_span(leaf_def.item.def_id), "missing value for assoc item in impl", ); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 826c69ee716..7599aa9fa41 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -93,7 +93,7 @@ fn univariant_uninterned<'tcx>( let dl = cx.data_layout(); let pack = repr.pack; if pack.is_some() && repr.align.is_some() { - cx.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned"); + cx.tcx.sess.span_delayed_bug(DUMMY_SP, "struct cannot be packed and aligned"); return Err(cx.tcx.arena.alloc(LayoutError::Unknown(ty))); } @@ -346,7 +346,7 @@ fn layout_of_uncached<'tcx>( ty::Adt(def, args) if def.repr().simd() => { if !def.is_struct() { // Should have yielded E0517 by now. - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, "#[repr(simd)] was applied to an ADT that is not a struct", ); @@ -376,7 +376,7 @@ fn layout_of_uncached<'tcx>( // (should be caught by typeck) for fi in fields { if fi.ty(tcx, args) != f0_ty { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, "#[repr(simd)] was applied to an ADT with heterogeneous field type", ); @@ -473,7 +473,7 @@ fn layout_of_uncached<'tcx>( if def.is_union() { if def.repr().pack.is_some() && def.repr().align.is_some() { - cx.tcx.sess.delay_span_bug( + cx.tcx.sess.span_delayed_bug( tcx.def_span(def.did()), "union cannot be packed and aligned", ); diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 16f5ed09d00..db43c31ccab 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -238,7 +238,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { .instantiate(self.tcx, impl_args) .visit_with(self); } else { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( self.tcx.def_span(assoc.def_id), "item had incorrect args", ); diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 827418a6432..daf4465963e 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -10,8 +10,8 @@ use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::Body; use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, - GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, RigidTy, Span, TraitDecl, TraitDef, - Ty, TyKind, + GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, + TraitDef, Ty, TyKind, }; use crate::{ mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol, @@ -24,7 +24,11 @@ pub trait Context { fn entry_fn(&self) -> Option<CrateItem>; /// Retrieve all items of the local crate that have a MIR associated with them. fn all_local_items(&self) -> CrateItems; + /// Retrieve the body of a function. + /// This function will panic if the body is not available. fn mir_body(&self, item: DefId) -> mir::Body; + /// Check whether the body of a function is available. + fn has_body(&self, item: DefId) -> bool; fn all_trait_decls(&self) -> TraitDecls; fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; fn all_trait_impls(&self) -> ImplTraitDecls; @@ -64,6 +68,9 @@ pub trait Context { /// Returns if the ADT is a box. fn adt_is_box(&self, def: AdtDef) -> bool; + /// Retrieve the function signature for the given generic arguments. + fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + /// Evaluate constant as a target usize. fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>; @@ -85,8 +92,7 @@ pub trait Context { /// Obtain the representation of a type. fn ty_kind(&self, ty: Ty) -> TyKind; - /// Get the body of an Instance. - /// FIXME: Monomorphize the body. + /// Get the body of an Instance which is already monomorphized. fn instance_body(&self, instance: InstanceDef) -> Option<Body>; /// Get the instance type with generic substitutions applied and lifetimes erased. @@ -98,6 +104,9 @@ pub trait Context { /// Get the instance mangled name. fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol; + /// Check if this is an empty DropGlue shim. + fn is_empty_drop_shim(&self, def: InstanceDef) -> bool; + /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. fn mono_instance(&self, item: CrateItem) -> Instance; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 02a28687676..3a4f4283562 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -3,7 +3,7 @@ use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, }; use crate::{Error, Opaque, Span, Symbol}; -use std::{io, slice}; +use std::io; /// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { @@ -23,6 +23,8 @@ pub struct Body { pub(super) var_debug_info: Vec<VarDebugInfo>, } +pub type BasicBlockIdx = usize; + impl Body { /// Constructs a `Body`. /// @@ -114,22 +116,21 @@ pub struct Terminator { } impl Terminator { - pub fn successors(&self) -> Successors<'_> { + pub fn successors(&self) -> Successors { self.kind.successors() } } -pub type Successors<'a> = impl Iterator<Item = usize> + 'a; +pub type Successors = Vec<BasicBlockIdx>; #[derive(Clone, Debug, Eq, PartialEq)] pub enum TerminatorKind { Goto { - target: usize, + target: BasicBlockIdx, }, SwitchInt { discr: Operand, targets: SwitchTargets, - otherwise: usize, }, Resume, Abort, @@ -137,43 +138,42 @@ pub enum TerminatorKind { Unreachable, Drop { place: Place, - target: usize, + target: BasicBlockIdx, unwind: UnwindAction, }, Call { func: Operand, args: Vec<Operand>, destination: Place, - target: Option<usize>, + target: Option<BasicBlockIdx>, unwind: UnwindAction, }, Assert { cond: Operand, expected: bool, msg: AssertMessage, - target: usize, + target: BasicBlockIdx, unwind: UnwindAction, }, - CoroutineDrop, InlineAsm { template: String, operands: Vec<InlineAsmOperand>, options: String, line_spans: String, - destination: Option<usize>, + destination: Option<BasicBlockIdx>, unwind: UnwindAction, }, } impl TerminatorKind { - pub fn successors(&self) -> Successors<'_> { + pub fn successors(&self) -> Successors { use self::TerminatorKind::*; match *self { - Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } - | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } - | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } - | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { - Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) + Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => { + vec![t, u] } Goto { target: t } | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } @@ -182,21 +182,18 @@ impl TerminatorKind { | Assert { target: t, unwind: _, .. } | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } | InlineAsm { destination: Some(t), unwind: _, .. } => { - Some(t).into_iter().chain((&[]).into_iter().copied()) + vec![t] } - CoroutineDrop - | Return + Return | Resume | Abort | Unreachable | Call { target: None, unwind: _, .. } | InlineAsm { destination: None, unwind: _, .. } => { - None.into_iter().chain((&[]).into_iter().copied()) - } - SwitchInt { ref targets, .. } => { - None.into_iter().chain(targets.targets.iter().copied()) + vec![] } + SwitchInt { ref targets, .. } => targets.all_targets(), } } @@ -205,7 +202,6 @@ impl TerminatorKind { TerminatorKind::Goto { .. } | TerminatorKind::Return | TerminatorKind::Unreachable - | TerminatorKind::CoroutineDrop | TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::SwitchInt { .. } => None, @@ -231,7 +227,7 @@ pub enum UnwindAction { Continue, Unreachable, Terminate, - Cleanup(usize), + Cleanup(BasicBlockIdx), } #[derive(Clone, Debug, Eq, PartialEq)] @@ -662,10 +658,42 @@ pub struct Constant { pub literal: Const, } +/// The possible branch sites of a [TerminatorKind::SwitchInt]. #[derive(Clone, Debug, Eq, PartialEq)] pub struct SwitchTargets { - pub value: Vec<u128>, - pub targets: Vec<usize>, + /// The conditional branches where the first element represents the value that guards this + /// branch, and the second element is the branch target. + branches: Vec<(u128, BasicBlockIdx)>, + /// The `otherwise` branch which will be taken in case none of the conditional branches are + /// satisfied. + otherwise: BasicBlockIdx, +} + +impl SwitchTargets { + /// All possible targets including the `otherwise` target. + pub fn all_targets(&self) -> Successors { + self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect() + } + + /// The `otherwise` branch target. + pub fn otherwise(&self) -> BasicBlockIdx { + self.otherwise + } + + /// The conditional targets which are only taken if the pattern matches the given value. + pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> + '_ { + self.branches.iter().copied() + } + + /// The number of targets including `otherwise`. + pub fn len(&self) -> usize { + self.branches.len() + 1 + } + + /// Create a new SwitchTargets from the given branches and `otherwise` target. + pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets { + SwitchTargets { branches, otherwise } + } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 9f9af5d6309..10270c82e63 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,6 +1,6 @@ use crate::crate_def::CrateDef; use crate::mir::Body; -use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; +use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, FnSig, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol}; use std::fmt::{Debug, Formatter}; @@ -27,7 +27,8 @@ pub enum InstanceKind { /// A compiler intrinsic function. Intrinsic, /// A virtual function definition stored in a VTable. - Virtual, + /// The `idx` field indicates the position in the VTable for this instance. + Virtual { idx: usize }, /// A compiler generated shim. Shim, } @@ -106,6 +107,24 @@ impl Instance { }) }) } + + /// Get this function signature with all types already instantiated. + pub fn fn_sig(&self) -> FnSig { + self.ty().kind().fn_sig().unwrap().skip_binder() + } + + /// Check whether this instance is an empty shim. + /// + /// Allow users to check if this shim can be ignored when called directly. + /// + /// We have decided not to export different types of Shims to StableMIR users, however, this + /// is a query that can be very helpful for users when processing DropGlue. + /// + /// When generating code for a Drop terminator, users can ignore an empty drop glue. + /// These shims are only needed to generate a valid Drop call done via VTable. + pub fn is_empty_shim(&self) -> bool { + self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def)) + } } impl Debug for Instance { @@ -124,8 +143,6 @@ impl TryFrom<CrateItem> for Instance { fn try_from(item: CrateItem) -> Result<Self, Self::Error> { with(|context| { - // FIXME(celinval): - // - Return `Err` if instance does not have a body. if !context.requires_monomorphization(item.0) { Ok(context.mono_instance(item)) } else { @@ -141,11 +158,13 @@ impl TryFrom<Instance> for CrateItem { type Error = crate::Error; fn try_from(value: Instance) -> Result<Self, Self::Error> { - if value.kind == InstanceKind::Item { - Ok(CrateItem(with(|context| context.instance_def_id(value.def)))) - } else { - Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind))) - } + with(|context| { + if value.kind == InstanceKind::Item && context.has_body(value.def.def_id()) { + Ok(CrateItem(context.instance_def_id(value.def))) + } else { + Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind))) + } + }) } } @@ -170,6 +189,12 @@ impl From<StaticDef> for CrateItem { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct InstanceDef(usize); +impl CrateDef for InstanceDef { + fn def_id(&self) -> DefId { + with(|context| context.instance_def_id(*self)) + } +} + crate_def! { /// Holds information about a static variable definition. pub StaticDef; diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 759c3b148df..3a0eed521dc 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -76,7 +76,8 @@ pub fn pretty_statement(statement: &StatementKind) -> String { pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> { write!(w, "{}", pretty_terminator_head(terminator))?; - let successor_count = terminator.successors().count(); + let successors = terminator.successors(); + let successor_count = successors.len(); let labels = pretty_successor_labels(terminator); let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); @@ -98,12 +99,12 @@ pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) - Ok(()) } (1, false) => { - write!(w, " -> {:?}", terminator.successors().next().unwrap())?; + write!(w, " -> {:?}", successors[0])?; Ok(()) } _ => { write!(w, " -> [")?; - for (i, target) in terminator.successors().enumerate() { + for (i, target) in successors.iter().enumerate() { if i > 0 { write!(w, ", ")?; } @@ -157,7 +158,6 @@ pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String { pretty.push_str(")"); pretty } - CoroutineDrop => format!(" coroutine_drop"), InlineAsm { .. } => todo!(), } } @@ -165,12 +165,11 @@ pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String { pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> { use self::TerminatorKind::*; match terminator { - Resume | Abort | Return | Unreachable | CoroutineDrop => vec![], + Resume | Abort | Return | Unreachable => vec![], Goto { .. } => vec!["".to_string()], SwitchInt { targets, .. } => targets - .value - .iter() - .map(|target| format!("{}", target)) + .branches() + .map(|(val, _target)| format!("{val}")) .chain(iter::once("otherwise".into())) .collect(), Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 69bf6ca72b0..0c44781c463 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -237,8 +237,7 @@ pub trait MirVisitor { TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Abort - | TerminatorKind::Unreachable - | TerminatorKind::CoroutineDrop => {} + | TerminatorKind::Unreachable => {} TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { self.visit_operand(cond, location); self.visit_assert_msg(msg, location); @@ -268,7 +267,7 @@ pub trait MirVisitor { let local = RETURN_LOCAL; self.visit_local(&local, PlaceContext::NON_MUTATING, location); } - TerminatorKind::SwitchInt { discr, targets: _, otherwise: _ } => { + TerminatorKind::SwitchInt { discr, targets: _ } => { self.visit_operand(discr, location); } } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 80558657deb..6c4fb4a7753 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -168,7 +168,11 @@ impl TyKind { } pub fn is_unit(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.len() == 0) + matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.is_empty()) + } + + pub fn is_bool(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Bool)) } pub fn is_trait(&self) -> bool { @@ -187,6 +191,14 @@ impl TyKind { matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union) } + pub fn is_fn(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::FnDef(..))) + } + + pub fn is_fn_ptr(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::FnPtr(..))) + } + pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> { if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self { if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) = @@ -227,6 +239,15 @@ impl TyKind { _ => None, } } + + /// Get the function signature for function like types (Fn, FnPtr, Closure, Coroutine) + pub fn fn_sig(&self) -> Option<PolyFnSig> { + match self { + TyKind::RigidTy(RigidTy::FnDef(def, args)) => Some(with(|cx| cx.fn_sig(*def, args))), + TyKind::RigidTy(RigidTy::FnPtr(sig)) => Some(sig.clone()), + _ => None, + } + } } pub struct TypeAndMut { @@ -307,8 +328,9 @@ crate_def! { } impl FnDef { - pub fn body(&self) -> Body { - with(|ctx| ctx.mir_body(self.0)) + // Get the function body if available. + pub fn body(&self) -> Option<Body> { + with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) } } @@ -488,6 +510,16 @@ pub struct FnSig { pub abi: Abi, } +impl FnSig { + pub fn output(&self) -> Ty { + self.inputs_and_output[self.inputs_and_output.len() - 1] + } + + pub fn inputs(&self) -> &[Ty] { + &self.inputs_and_output[..self.inputs_and_output.len() - 1] + } +} + #[derive(Clone, PartialEq, Eq, Debug)] pub enum Abi { Rust, diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f25ca9e2b18..214c8e49a5a 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -341,6 +341,9 @@ extern "rust-intrinsic" { /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. #[rustc_nounwind] pub fn atomic_load_relaxed<T: Copy>(src: *const T) -> T; + /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! + /// In terms of the Rust Abstract Machine, this operation is equivalent to `src.read()`, + /// i.e., it performs a non-atomic read. #[rustc_nounwind] pub fn atomic_load_unordered<T: Copy>(src: *const T) -> T; @@ -365,6 +368,9 @@ extern "rust-intrinsic" { /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. #[rustc_nounwind] pub fn atomic_store_relaxed<T: Copy>(dst: *mut T, val: T); + /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! + /// In terms of the Rust Abstract Machine, this operation is equivalent to `dst.write(val)`, + /// i.e., it performs a non-atomic write. #[rustc_nounwind] pub fn atomic_store_unordered<T: Copy>(dst: *mut T, val: T); @@ -2312,6 +2318,10 @@ extern "rust-intrinsic" { /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. + /// + /// Do NOT use this intrinsic; "nontemporal" operations do not exist in our memory model! + /// It exists to support current stdarch, but the plan is to change stdarch and remove this intrinsic. + /// See <https://github.com/rust-lang/rust/issues/114582> for some more discussion. #[rustc_nounwind] pub fn nontemporal_store<T>(ptr: *mut T, val: T); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index dec9a6d991d..07720f23598 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -446,9 +446,10 @@ pub mod arch; #[unstable(feature = "portable_simd", issue = "86656")] mod core_simd; -#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")] #[unstable(feature = "portable_simd", issue = "86656")] pub mod simd { + #![doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")] + #[unstable(feature = "portable_simd", issue = "86656")] pub use crate::core_simd::simd::*; } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 65aae8499f3..a7b36fe7d29 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3979,7 +3979,7 @@ impl<T> [T] { /// /// ``` /// #![feature(portable_simd)] - /// use core::simd::SimdFloat; + /// use core::simd::prelude::*; /// /// let short = &[1, 2, 3]; /// let (prefix, middle, suffix) = short.as_simd::<4>(); @@ -3991,7 +3991,6 @@ impl<T> [T] { /// /// fn basic_simd_sum(x: &[f32]) -> f32 { /// use std::ops::Add; - /// use std::simd::f32x4; /// let (prefix, middle, suffix) = x.as_simd(); /// let sums = f32x4::from_array([ /// prefix.iter().copied().sum(), diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 701e61e6615..caa54e00f31 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -1740,9 +1740,9 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> { debug_assert!(needle.len() > 1); use crate::ops::BitAnd; + use crate::simd::cmp::SimdPartialEq; use crate::simd::mask8x16 as Mask; use crate::simd::u8x16 as Block; - use crate::simd::{SimdPartialEq, ToBitMask}; let first_probe = needle[0]; let last_byte_offset = needle.len() - 1; @@ -1765,7 +1765,7 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> { }; // do a naive search if the haystack is too small to fit - if haystack.len() < Block::LANES + last_byte_offset { + if haystack.len() < Block::LEN + last_byte_offset { return Some(haystack.windows(needle.len()).any(|c| c == needle)); } @@ -1812,7 +1812,7 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> { let eq_first: Mask = a.simd_eq(first_probe); let eq_last: Mask = b.simd_eq(second_probe); let both = eq_first.bitand(eq_last); - let mask = both.to_bitmask(); + let mask = both.to_bitmask() as u16; return mask; }; @@ -1822,32 +1822,32 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> { // The loop condition must ensure that there's enough headroom to read LANE bytes, // and not only at the current index but also at the index shifted by block_offset const UNROLL: usize = 4; - while i + last_byte_offset + UNROLL * Block::LANES < haystack.len() && !result { + while i + last_byte_offset + UNROLL * Block::LEN < haystack.len() && !result { let mut masks = [0u16; UNROLL]; for j in 0..UNROLL { - masks[j] = test_chunk(i + j * Block::LANES); + masks[j] = test_chunk(i + j * Block::LEN); } for j in 0..UNROLL { let mask = masks[j]; if mask != 0 { - result |= check_mask(i + j * Block::LANES, mask, result); + result |= check_mask(i + j * Block::LEN, mask, result); } } - i += UNROLL * Block::LANES; + i += UNROLL * Block::LEN; } - while i + last_byte_offset + Block::LANES < haystack.len() && !result { + while i + last_byte_offset + Block::LEN < haystack.len() && !result { let mask = test_chunk(i); if mask != 0 { result |= check_mask(i, mask, result); } - i += Block::LANES; + i += Block::LEN; } // Process the tail that didn't fit into LANES-sized steps. // This simply repeats the same procedure but as right-aligned chunk instead // of a left-aligned one. The last byte must be exactly flush with the string end so // we don't miss a single byte or read out of bounds. - let i = haystack.len() - last_byte_offset - Block::LANES; + let i = haystack.len() - last_byte_offset - Block::LEN; let mask = test_chunk(i); if mask != 0 { result |= check_mask(i, mask, result); diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs index 565c8975eb9..b8b5f26ca3f 100644 --- a/library/core/tests/simd.rs +++ b/library/core/tests/simd.rs @@ -1,5 +1,4 @@ -use core::simd::f32x4; -use core::simd::SimdFloat; +use core::simd::prelude::*; #[test] fn testing() { diff --git a/library/portable-simd/.github/workflows/ci.yml b/library/portable-simd/.github/workflows/ci.yml index 1ff377fce34..90543044ea8 100644 --- a/library/portable-simd/.github/workflows/ci.yml +++ b/library/portable-simd/.github/workflows/ci.yml @@ -167,40 +167,33 @@ jobs: RUSTFLAGS: ${{ matrix.rustflags }} cross-tests: - name: "${{ matrix.target }} (via cross)" + name: "${{ matrix.target_feature }} on ${{ matrix.target }} (via cross)" runs-on: ubuntu-latest strategy: fail-fast: false - # TODO: Sadly, we cant configure target-feature in a meaningful way - # because `cross` doesn't tell qemu to enable any non-default cpu - # features, nor does it give us a way to do so. - # - # Ultimately, we'd like to do something like [rust-lang/stdarch][stdarch]. - # This is a lot more complex... but in practice it's likely that we can just - # snarf the docker config from around [here][1000-dockerfiles]. - # - # [stdarch]: https://github.com/rust-lang/stdarch/blob/a5db4eaf/.github/workflows/main.yml#L67 - # [1000-dockerfiles]: https://github.com/rust-lang/stdarch/tree/a5db4eaf/ci/docker matrix: target: - - i586-unknown-linux-gnu - # 32-bit arm has a few idiosyncracies like having subnormal flushing - # to zero on by default. Ideally we'd set - armv7-unknown-linux-gnueabihf - - aarch64-unknown-linux-gnu - # Note: The issue above means neither of these mips targets will use - # MSA (mips simd) but MIPS uses a nonstandard binary representation - # for NaNs which makes it worth testing on despite that. + - thumbv7neon-unknown-linux-gnueabihf # includes neon by default + - aarch64-unknown-linux-gnu # includes neon by default + - powerpc-unknown-linux-gnu + - powerpc64le-unknown-linux-gnu # includes altivec by default + - riscv64gc-unknown-linux-gnu + # MIPS uses a nonstandard binary representation for NaNs which makes it worth testing + # non-nightly since https://github.com/rust-lang/rust/pull/113274 # - mips-unknown-linux-gnu # - mips64-unknown-linux-gnuabi64 - - riscv64gc-unknown-linux-gnu - # TODO this test works, but it appears to time out - # - powerpc-unknown-linux-gnu - # TODO this test is broken, but it appears to be a problem with QEMU, not us. - # - powerpc64le-unknown-linux-gnu - # TODO enable this once a new version of cross is released + # Lots of errors in QEMU and no real hardware to test on. Not clear if it's QEMU or bad codegen. # - powerpc64-unknown-linux-gnu + target_feature: [default] + include: + - { target: powerpc64le-unknown-linux-gnu, target_feature: "+vsx" } + # Fails due to QEMU floating point errors, probably handling subnormals incorrectly. + # This target is somewhat redundant, since ppc64le has altivec as well. + # - { target: powerpc-unknown-linux-gnu, target_feature: "+altivec" } + # We should test this, but cross currently can't run it + # - { target: riscv64gc-unknown-linux-gnu, target_feature: "+v,+zvl128b" } steps: - uses: actions/checkout@v2 @@ -217,11 +210,27 @@ jobs: # being part of the tarball means we can't just use the download/latest # URL :( run: | - CROSS_URL=https://github.com/rust-embedded/cross/releases/download/v0.2.1/cross-v0.2.1-x86_64-unknown-linux-gnu.tar.gz + CROSS_URL=https://github.com/cross-rs/cross/releases/download/v0.2.5/cross-x86_64-unknown-linux-gnu.tar.gz mkdir -p "$HOME/.bin" curl -sfSL --retry-delay 10 --retry 5 "${CROSS_URL}" | tar zxf - -C "$HOME/.bin" echo "$HOME/.bin" >> $GITHUB_PATH + - name: Configure Emulated CPUs + run: | + echo "CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_RUNNER=qemu-ppc -cpu e600" >> $GITHUB_ENV + # echo "CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER=qemu-riscv64 -cpu rv64,zba=true,zbb=true,v=true,vlen=256,vext_spec=v1.0" >> $GITHUB_ENV + + - name: Configure RUSTFLAGS + shell: bash + run: | + case "${{ matrix.target_feature }}" in + default) + echo "RUSTFLAGS=" >> $GITHUB_ENV;; + *) + echo "RUSTFLAGS=-Ctarget-feature=${{ matrix.target_feature }}" >> $GITHUB_ENV + ;; + esac + - name: Test (debug) run: cross test --verbose --target=${{ matrix.target }} @@ -229,7 +238,7 @@ jobs: run: cross test --verbose --target=${{ matrix.target }} --release features: - name: "Check cargo features (${{ matrix.simd }} × ${{ matrix.features }})" + name: "Test cargo features (${{ matrix.simd }} × ${{ matrix.features }})" runs-on: ubuntu-latest strategy: fail-fast: false @@ -240,12 +249,8 @@ jobs: features: - "" - "--features std" - - "--features generic_const_exprs" - - "--features std --features generic_const_exprs" - "--features all_lane_counts" - - "--features all_lane_counts --features std" - - "--features all_lane_counts --features generic_const_exprs" - - "--features all_lane_counts --features std --features generic_const_exprs" + - "--all-features" steps: - uses: actions/checkout@v2 @@ -257,9 +262,9 @@ jobs: run: echo "CPU_FEATURE=$(lscpu | grep -o avx512[a-z]* | sed s/avx/+avx/ | tr '\n' ',' )" >> $GITHUB_ENV - name: Check build if: ${{ matrix.simd == '' }} - run: RUSTFLAGS="-Dwarnings" cargo check --all-targets --no-default-features ${{ matrix.features }} + run: RUSTFLAGS="-Dwarnings" cargo test --all-targets --no-default-features ${{ matrix.features }} - name: Check AVX if: ${{ matrix.simd == 'avx512' && contains(env.CPU_FEATURE, 'avx512') }} run: | echo "Found AVX features: $CPU_FEATURE" - RUSTFLAGS="-Dwarnings -Ctarget-feature=$CPU_FEATURE" cargo check --all-targets --no-default-features ${{ matrix.features }} + RUSTFLAGS="-Dwarnings -Ctarget-feature=$CPU_FEATURE" cargo test --all-targets --no-default-features ${{ matrix.features }} diff --git a/library/portable-simd/.gitignore b/library/portable-simd/.gitignore index 96ef6c0b944..ea8c4bf7f35 100644 --- a/library/portable-simd/.gitignore +++ b/library/portable-simd/.gitignore @@ -1,2 +1 @@ /target -Cargo.lock diff --git a/library/portable-simd/Cargo.lock b/library/portable-simd/Cargo.lock new file mode 100644 index 00000000000..46312c09657 --- /dev/null +++ b/library/portable-simd/Cargo.lock @@ -0,0 +1,304 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "core_simd" +version = "0.1.0" +dependencies = [ + "proptest", + "std_float", + "test_helpers", + "wasm-bindgen", + "wasm-bindgen-test", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f" +dependencies = [ + "bitflags", + "byteorder", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xorshift" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +dependencies = [ + "rand_core", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "std_float" +version = "0.1.0" +dependencies = [ + "core_simd", +] + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "test_helpers" +version = "0.1.0" +dependencies = [ + "proptest", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml index d1a3a515a7e..b4a8fd70f4c 100644 --- a/library/portable-simd/crates/core_simd/Cargo.toml +++ b/library/portable-simd/crates/core_simd/Cargo.toml @@ -12,7 +12,6 @@ license = "MIT OR Apache-2.0" default = ["as_crate"] as_crate = [] std = [] -generic_const_exprs = [] all_lane_counts = [] [target.'cfg(target_arch = "wasm32")'.dev-dependencies] diff --git a/library/portable-simd/crates/core_simd/examples/dot_product.rs b/library/portable-simd/crates/core_simd/examples/dot_product.rs index a7973ec7404..f047010a65c 100644 --- a/library/portable-simd/crates/core_simd/examples/dot_product.rs +++ b/library/portable-simd/crates/core_simd/examples/dot_product.rs @@ -6,7 +6,7 @@ #![feature(slice_as_chunks)] // Add these imports to use the stdsimd library #![feature(portable_simd)] -use core_simd::simd::*; +use core_simd::simd::prelude::*; // This is your barebones dot product implementation: // Take 2 vectors, multiply them element wise and *then* diff --git a/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs b/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs index 39f530f68f5..bad86414401 100644 --- a/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs +++ b/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs @@ -2,8 +2,7 @@ // Code ported from the `packed_simd` crate // Run this code with `cargo test --example matrix_inversion` #![feature(array_chunks, portable_simd)] -use core_simd::simd::*; -use Which::*; +use core_simd::simd::prelude::*; // Gotta define our own 4x4 matrix since Rust doesn't ship multidim arrays yet :^) #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] @@ -164,10 +163,10 @@ pub fn simd_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> { let m_2 = f32x4::from_array(m[2]); let m_3 = f32x4::from_array(m[3]); - const SHUFFLE01: [Which; 4] = [First(0), First(1), Second(0), Second(1)]; - const SHUFFLE02: [Which; 4] = [First(0), First(2), Second(0), Second(2)]; - const SHUFFLE13: [Which; 4] = [First(1), First(3), Second(1), Second(3)]; - const SHUFFLE23: [Which; 4] = [First(2), First(3), Second(2), Second(3)]; + const SHUFFLE01: [usize; 4] = [0, 1, 4, 5]; + const SHUFFLE02: [usize; 4] = [0, 2, 4, 6]; + const SHUFFLE13: [usize; 4] = [1, 3, 5, 7]; + const SHUFFLE23: [usize; 4] = [2, 3, 6, 7]; let tmp = simd_swizzle!(m_0, m_1, SHUFFLE01); let row1 = simd_swizzle!(m_2, m_3, SHUFFLE01); @@ -180,58 +179,58 @@ pub fn simd_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> { let row2 = simd_swizzle!(tmp, row3, SHUFFLE02); let row3 = simd_swizzle!(row3, tmp, SHUFFLE13); - let tmp = (row2 * row3).reverse().rotate_lanes_right::<2>(); + let tmp = (row2 * row3).reverse().rotate_elements_right::<2>(); let minor0 = row1 * tmp; let minor1 = row0 * tmp; - let tmp = tmp.rotate_lanes_right::<2>(); + let tmp = tmp.rotate_elements_right::<2>(); let minor0 = (row1 * tmp) - minor0; let minor1 = (row0 * tmp) - minor1; - let minor1 = minor1.rotate_lanes_right::<2>(); + let minor1 = minor1.rotate_elements_right::<2>(); - let tmp = (row1 * row2).reverse().rotate_lanes_right::<2>(); + let tmp = (row1 * row2).reverse().rotate_elements_right::<2>(); let minor0 = (row3 * tmp) + minor0; let minor3 = row0 * tmp; - let tmp = tmp.rotate_lanes_right::<2>(); + let tmp = tmp.rotate_elements_right::<2>(); let minor0 = minor0 - row3 * tmp; let minor3 = row0 * tmp - minor3; - let minor3 = minor3.rotate_lanes_right::<2>(); + let minor3 = minor3.rotate_elements_right::<2>(); - let tmp = (row3 * row1.rotate_lanes_right::<2>()) + let tmp = (row3 * row1.rotate_elements_right::<2>()) .reverse() - .rotate_lanes_right::<2>(); - let row2 = row2.rotate_lanes_right::<2>(); + .rotate_elements_right::<2>(); + let row2 = row2.rotate_elements_right::<2>(); let minor0 = row2 * tmp + minor0; let minor2 = row0 * tmp; - let tmp = tmp.rotate_lanes_right::<2>(); + let tmp = tmp.rotate_elements_right::<2>(); let minor0 = minor0 - row2 * tmp; let minor2 = row0 * tmp - minor2; - let minor2 = minor2.rotate_lanes_right::<2>(); + let minor2 = minor2.rotate_elements_right::<2>(); - let tmp = (row0 * row1).reverse().rotate_lanes_right::<2>(); + let tmp = (row0 * row1).reverse().rotate_elements_right::<2>(); let minor2 = minor2 + row3 * tmp; let minor3 = row2 * tmp - minor3; - let tmp = tmp.rotate_lanes_right::<2>(); + let tmp = tmp.rotate_elements_right::<2>(); let minor2 = row3 * tmp - minor2; let minor3 = minor3 - row2 * tmp; - let tmp = (row0 * row3).reverse().rotate_lanes_right::<2>(); + let tmp = (row0 * row3).reverse().rotate_elements_right::<2>(); let minor1 = minor1 - row2 * tmp; let minor2 = row1 * tmp + minor2; - let tmp = tmp.rotate_lanes_right::<2>(); + let tmp = tmp.rotate_elements_right::<2>(); let minor1 = row2 * tmp + minor1; let minor2 = minor2 - row1 * tmp; - let tmp = (row0 * row2).reverse().rotate_lanes_right::<2>(); + let tmp = (row0 * row2).reverse().rotate_elements_right::<2>(); let minor1 = row3 * tmp + minor1; let minor3 = minor3 - row1 * tmp; - let tmp = tmp.rotate_lanes_right::<2>(); + let tmp = tmp.rotate_elements_right::<2>(); let minor1 = minor1 - row3 * tmp; let minor3 = row1 * tmp + minor3; let det = row0 * minor0; - let det = det.rotate_lanes_right::<2>() + det; - let det = det.reverse().rotate_lanes_right::<2>() + det; + let det = det.rotate_elements_right::<2>() + det; + let det = det.reverse().rotate_elements_right::<2>() + det; if det.reduce_sum() == 0. { return None; diff --git a/library/portable-simd/crates/core_simd/examples/nbody.rs b/library/portable-simd/crates/core_simd/examples/nbody.rs index df38a00967f..65820d1340b 100644 --- a/library/portable-simd/crates/core_simd/examples/nbody.rs +++ b/library/portable-simd/crates/core_simd/examples/nbody.rs @@ -1,11 +1,12 @@ #![feature(portable_simd)] +#![allow(clippy::excessive_precision)] extern crate std_float; /// Benchmarks game nbody code /// Taken from the `packed_simd` crate /// Run this benchmark with `cargo test --example nbody` mod nbody { - use core_simd::simd::*; + use core_simd::simd::prelude::*; #[allow(unused)] // False positive? use std_float::StdFloat; diff --git a/library/portable-simd/crates/core_simd/examples/spectral_norm.rs b/library/portable-simd/crates/core_simd/examples/spectral_norm.rs index d576bd0ccee..bc7934c2522 100644 --- a/library/portable-simd/crates/core_simd/examples/spectral_norm.rs +++ b/library/portable-simd/crates/core_simd/examples/spectral_norm.rs @@ -1,6 +1,6 @@ #![feature(portable_simd)] -use core_simd::simd::*; +use core_simd::simd::prelude::*; fn a(i: usize, j: usize) -> f64 { ((i + j) * (i + j + 1) / 2 + i + 1) as f64 diff --git a/library/portable-simd/crates/core_simd/src/core_simd_docs.md b/library/portable-simd/crates/core_simd/src/core_simd_docs.md index 15e8ed0253e..bf412e035b5 100644 --- a/library/portable-simd/crates/core_simd/src/core_simd_docs.md +++ b/library/portable-simd/crates/core_simd/src/core_simd_docs.md @@ -2,3 +2,38 @@ Portable SIMD module. This module offers a portable abstraction for SIMD operations that is not bound to any particular hardware architecture. + +# What is "portable"? + +This module provides a SIMD implementation that is fast and predictable on any target. + +### Portable SIMD works on every target + +Unlike target-specific SIMD in `std::arch`, portable SIMD compiles for every target. +In this regard, it is just like "regular" Rust. + +### Portable SIMD is consistent between targets + +A program using portable SIMD can expect identical behavior on any target. +In most regards, [`Simd<T, N>`] can be thought of as a parallelized `[T; N]` and operates like a sequence of `T`. + +This has one notable exception: a handful of older architectures (e.g. `armv7` and `powerpc`) flush [subnormal](`f32::is_subnormal`) `f32` values to zero. +On these architectures, subnormal `f32` input values are replaced with zeros, and any operation producing subnormal `f32` values produces zeros instead. +This doesn't affect most architectures or programs. + +### Operations use the best instructions available + +Operations provided by this module compile to the best available SIMD instructions. + +Portable SIMD is not a low-level vendor library, and operations in portable SIMD _do not_ necessarily map to a single instruction. +Instead, they map to a reasonable implementation of the operation for the target. + +Consistency between targets is not compromised to use faster or fewer instructions. +In some cases, `std::arch` will provide a faster function that has slightly different behavior than the `std::simd` equivalent. +For example, `_mm_min_ps`[^1] can be slightly faster than [`SimdFloat::simd_min`](`num::SimdFloat::simd_min`), but does not conform to the IEEE standard also used by [`f32::min`]. +When necessary, [`Simd<T, N>`] can be converted to the types provided by `std::arch` to make use of target-specific functions. + +Many targets simply don't have SIMD, or don't support SIMD for a particular element type. +In those cases, regular scalar operations are generated instead. + +[^1]: `_mm_min_ps(x, y)` is equivalent to `x.simd_lt(y).select(x, y)` diff --git a/library/portable-simd/crates/core_simd/src/fmt.rs b/library/portable-simd/crates/core_simd/src/fmt.rs index b7317969cbb..3a540f5a049 100644 --- a/library/portable-simd/crates/core_simd/src/fmt.rs +++ b/library/portable-simd/crates/core_simd/src/fmt.rs @@ -1,9 +1,9 @@ use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; use core::fmt; -impl<T, const LANES: usize> fmt::Debug for Simd<T, LANES> +impl<T, const N: usize> fmt::Debug for Simd<T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, T: SimdElement + fmt::Debug, { /// A `Simd<T, N>` has a debug format like the one for `[T]`: diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs index dd6698e2ba5..b27893bc729 100644 --- a/library/portable-simd/crates/core_simd/src/intrinsics.rs +++ b/library/portable-simd/crates/core_simd/src/intrinsics.rs @@ -160,4 +160,10 @@ extern "platform-intrinsic" { /// convert an exposed address back to a pointer pub(crate) fn simd_from_exposed_addr<T, U>(addr: T) -> U; + + // Integer operations + pub(crate) fn simd_bswap<T>(x: T) -> T; + pub(crate) fn simd_bitreverse<T>(x: T) -> T; + pub(crate) fn simd_ctlz<T>(x: T) -> T; + pub(crate) fn simd_cttz<T>(x: T) -> T; } diff --git a/library/portable-simd/crates/core_simd/src/iter.rs b/library/portable-simd/crates/core_simd/src/iter.rs index 328c995b81d..b3732fd74d5 100644 --- a/library/portable-simd/crates/core_simd/src/iter.rs +++ b/library/portable-simd/crates/core_simd/src/iter.rs @@ -6,9 +6,9 @@ use core::{ macro_rules! impl_traits { { $type:ty } => { - impl<const LANES: usize> Sum<Self> for Simd<$type, LANES> + impl<const N: usize> Sum<Self> for Simd<$type, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { @@ -16,9 +16,9 @@ macro_rules! impl_traits { } } - impl<const LANES: usize> Product<Self> for Simd<$type, LANES> + impl<const N: usize> Product<Self> for Simd<$type, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn product<I: Iterator<Item = Self>>(iter: I) -> Self { @@ -26,9 +26,9 @@ macro_rules! impl_traits { } } - impl<'a, const LANES: usize> Sum<&'a Self> for Simd<$type, LANES> + impl<'a, const N: usize> Sum<&'a Self> for Simd<$type, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self { @@ -36,9 +36,9 @@ macro_rules! impl_traits { } } - impl<'a, const LANES: usize> Product<&'a Self> for Simd<$type, LANES> + impl<'a, const N: usize> Product<&'a Self> for Simd<$type, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self { diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs index 2b91eb9e800..4cd7265ed67 100644 --- a/library/portable-simd/crates/core_simd/src/lane_count.rs +++ b/library/portable-simd/crates/core_simd/src/lane_count.rs @@ -4,11 +4,11 @@ mod sealed { use sealed::Sealed; /// Specifies the number of lanes in a SIMD vector as a type. -pub struct LaneCount<const LANES: usize>; +pub struct LaneCount<const N: usize>; -impl<const LANES: usize> LaneCount<LANES> { +impl<const N: usize> LaneCount<N> { /// The number of bytes in a bitmask with this many lanes. - pub const BITMASK_LEN: usize = (LANES + 7) / 8; + pub const BITMASK_LEN: usize = (N + 7) / 8; } /// Statically guarantees that a lane count is marked as supported. @@ -21,7 +21,7 @@ pub trait SupportedLaneCount: Sealed { type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>; } -impl<const LANES: usize> Sealed for LaneCount<LANES> {} +impl<const N: usize> Sealed for LaneCount<N> {} macro_rules! supported_lane_count { ($($lanes:literal),+) => { diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index fde406bda70..64ba9705ef5 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -5,6 +5,7 @@ const_mut_refs, convert_float_to_int, decl_macro, + inline_const, intra_doc_pointers, platform_intrinsics, repr_simd, @@ -14,10 +15,9 @@ strict_provenance, ptr_metadata )] -#![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))] -#![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))] #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)] +#![allow(internal_features)] #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs index fea687bdc1a..0623d2bf3d1 100644 --- a/library/portable-simd/crates/core_simd/src/masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks.rs @@ -1,4 +1,4 @@ -//! Types and traits associated with masking lanes of vectors. +//! Types and traits associated with masking elements of vectors. //! Types representing #![allow(non_camel_case_types)] @@ -12,13 +12,9 @@ )] mod mask_impl; -mod to_bitmask; -pub use to_bitmask::ToBitMask; - -#[cfg(feature = "generic_const_exprs")] -pub use to_bitmask::{bitmask_len, ToBitMaskArray}; - -use crate::simd::{intrinsics, LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{ + cmp::SimdPartialEq, intrinsics, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount, +}; use core::cmp::Ordering; use core::{fmt, mem}; @@ -32,13 +28,17 @@ mod sealed { /// prevent us from ever removing that bound, or from implementing `MaskElement` on /// non-`PartialEq` types in the future. pub trait Sealed { - fn valid<const LANES: usize>(values: Simd<Self, LANES>) -> bool + fn valid<const N: usize>(values: Simd<Self, N>) -> bool where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, Self: SimdElement; fn eq(self, other: Self) -> bool; + fn as_usize(self) -> usize; + + type Unsigned: SimdElement; + const TRUE: Self; const FALSE: Self; @@ -50,15 +50,15 @@ use sealed::Sealed; /// /// # Safety /// Type must be a signed integer. -pub unsafe trait MaskElement: SimdElement + Sealed {} +pub unsafe trait MaskElement: SimdElement<Mask = Self> + SimdCast + Sealed {} macro_rules! impl_element { - { $ty:ty } => { + { $ty:ty, $unsigned:ty } => { impl Sealed for $ty { #[inline] - fn valid<const LANES: usize>(value: Simd<Self, LANES>) -> bool + fn valid<const N: usize>(value: Simd<Self, N>) -> bool where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { (value.simd_eq(Simd::splat(0 as _)) | value.simd_eq(Simd::splat(-1 as _))).all() } @@ -66,6 +66,13 @@ macro_rules! impl_element { #[inline] fn eq(self, other: Self) -> bool { self == other } + #[inline] + fn as_usize(self) -> usize { + self as usize + } + + type Unsigned = $unsigned; + const TRUE: Self = -1; const FALSE: Self = 0; } @@ -75,36 +82,36 @@ macro_rules! impl_element { } } -impl_element! { i8 } -impl_element! { i16 } -impl_element! { i32 } -impl_element! { i64 } -impl_element! { isize } +impl_element! { i8, u8 } +impl_element! { i16, u16 } +impl_element! { i32, u32 } +impl_element! { i64, u64 } +impl_element! { isize, usize } -/// A SIMD vector mask for `LANES` elements of width specified by `Element`. +/// A SIMD vector mask for `N` elements of width specified by `Element`. /// -/// Masks represent boolean inclusion/exclusion on a per-lane basis. +/// Masks represent boolean inclusion/exclusion on a per-element basis. /// /// The layout of this type is unspecified, and may change between platforms /// and/or Rust versions, and code should not assume that it is equivalent to -/// `[T; LANES]`. -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 -pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>) +/// `[T; N]`. +#[repr(transparent)] +pub struct Mask<T, const N: usize>(mask_impl::Mask<T, N>) where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount; + LaneCount<N>: SupportedLaneCount; -impl<T, const LANES: usize> Copy for Mask<T, LANES> +impl<T, const N: usize> Copy for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } -impl<T, const LANES: usize> Clone for Mask<T, LANES> +impl<T, const N: usize> Clone for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn clone(&self) -> Self { @@ -112,12 +119,12 @@ where } } -impl<T, const LANES: usize> Mask<T, LANES> +impl<T, const N: usize> Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - /// Construct a mask by setting all lanes to the given value. + /// Construct a mask by setting all elements to the given value. #[inline] pub fn splat(value: bool) -> Self { Self(mask_impl::Mask::splat(value)) @@ -125,7 +132,7 @@ where /// Converts an array of bools to a SIMD mask. #[inline] - pub fn from_array(array: [bool; LANES]) -> Self { + pub fn from_array(array: [bool; N]) -> Self { // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of // true: 0b_0000_0001 // false: 0b_0000_0000 @@ -133,16 +140,15 @@ where // This would be hypothetically valid as an "in-place" transmute, // but these are "dependently-sized" types, so copy elision it is! unsafe { - let bytes: [u8; LANES] = mem::transmute_copy(&array); - let bools: Simd<i8, LANES> = - intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8)); + let bytes: [u8; N] = mem::transmute_copy(&array); + let bools: Simd<i8, N> = intrinsics::simd_ne(Simd::from_array(bytes), Simd::splat(0u8)); Mask::from_int_unchecked(intrinsics::simd_cast(bools)) } } /// Converts a SIMD mask to an array of bools. #[inline] - pub fn to_array(self) -> [bool; LANES] { + pub fn to_array(self) -> [bool; N] { // This follows mostly the same logic as from_array. // SAFETY: Rust's bool has a layout of 1 byte (u8) with a value of // true: 0b_0000_0001 @@ -154,7 +160,7 @@ where // This would be hypothetically valid as an "in-place" transmute, // but these are "dependently-sized" types, so copy elision it is! unsafe { - let mut bytes: Simd<i8, LANES> = intrinsics::simd_cast(self.to_int()); + let mut bytes: Simd<i8, N> = intrinsics::simd_cast(self.to_int()); bytes &= Simd::splat(1i8); mem::transmute_copy(&bytes) } @@ -164,10 +170,10 @@ where /// represents `true`. /// /// # Safety - /// All lanes must be either 0 or -1. + /// All elements must be either 0 or -1. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self { + pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self { // Safety: the caller must confirm this invariant unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) } } @@ -176,11 +182,11 @@ where /// represents `true`. /// /// # Panics - /// Panics if any lane is not 0 or -1. + /// Panics if any element is not 0 or -1. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] #[track_caller] - pub fn from_int(value: Simd<T, LANES>) -> Self { + pub fn from_int(value: Simd<T, N>) -> Self { assert!(T::valid(value), "all values must be either 0 or -1",); // Safety: the validity has been checked unsafe { Self::from_int_unchecked(value) } @@ -190,121 +196,244 @@ where /// represents `true`. #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - pub fn to_int(self) -> Simd<T, LANES> { + pub fn to_int(self) -> Simd<T, N> { self.0.to_int() } - /// Converts the mask to a mask of any other lane size. + /// Converts the mask to a mask of any other element size. #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn cast<U: MaskElement>(self) -> Mask<U, LANES> { + pub fn cast<U: MaskElement>(self) -> Mask<U, N> { Mask(self.0.convert()) } - /// Tests the value of the specified lane. + /// Tests the value of the specified element. /// /// # Safety - /// `lane` must be less than `LANES`. + /// `index` must be less than `self.len()`. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] - pub unsafe fn test_unchecked(&self, lane: usize) -> bool { + pub unsafe fn test_unchecked(&self, index: usize) -> bool { // Safety: the caller must confirm this invariant - unsafe { self.0.test_unchecked(lane) } + unsafe { self.0.test_unchecked(index) } } - /// Tests the value of the specified lane. + /// Tests the value of the specified element. /// /// # Panics - /// Panics if `lane` is greater than or equal to the number of lanes in the vector. + /// Panics if `index` is greater than or equal to the number of elements in the vector. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] #[track_caller] - pub fn test(&self, lane: usize) -> bool { - assert!(lane < LANES, "lane index out of range"); - // Safety: the lane index has been checked - unsafe { self.test_unchecked(lane) } + pub fn test(&self, index: usize) -> bool { + assert!(index < N, "element index out of range"); + // Safety: the element index has been checked + unsafe { self.test_unchecked(index) } } - /// Sets the value of the specified lane. + /// Sets the value of the specified element. /// /// # Safety - /// `lane` must be less than `LANES`. + /// `index` must be less than `self.len()`. #[inline] - pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { + pub unsafe fn set_unchecked(&mut self, index: usize, value: bool) { // Safety: the caller must confirm this invariant unsafe { - self.0.set_unchecked(lane, value); + self.0.set_unchecked(index, value); } } - /// Sets the value of the specified lane. + /// Sets the value of the specified element. /// /// # Panics - /// Panics if `lane` is greater than or equal to the number of lanes in the vector. + /// Panics if `index` is greater than or equal to the number of elements in the vector. #[inline] #[track_caller] - pub fn set(&mut self, lane: usize, value: bool) { - assert!(lane < LANES, "lane index out of range"); - // Safety: the lane index has been checked + pub fn set(&mut self, index: usize, value: bool) { + assert!(index < N, "element index out of range"); + // Safety: the element index has been checked unsafe { - self.set_unchecked(lane, value); + self.set_unchecked(index, value); } } - /// Returns true if any lane is set, or false otherwise. + /// Returns true if any element is set, or false otherwise. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub fn any(self) -> bool { self.0.any() } - /// Returns true if all lanes are set, or false otherwise. + /// Returns true if all elements are set, or false otherwise. #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub fn all(self) -> bool { self.0.all() } + + /// Create a bitmask from a mask. + /// + /// Each bit is set if the corresponding element in the mask is `true`. + /// If the mask contains more than 64 elements, the bitmask is truncated to the first 64. + #[inline] + #[must_use = "method returns a new integer and does not mutate the original value"] + pub fn to_bitmask(self) -> u64 { + self.0.to_bitmask_integer() + } + + /// Create a mask from a bitmask. + /// + /// For each bit, if it is set, the corresponding element in the mask is set to `true`. + /// If the mask contains more than 64 elements, the remainder are set to `false`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn from_bitmask(bitmask: u64) -> Self { + Self(mask_impl::Mask::from_bitmask_integer(bitmask)) + } + + /// Create a bitmask vector from a mask. + /// + /// Each bit is set if the corresponding element in the mask is `true`. + /// The remaining bits are unset. + /// + /// The bits are packed into the first N bits of the vector: + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::mask32x8; + /// let mask = mask32x8::from_array([true, false, true, false, false, false, true, false]); + /// assert_eq!(mask.to_bitmask_vector()[0], 0b01000101); + /// ``` + #[inline] + #[must_use = "method returns a new integer and does not mutate the original value"] + pub fn to_bitmask_vector(self) -> Simd<u8, N> { + self.0.to_bitmask_vector() + } + + /// Create a mask from a bitmask vector. + /// + /// For each bit, if it is set, the corresponding element in the mask is set to `true`. + /// + /// The bits are packed into the first N bits of the vector: + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::{mask32x8, u8x8}; + /// let bitmask = u8x8::from_array([0b01000101, 0, 0, 0, 0, 0, 0, 0]); + /// assert_eq!( + /// mask32x8::from_bitmask_vector(bitmask), + /// mask32x8::from_array([true, false, true, false, false, false, true, false]), + /// ); + /// ``` + #[inline] + #[must_use = "method returns a new mask and does not mutate the original value"] + pub fn from_bitmask_vector(bitmask: Simd<u8, N>) -> Self { + Self(mask_impl::Mask::from_bitmask_vector(bitmask)) + } + + /// Find the index of the first set element. + /// + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::mask32x8; + /// assert_eq!(mask32x8::splat(false).first_set(), None); + /// assert_eq!(mask32x8::splat(true).first_set(), Some(0)); + /// + /// let mask = mask32x8::from_array([false, true, false, false, true, false, false, true]); + /// assert_eq!(mask.first_set(), Some(1)); + /// ``` + #[inline] + #[must_use = "method returns the index and does not mutate the original value"] + pub fn first_set(self) -> Option<usize> { + // If bitmasks are efficient, using them is better + if cfg!(target_feature = "sse") && N <= 64 { + let tz = self.to_bitmask().trailing_zeros(); + return if tz == 64 { None } else { Some(tz as usize) }; + } + + // To find the first set index: + // * create a vector 0..N + // * replace unset mask elements in that vector with -1 + // * perform _unsigned_ reduce-min + // * check if the result is -1 or an index + + let index = Simd::from_array( + const { + let mut index = [0; N]; + let mut i = 0; + while i < N { + index[i] = i; + i += 1; + } + index + }, + ); + + // Safety: the input and output are integer vectors + let index: Simd<T, N> = unsafe { intrinsics::simd_cast(index) }; + + let masked_index = self.select(index, Self::splat(true).to_int()); + + // Safety: the input and output are integer vectors + let masked_index: Simd<T::Unsigned, N> = unsafe { intrinsics::simd_cast(masked_index) }; + + // Safety: the input is an integer vector + let min_index: T::Unsigned = unsafe { intrinsics::simd_reduce_min(masked_index) }; + + // Safety: the return value is the unsigned version of T + let min_index: T = unsafe { core::mem::transmute_copy(&min_index) }; + + if min_index.eq(T::TRUE) { + None + } else { + Some(min_index.as_usize()) + } + } } // vector/array conversion -impl<T, const LANES: usize> From<[bool; LANES]> for Mask<T, LANES> +impl<T, const N: usize> From<[bool; N]> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] - fn from(array: [bool; LANES]) -> Self { + fn from(array: [bool; N]) -> Self { Self::from_array(array) } } -impl<T, const LANES: usize> From<Mask<T, LANES>> for [bool; LANES] +impl<T, const N: usize> From<Mask<T, N>> for [bool; N] where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] - fn from(vector: Mask<T, LANES>) -> Self { + fn from(vector: Mask<T, N>) -> Self { vector.to_array() } } -impl<T, const LANES: usize> Default for Mask<T, LANES> +impl<T, const N: usize> Default for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] - #[must_use = "method returns a defaulted mask with all lanes set to false (0)"] + #[must_use = "method returns a defaulted mask with all elements set to false (0)"] fn default() -> Self { Self::splat(false) } } -impl<T, const LANES: usize> PartialEq for Mask<T, LANES> +impl<T, const N: usize> PartialEq for Mask<T, N> where T: MaskElement + PartialEq, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] @@ -313,10 +442,10 @@ where } } -impl<T, const LANES: usize> PartialOrd for Mask<T, LANES> +impl<T, const N: usize> PartialOrd for Mask<T, N> where T: MaskElement + PartialOrd, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] #[must_use = "method returns a new Ordering and does not mutate the original value"] @@ -325,23 +454,23 @@ where } } -impl<T, const LANES: usize> fmt::Debug for Mask<T, LANES> +impl<T, const N: usize> fmt::Debug for Mask<T, N> where T: MaskElement + fmt::Debug, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() - .entries((0..LANES).map(|lane| self.test(lane))) + .entries((0..N).map(|i| self.test(i))) .finish() } } -impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitAnd for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -351,10 +480,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitAnd<bool> for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitAnd<bool> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -364,23 +493,23 @@ where } } -impl<T, const LANES: usize> core::ops::BitAnd<Mask<T, LANES>> for bool +impl<T, const N: usize> core::ops::BitAnd<Mask<T, N>> for bool where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Output = Mask<T, LANES>; + type Output = Mask<T, N>; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - fn bitand(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> { + fn bitand(self, rhs: Mask<T, N>) -> Mask<T, N> { Mask::splat(self) & rhs } } -impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitOr for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -390,10 +519,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitOr<bool> for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitOr<bool> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -403,23 +532,23 @@ where } } -impl<T, const LANES: usize> core::ops::BitOr<Mask<T, LANES>> for bool +impl<T, const N: usize> core::ops::BitOr<Mask<T, N>> for bool where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Output = Mask<T, LANES>; + type Output = Mask<T, N>; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - fn bitor(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> { + fn bitor(self, rhs: Mask<T, N>) -> Mask<T, N> { Mask::splat(self) | rhs } } -impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitXor for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -429,10 +558,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitXor<bool> for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitXor<bool> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -442,25 +571,25 @@ where } } -impl<T, const LANES: usize> core::ops::BitXor<Mask<T, LANES>> for bool +impl<T, const N: usize> core::ops::BitXor<Mask<T, N>> for bool where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Output = Mask<T, LANES>; + type Output = Mask<T, N>; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - fn bitxor(self, rhs: Mask<T, LANES>) -> Self::Output { + fn bitxor(self, rhs: Mask<T, N>) -> Self::Output { Mask::splat(self) ^ rhs } } -impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES> +impl<T, const N: usize> core::ops::Not for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Output = Mask<T, LANES>; + type Output = Mask<T, N>; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] fn not(self) -> Self::Output { @@ -468,10 +597,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitAndAssign for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitAndAssign for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn bitand_assign(&mut self, rhs: Self) { @@ -479,10 +608,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitAndAssign<bool> for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitAndAssign<bool> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn bitand_assign(&mut self, rhs: bool) { @@ -490,10 +619,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitOrAssign for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitOrAssign for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn bitor_assign(&mut self, rhs: Self) { @@ -501,10 +630,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitOrAssign<bool> for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitOrAssign<bool> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn bitor_assign(&mut self, rhs: bool) { @@ -512,10 +641,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitXorAssign for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitXorAssign for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn bitxor_assign(&mut self, rhs: Self) { @@ -523,10 +652,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitXorAssign<bool> for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitXorAssign<bool> for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn bitxor_assign(&mut self, rhs: bool) { @@ -537,12 +666,12 @@ where macro_rules! impl_from { { $from:ty => $($to:ty),* } => { $( - impl<const LANES: usize> From<Mask<$from, LANES>> for Mask<$to, LANES> + impl<const N: usize> From<Mask<$from, N>> for Mask<$to, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] - fn from(value: Mask<$from, LANES>) -> Self { + fn from(value: Mask<$from, N>) -> Self { value.cast() } } diff --git a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs index 20465ba9b07..6ddff07fea2 100644 --- a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs +++ b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs @@ -1,30 +1,30 @@ #![allow(unused_imports)] use super::MaskElement; use crate::simd::intrinsics; -use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask}; +use crate::simd::{LaneCount, Simd, SupportedLaneCount}; use core::marker::PhantomData; /// A mask where each lane is represented by a single bit. #[repr(transparent)] -pub struct Mask<T, const LANES: usize>( - <LaneCount<LANES> as SupportedLaneCount>::BitMask, +pub struct Mask<T, const N: usize>( + <LaneCount<N> as SupportedLaneCount>::BitMask, PhantomData<T>, ) where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount; + LaneCount<N>: SupportedLaneCount; -impl<T, const LANES: usize> Copy for Mask<T, LANES> +impl<T, const N: usize> Copy for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } -impl<T, const LANES: usize> Clone for Mask<T, LANES> +impl<T, const N: usize> Clone for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn clone(&self) -> Self { @@ -32,10 +32,10 @@ where } } -impl<T, const LANES: usize> PartialEq for Mask<T, LANES> +impl<T, const N: usize> PartialEq for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn eq(&self, other: &Self) -> bool { @@ -43,10 +43,10 @@ where } } -impl<T, const LANES: usize> PartialOrd for Mask<T, LANES> +impl<T, const N: usize> PartialOrd for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { @@ -54,17 +54,17 @@ where } } -impl<T, const LANES: usize> Eq for Mask<T, LANES> +impl<T, const N: usize> Eq for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } -impl<T, const LANES: usize> Ord for Mask<T, LANES> +impl<T, const N: usize> Ord for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn cmp(&self, other: &Self) -> core::cmp::Ordering { @@ -72,22 +72,22 @@ where } } -impl<T, const LANES: usize> Mask<T, LANES> +impl<T, const N: usize> Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub fn splat(value: bool) -> Self { - let mut mask = <LaneCount<LANES> as SupportedLaneCount>::BitMask::default(); + let mut mask = <LaneCount<N> as SupportedLaneCount>::BitMask::default(); if value { mask.as_mut().fill(u8::MAX) } else { mask.as_mut().fill(u8::MIN) } - if LANES % 8 > 0 { - *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8); + if N % 8 > 0 { + *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - N % 8); } Self(mask, PhantomData) } @@ -107,7 +107,7 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - pub fn to_int(self) -> Simd<T, LANES> { + pub fn to_int(self) -> Simd<T, N> { unsafe { intrinsics::simd_select_bitmask(self.0, Simd::splat(T::TRUE), Simd::splat(T::FALSE)) } @@ -115,51 +115,47 @@ where #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self { + pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self { unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) } } - #[cfg(feature = "generic_const_exprs")] #[inline] - #[must_use = "method returns a new array and does not mutate the original value"] - pub fn to_bitmask_array<const N: usize>(self) -> [u8; N] { - assert!(core::mem::size_of::<Self>() == N); - - // Safety: converting an integer to an array of bytes of the same size is safe - unsafe { core::mem::transmute_copy(&self.0) } + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn to_bitmask_vector(self) -> Simd<u8, N> { + let mut bitmask = Simd::splat(0); + bitmask.as_mut_array()[..self.0.as_ref().len()].copy_from_slice(self.0.as_ref()); + bitmask } - #[cfg(feature = "generic_const_exprs")] #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn from_bitmask_array<const N: usize>(bitmask: [u8; N]) -> Self { - assert!(core::mem::size_of::<Self>() == N); - - // Safety: converting an array of bytes to an integer of the same size is safe - Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData) + pub fn from_bitmask_vector(bitmask: Simd<u8, N>) -> Self { + let mut bytes = <LaneCount<N> as SupportedLaneCount>::BitMask::default(); + let len = bytes.as_ref().len(); + bytes.as_mut().copy_from_slice(&bitmask.as_array()[..len]); + Self(bytes, PhantomData) } #[inline] - pub fn to_bitmask_integer<U>(self) -> U - where - super::Mask<T, LANES>: ToBitMask<BitMask = U>, - { - // Safety: these are the same types - unsafe { core::mem::transmute_copy(&self.0) } + pub fn to_bitmask_integer(self) -> u64 { + let mut bitmask = [0u8; 8]; + bitmask[..self.0.as_ref().len()].copy_from_slice(self.0.as_ref()); + u64::from_ne_bytes(bitmask) } #[inline] - pub fn from_bitmask_integer<U>(bitmask: U) -> Self - where - super::Mask<T, LANES>: ToBitMask<BitMask = U>, - { - // Safety: these are the same types - unsafe { Self(core::mem::transmute_copy(&bitmask), PhantomData) } + pub fn from_bitmask_integer(bitmask: u64) -> Self { + let mut bytes = <LaneCount<N> as SupportedLaneCount>::BitMask::default(); + let len = bytes.as_mut().len(); + bytes + .as_mut() + .copy_from_slice(&bitmask.to_ne_bytes()[..len]); + Self(bytes, PhantomData) } #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn convert<U>(self) -> Mask<U, LANES> + pub fn convert<U>(self) -> Mask<U, N> where U: MaskElement, { @@ -180,11 +176,11 @@ where } } -impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitAnd for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, - <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, + LaneCount<N>: SupportedLaneCount, + <LaneCount<N> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, { type Output = Self; #[inline] @@ -197,11 +193,11 @@ where } } -impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitOr for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, - <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, + LaneCount<N>: SupportedLaneCount, + <LaneCount<N> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, { type Output = Self; #[inline] @@ -214,10 +210,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitXor for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -230,10 +226,10 @@ where } } -impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES> +impl<T, const N: usize> core::ops::Not for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -242,8 +238,8 @@ where for x in self.0.as_mut() { *x = !*x; } - if LANES % 8 > 0 { - *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8); + if N % 8 > 0 { + *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - N % 8); } self } diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs index 1d13c45b8e7..63964f455e0 100644 --- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs @@ -1,29 +1,25 @@ //! Masks that take up full SIMD vector registers. -use super::MaskElement; use crate::simd::intrinsics; -use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask}; - -#[cfg(feature = "generic_const_exprs")] -use crate::simd::ToBitMaskArray; +use crate::simd::{LaneCount, MaskElement, Simd, SupportedLaneCount}; #[repr(transparent)] -pub struct Mask<T, const LANES: usize>(Simd<T, LANES>) +pub struct Mask<T, const N: usize>(Simd<T, N>) where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount; + LaneCount<N>: SupportedLaneCount; -impl<T, const LANES: usize> Copy for Mask<T, LANES> +impl<T, const N: usize> Copy for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } -impl<T, const LANES: usize> Clone for Mask<T, LANES> +impl<T, const N: usize> Clone for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] @@ -32,10 +28,10 @@ where } } -impl<T, const LANES: usize> PartialEq for Mask<T, LANES> +impl<T, const N: usize> PartialEq for Mask<T, N> where T: MaskElement + PartialEq, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn eq(&self, other: &Self) -> bool { @@ -43,10 +39,10 @@ where } } -impl<T, const LANES: usize> PartialOrd for Mask<T, LANES> +impl<T, const N: usize> PartialOrd for Mask<T, N> where T: MaskElement + PartialOrd, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { @@ -54,17 +50,17 @@ where } } -impl<T, const LANES: usize> Eq for Mask<T, LANES> +impl<T, const N: usize> Eq for Mask<T, N> where T: MaskElement + Eq, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } -impl<T, const LANES: usize> Ord for Mask<T, LANES> +impl<T, const N: usize> Ord for Mask<T, N> where T: MaskElement + Ord, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn cmp(&self, other: &Self) -> core::cmp::Ordering { @@ -101,10 +97,10 @@ macro_rules! impl_reverse_bits { impl_reverse_bits! { u8, u16, u32, u64 } -impl<T, const LANES: usize> Mask<T, LANES> +impl<T, const N: usize> Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] @@ -125,19 +121,19 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] - pub fn to_int(self) -> Simd<T, LANES> { + pub fn to_int(self) -> Simd<T, N> { self.0 } #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self { + pub unsafe fn from_int_unchecked(value: Simd<T, N>) -> Self { Self(value) } #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn convert<U>(self) -> Mask<U, LANES> + pub fn convert<U>(self) -> Mask<U, N> where U: MaskElement, { @@ -145,62 +141,50 @@ where unsafe { Mask(intrinsics::simd_cast(self.0)) } } - #[cfg(feature = "generic_const_exprs")] #[inline] - #[must_use = "method returns a new array and does not mutate the original value"] - pub fn to_bitmask_array<const N: usize>(self) -> [u8; N] - where - super::Mask<T, LANES>: ToBitMaskArray, - [(); <super::Mask<T, LANES> as ToBitMaskArray>::BYTES]: Sized, - { - assert_eq!(<super::Mask<T, LANES> as ToBitMaskArray>::BYTES, N); + #[must_use = "method returns a new vector and does not mutate the original value"] + pub fn to_bitmask_vector(self) -> Simd<u8, N> { + let mut bitmask = Simd::splat(0); - // Safety: N is the correct bitmask size + // Safety: Bytes is the right size array unsafe { // Compute the bitmask - let bitmask: [u8; <super::Mask<T, LANES> as ToBitMaskArray>::BYTES] = + let mut bytes: <LaneCount<N> as SupportedLaneCount>::BitMask = intrinsics::simd_bitmask(self.0); - // Transmute to the return type, previously asserted to be the same size - let mut bitmask: [u8; N] = core::mem::transmute_copy(&bitmask); - // LLVM assumes bit order should match endianness if cfg!(target_endian = "big") { - for x in bitmask.as_mut() { - *x = x.reverse_bits(); + for x in bytes.as_mut() { + *x = x.reverse_bits() } - }; + } - bitmask + bitmask.as_mut_array()[..bytes.as_ref().len()].copy_from_slice(bytes.as_ref()); } + + bitmask } - #[cfg(feature = "generic_const_exprs")] #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] - pub fn from_bitmask_array<const N: usize>(mut bitmask: [u8; N]) -> Self - where - super::Mask<T, LANES>: ToBitMaskArray, - [(); <super::Mask<T, LANES> as ToBitMaskArray>::BYTES]: Sized, - { - assert_eq!(<super::Mask<T, LANES> as ToBitMaskArray>::BYTES, N); + pub fn from_bitmask_vector(bitmask: Simd<u8, N>) -> Self { + let mut bytes = <LaneCount<N> as SupportedLaneCount>::BitMask::default(); - // Safety: N is the correct bitmask size + // Safety: Bytes is the right size array unsafe { + let len = bytes.as_ref().len(); + bytes.as_mut().copy_from_slice(&bitmask.as_array()[..len]); + // LLVM assumes bit order should match endianness if cfg!(target_endian = "big") { - for x in bitmask.as_mut() { + for x in bytes.as_mut() { *x = x.reverse_bits(); } } - // Transmute to the bitmask type, previously asserted to be the same size - let bitmask: [u8; <super::Mask<T, LANES> as ToBitMaskArray>::BYTES] = - core::mem::transmute_copy(&bitmask); - // Compute the regular mask Self::from_int_unchecked(intrinsics::simd_select_bitmask( - bitmask, + bytes, Self::splat(true).to_int(), Self::splat(false).to_int(), )) @@ -208,40 +192,81 @@ where } #[inline] - pub(crate) fn to_bitmask_integer<U: ReverseBits>(self) -> U + unsafe fn to_bitmask_impl<U: ReverseBits, const M: usize>(self) -> U where - super::Mask<T, LANES>: ToBitMask<BitMask = U>, + LaneCount<M>: SupportedLaneCount, { - // Safety: U is required to be the appropriate bitmask type - let bitmask: U = unsafe { intrinsics::simd_bitmask(self.0) }; + let resized = self.to_int().resize::<M>(T::FALSE); + + // Safety: `resized` is an integer vector with length M, which must match T + let bitmask: U = unsafe { intrinsics::simd_bitmask(resized) }; // LLVM assumes bit order should match endianness if cfg!(target_endian = "big") { - bitmask.reverse_bits(LANES) + bitmask.reverse_bits(M) } else { bitmask } } #[inline] - pub(crate) fn from_bitmask_integer<U: ReverseBits>(bitmask: U) -> Self + unsafe fn from_bitmask_impl<U: ReverseBits, const M: usize>(bitmask: U) -> Self where - super::Mask<T, LANES>: ToBitMask<BitMask = U>, + LaneCount<M>: SupportedLaneCount, { // LLVM assumes bit order should match endianness let bitmask = if cfg!(target_endian = "big") { - bitmask.reverse_bits(LANES) + bitmask.reverse_bits(M) } else { bitmask }; - // Safety: U is required to be the appropriate bitmask type - unsafe { - Self::from_int_unchecked(intrinsics::simd_select_bitmask( + // SAFETY: `mask` is the correct bitmask type for a u64 bitmask + let mask: Simd<T, M> = unsafe { + intrinsics::simd_select_bitmask( bitmask, - Self::splat(true).to_int(), - Self::splat(false).to_int(), - )) + Simd::<T, M>::splat(T::TRUE), + Simd::<T, M>::splat(T::FALSE), + ) + }; + + // SAFETY: `mask` only contains `T::TRUE` or `T::FALSE` + unsafe { Self::from_int_unchecked(mask.resize::<N>(T::FALSE)) } + } + + #[inline] + pub(crate) fn to_bitmask_integer(self) -> u64 { + // TODO modify simd_bitmask to zero-extend output, making this unnecessary + if N <= 8 { + // Safety: bitmask matches length + unsafe { self.to_bitmask_impl::<u8, 8>() as u64 } + } else if N <= 16 { + // Safety: bitmask matches length + unsafe { self.to_bitmask_impl::<u16, 16>() as u64 } + } else if N <= 32 { + // Safety: bitmask matches length + unsafe { self.to_bitmask_impl::<u32, 32>() as u64 } + } else { + // Safety: bitmask matches length + unsafe { self.to_bitmask_impl::<u64, 64>() } + } + } + + #[inline] + pub(crate) fn from_bitmask_integer(bitmask: u64) -> Self { + // TODO modify simd_bitmask_select to truncate input, making this unnecessary + if N <= 8 { + // Safety: bitmask matches length + unsafe { Self::from_bitmask_impl::<u8, 8>(bitmask as u8) } + } else if N <= 16 { + // Safety: bitmask matches length + unsafe { Self::from_bitmask_impl::<u16, 16>(bitmask as u16) } + } else if N <= 32 { + // Safety: bitmask matches length + unsafe { Self::from_bitmask_impl::<u32, 32>(bitmask as u32) } + } else { + // Safety: bitmask matches length + unsafe { Self::from_bitmask_impl::<u64, 64>(bitmask) } } } @@ -260,21 +285,21 @@ where } } -impl<T, const LANES: usize> From<Mask<T, LANES>> for Simd<T, LANES> +impl<T, const N: usize> From<Mask<T, N>> for Simd<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] - fn from(value: Mask<T, LANES>) -> Self { + fn from(value: Mask<T, N>) -> Self { value.0 } } -impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitAnd for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -285,10 +310,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitOr for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -299,10 +324,10 @@ where } } -impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES> +impl<T, const N: usize> core::ops::BitXor for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] @@ -313,10 +338,10 @@ where } } -impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES> +impl<T, const N: usize> core::ops::Not for Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; #[inline] diff --git a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs deleted file mode 100644 index fc7d6b781f2..00000000000 --- a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs +++ /dev/null @@ -1,97 +0,0 @@ -use super::{mask_impl, Mask, MaskElement}; -use crate::simd::{LaneCount, SupportedLaneCount}; - -mod sealed { - pub trait Sealed {} -} -pub use sealed::Sealed; - -impl<T, const LANES: usize> Sealed for Mask<T, LANES> -where - T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, -{ -} - -/// Converts masks to and from integer bitmasks. -/// -/// Each bit of the bitmask corresponds to a mask lane, starting with the LSB. -pub trait ToBitMask: Sealed { - /// The integer bitmask type. - type BitMask; - - /// Converts a mask to a bitmask. - fn to_bitmask(self) -> Self::BitMask; - - /// Converts a bitmask to a mask. - fn from_bitmask(bitmask: Self::BitMask) -> Self; -} - -/// Converts masks to and from byte array bitmasks. -/// -/// Each bit of the bitmask corresponds to a mask lane, starting with the LSB of the first byte. -#[cfg(feature = "generic_const_exprs")] -pub trait ToBitMaskArray: Sealed { - /// The length of the bitmask array. - const BYTES: usize; - - /// Converts a mask to a bitmask. - fn to_bitmask_array(self) -> [u8; Self::BYTES]; - - /// Converts a bitmask to a mask. - fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self; -} - -macro_rules! impl_integer_intrinsic { - { $(impl ToBitMask<BitMask=$int:ty> for Mask<_, $lanes:literal>)* } => { - $( - impl<T: MaskElement> ToBitMask for Mask<T, $lanes> { - type BitMask = $int; - - #[inline] - fn to_bitmask(self) -> $int { - self.0.to_bitmask_integer() - } - - #[inline] - fn from_bitmask(bitmask: $int) -> Self { - Self(mask_impl::Mask::from_bitmask_integer(bitmask)) - } - } - )* - } -} - -impl_integer_intrinsic! { - impl ToBitMask<BitMask=u8> for Mask<_, 1> - impl ToBitMask<BitMask=u8> for Mask<_, 2> - impl ToBitMask<BitMask=u8> for Mask<_, 4> - impl ToBitMask<BitMask=u8> for Mask<_, 8> - impl ToBitMask<BitMask=u16> for Mask<_, 16> - impl ToBitMask<BitMask=u32> for Mask<_, 32> - impl ToBitMask<BitMask=u64> for Mask<_, 64> -} - -/// Returns the minimum number of bytes in a bitmask with `lanes` lanes. -#[cfg(feature = "generic_const_exprs")] -pub const fn bitmask_len(lanes: usize) -> usize { - (lanes + 7) / 8 -} - -#[cfg(feature = "generic_const_exprs")] -impl<T: MaskElement, const LANES: usize> ToBitMaskArray for Mask<T, LANES> -where - LaneCount<LANES>: SupportedLaneCount, -{ - const BYTES: usize = bitmask_len(LANES); - - #[inline] - fn to_bitmask_array(self) -> [u8; Self::BYTES] { - self.0.to_bitmask_array() - } - - #[inline] - fn from_bitmask_array(bitmask: [u8; Self::BYTES]) -> Self { - Mask(mask_impl::Mask::from_bitmask_array(bitmask)) - } -} diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs index 19426769858..fd016f1c6f7 100644 --- a/library/portable-simd/crates/core_simd/src/mod.rs +++ b/library/portable-simd/crates/core_simd/src/mod.rs @@ -3,37 +3,37 @@ mod swizzle; pub(crate) mod intrinsics; -#[cfg(feature = "generic_const_exprs")] -mod to_bytes; - mod alias; mod cast; -mod elements; -mod eq; mod fmt; mod iter; mod lane_count; mod masks; mod ops; -mod ord; mod select; mod swizzle_dyn; +mod to_bytes; mod vector; mod vendor; -#[doc = include_str!("core_simd_docs.md")] pub mod simd { + #![doc = include_str!("core_simd_docs.md")] + pub mod prelude; + pub mod num; + + pub mod ptr; + + pub mod cmp; + pub(crate) use crate::core_simd::intrinsics; pub use crate::core_simd::alias::*; pub use crate::core_simd::cast::*; - pub use crate::core_simd::elements::*; - pub use crate::core_simd::eq::*; pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount}; pub use crate::core_simd::masks::*; - pub use crate::core_simd::ord::*; pub use crate::core_simd::swizzle::*; + pub use crate::core_simd::to_bytes::ToBytes; pub use crate::core_simd::vector::*; } diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs index b007456cf2c..8a1b083f039 100644 --- a/library/portable-simd/crates/core_simd/src/ops.rs +++ b/library/portable-simd/crates/core_simd/src/ops.rs @@ -1,4 +1,4 @@ -use crate::simd::{LaneCount, Simd, SimdElement, SimdPartialEq, SupportedLaneCount}; +use crate::simd::{cmp::SimdPartialEq, LaneCount, Simd, SimdElement, SupportedLaneCount}; use core::ops::{Add, Mul}; use core::ops::{BitAnd, BitOr, BitXor}; use core::ops::{Div, Rem, Sub}; @@ -6,12 +6,13 @@ use core::ops::{Shl, Shr}; mod assign; mod deref; +mod shift_scalar; mod unary; -impl<I, T, const LANES: usize> core::ops::Index<I> for Simd<T, LANES> +impl<I, T, const N: usize> core::ops::Index<I> for Simd<T, N> where T: SimdElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, I: core::slice::SliceIndex<[T]>, { type Output = I::Output; @@ -21,10 +22,10 @@ where } } -impl<I, T, const LANES: usize> core::ops::IndexMut<I> for Simd<T, LANES> +impl<I, T, const N: usize> core::ops::IndexMut<I> for Simd<T, N> where T: SimdElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, I: core::slice::SliceIndex<[T]>, { #[inline] diff --git a/library/portable-simd/crates/core_simd/src/ops/assign.rs b/library/portable-simd/crates/core_simd/src/ops/assign.rs index d2b48614fc9..0e87785025a 100644 --- a/library/portable-simd/crates/core_simd/src/ops/assign.rs +++ b/library/portable-simd/crates/core_simd/src/ops/assign.rs @@ -8,7 +8,7 @@ use core::ops::{ShlAssign, ShrAssign}; // non-commutative bit binary op-assignme // Arithmetic macro_rules! assign_ops { - ($(impl<T, U, const LANES: usize> $assignTrait:ident<U> for Simd<T, LANES> + ($(impl<T, U, const N: usize> $assignTrait:ident<U> for Simd<T, N> where Self: $trait:ident, { @@ -16,11 +16,11 @@ macro_rules! assign_ops { $call:ident } })*) => { - $(impl<T, U, const LANES: usize> $assignTrait<U> for Simd<T, LANES> + $(impl<T, U, const N: usize> $assignTrait<U> for Simd<T, N> where Self: $trait<U, Output = Self>, T: SimdElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn $assign_call(&mut self, rhs: U) { @@ -32,7 +32,7 @@ macro_rules! assign_ops { assign_ops! { // Arithmetic - impl<T, U, const LANES: usize> AddAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> AddAssign<U> for Simd<T, N> where Self: Add, { @@ -41,7 +41,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> MulAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> MulAssign<U> for Simd<T, N> where Self: Mul, { @@ -50,7 +50,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> SubAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> SubAssign<U> for Simd<T, N> where Self: Sub, { @@ -59,7 +59,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> DivAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> DivAssign<U> for Simd<T, N> where Self: Div, { @@ -67,7 +67,7 @@ assign_ops! { div } } - impl<T, U, const LANES: usize> RemAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> RemAssign<U> for Simd<T, N> where Self: Rem, { @@ -77,7 +77,7 @@ assign_ops! { } // Bitops - impl<T, U, const LANES: usize> BitAndAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> BitAndAssign<U> for Simd<T, N> where Self: BitAnd, { @@ -86,7 +86,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> BitOrAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> BitOrAssign<U> for Simd<T, N> where Self: BitOr, { @@ -95,7 +95,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> BitXorAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> BitXorAssign<U> for Simd<T, N> where Self: BitXor, { @@ -104,7 +104,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> ShlAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> ShlAssign<U> for Simd<T, N> where Self: Shl, { @@ -113,7 +113,7 @@ assign_ops! { } } - impl<T, U, const LANES: usize> ShrAssign<U> for Simd<T, LANES> + impl<T, U, const N: usize> ShrAssign<U> for Simd<T, N> where Self: Shr, { diff --git a/library/portable-simd/crates/core_simd/src/ops/deref.rs b/library/portable-simd/crates/core_simd/src/ops/deref.rs index 302bf148bd3..89a60ba1141 100644 --- a/library/portable-simd/crates/core_simd/src/ops/deref.rs +++ b/library/portable-simd/crates/core_simd/src/ops/deref.rs @@ -5,16 +5,16 @@ use super::*; macro_rules! deref_lhs { - (impl<T, const LANES: usize> $trait:ident for $simd:ty { + (impl<T, const N: usize> $trait:ident for $simd:ty { fn $call:ident }) => { - impl<T, const LANES: usize> $trait<$simd> for &$simd + impl<T, const N: usize> $trait<$simd> for &$simd where T: SimdElement, $simd: $trait<$simd, Output = $simd>, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Output = Simd<T, LANES>; + type Output = Simd<T, N>; #[inline] #[must_use = "operator returns a new vector without mutating the inputs"] @@ -26,16 +26,16 @@ macro_rules! deref_lhs { } macro_rules! deref_rhs { - (impl<T, const LANES: usize> $trait:ident for $simd:ty { + (impl<T, const N: usize> $trait:ident for $simd:ty { fn $call:ident }) => { - impl<T, const LANES: usize> $trait<&$simd> for $simd + impl<T, const N: usize> $trait<&$simd> for $simd where T: SimdElement, $simd: $trait<$simd, Output = $simd>, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Output = Simd<T, LANES>; + type Output = Simd<T, N>; #[inline] #[must_use = "operator returns a new vector without mutating the inputs"] @@ -47,25 +47,25 @@ macro_rules! deref_rhs { } macro_rules! deref_ops { - ($(impl<T, const LANES: usize> $trait:ident for $simd:ty { + ($(impl<T, const N: usize> $trait:ident for $simd:ty { fn $call:ident })*) => { $( deref_rhs! { - impl<T, const LANES: usize> $trait for $simd { + impl<T, const N: usize> $trait for $simd { fn $call } } deref_lhs! { - impl<T, const LANES: usize> $trait for $simd { + impl<T, const N: usize> $trait for $simd { fn $call } } - impl<'lhs, 'rhs, T, const LANES: usize> $trait<&'rhs $simd> for &'lhs $simd + impl<'lhs, 'rhs, T, const N: usize> $trait<&'rhs $simd> for &'lhs $simd where T: SimdElement, $simd: $trait<$simd, Output = $simd>, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = $simd; @@ -81,44 +81,44 @@ macro_rules! deref_ops { deref_ops! { // Arithmetic - impl<T, const LANES: usize> Add for Simd<T, LANES> { + impl<T, const N: usize> Add for Simd<T, N> { fn add } - impl<T, const LANES: usize> Mul for Simd<T, LANES> { + impl<T, const N: usize> Mul for Simd<T, N> { fn mul } - impl<T, const LANES: usize> Sub for Simd<T, LANES> { + impl<T, const N: usize> Sub for Simd<T, N> { fn sub } - impl<T, const LANES: usize> Div for Simd<T, LANES> { + impl<T, const N: usize> Div for Simd<T, N> { fn div } - impl<T, const LANES: usize> Rem for Simd<T, LANES> { + impl<T, const N: usize> Rem for Simd<T, N> { fn rem } // Bitops - impl<T, const LANES: usize> BitAnd for Simd<T, LANES> { + impl<T, const N: usize> BitAnd for Simd<T, N> { fn bitand } - impl<T, const LANES: usize> BitOr for Simd<T, LANES> { + impl<T, const N: usize> BitOr for Simd<T, N> { fn bitor } - impl<T, const LANES: usize> BitXor for Simd<T, LANES> { + impl<T, const N: usize> BitXor for Simd<T, N> { fn bitxor } - impl<T, const LANES: usize> Shl for Simd<T, LANES> { + impl<T, const N: usize> Shl for Simd<T, N> { fn shl } - impl<T, const LANES: usize> Shr for Simd<T, LANES> { + impl<T, const N: usize> Shr for Simd<T, N> { fn shr } } diff --git a/library/portable-simd/crates/core_simd/src/ops/shift_scalar.rs b/library/portable-simd/crates/core_simd/src/ops/shift_scalar.rs new file mode 100644 index 00000000000..f5115a5a5e9 --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/ops/shift_scalar.rs @@ -0,0 +1,62 @@ +// Shift operations uniquely typically only have a scalar on the right-hand side. +// Here, we implement shifts for scalar RHS arguments. + +use crate::simd::{LaneCount, Simd, SupportedLaneCount}; + +macro_rules! impl_splatted_shifts { + { impl $trait:ident :: $trait_fn:ident for $ty:ty } => { + impl<const N: usize> core::ops::$trait<$ty> for Simd<$ty, N> + where + LaneCount<N>: SupportedLaneCount, + { + type Output = Self; + #[inline] + fn $trait_fn(self, rhs: $ty) -> Self::Output { + self.$trait_fn(Simd::splat(rhs)) + } + } + + impl<const N: usize> core::ops::$trait<&$ty> for Simd<$ty, N> + where + LaneCount<N>: SupportedLaneCount, + { + type Output = Self; + #[inline] + fn $trait_fn(self, rhs: &$ty) -> Self::Output { + self.$trait_fn(Simd::splat(*rhs)) + } + } + + impl<'lhs, const N: usize> core::ops::$trait<$ty> for &'lhs Simd<$ty, N> + where + LaneCount<N>: SupportedLaneCount, + { + type Output = Simd<$ty, N>; + #[inline] + fn $trait_fn(self, rhs: $ty) -> Self::Output { + self.$trait_fn(Simd::splat(rhs)) + } + } + + impl<'lhs, const N: usize> core::ops::$trait<&$ty> for &'lhs Simd<$ty, N> + where + LaneCount<N>: SupportedLaneCount, + { + type Output = Simd<$ty, N>; + #[inline] + fn $trait_fn(self, rhs: &$ty) -> Self::Output { + self.$trait_fn(Simd::splat(*rhs)) + } + } + }; + { $($ty:ty),* } => { + $( + impl_splatted_shifts! { impl Shl::shl for $ty } + impl_splatted_shifts! { impl Shr::shr for $ty } + )* + } +} + +// In the past there were inference issues when generically splatting arguments. +// Enumerate them instead. +impl_splatted_shifts! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs index 4ad02215034..a651aa73e95 100644 --- a/library/portable-simd/crates/core_simd/src/ops/unary.rs +++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs @@ -3,11 +3,11 @@ use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; use core::ops::{Neg, Not}; // unary ops macro_rules! neg { - ($(impl<const LANES: usize> Neg for Simd<$scalar:ty, LANES>)*) => { - $(impl<const LANES: usize> Neg for Simd<$scalar, LANES> + ($(impl<const N: usize> Neg for Simd<$scalar:ty, N>)*) => { + $(impl<const N: usize> Neg for Simd<$scalar, N> where $scalar: SimdElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; @@ -22,27 +22,27 @@ macro_rules! neg { } neg! { - impl<const LANES: usize> Neg for Simd<f32, LANES> + impl<const N: usize> Neg for Simd<f32, N> - impl<const LANES: usize> Neg for Simd<f64, LANES> + impl<const N: usize> Neg for Simd<f64, N> - impl<const LANES: usize> Neg for Simd<i8, LANES> + impl<const N: usize> Neg for Simd<i8, N> - impl<const LANES: usize> Neg for Simd<i16, LANES> + impl<const N: usize> Neg for Simd<i16, N> - impl<const LANES: usize> Neg for Simd<i32, LANES> + impl<const N: usize> Neg for Simd<i32, N> - impl<const LANES: usize> Neg for Simd<i64, LANES> + impl<const N: usize> Neg for Simd<i64, N> - impl<const LANES: usize> Neg for Simd<isize, LANES> + impl<const N: usize> Neg for Simd<isize, N> } macro_rules! not { - ($(impl<const LANES: usize> Not for Simd<$scalar:ty, LANES>)*) => { - $(impl<const LANES: usize> Not for Simd<$scalar, LANES> + ($(impl<const N: usize> Not for Simd<$scalar:ty, N>)*) => { + $(impl<const N: usize> Not for Simd<$scalar, N> where $scalar: SimdElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Output = Self; @@ -56,23 +56,23 @@ macro_rules! not { } not! { - impl<const LANES: usize> Not for Simd<i8, LANES> + impl<const N: usize> Not for Simd<i8, N> - impl<const LANES: usize> Not for Simd<i16, LANES> + impl<const N: usize> Not for Simd<i16, N> - impl<const LANES: usize> Not for Simd<i32, LANES> + impl<const N: usize> Not for Simd<i32, N> - impl<const LANES: usize> Not for Simd<i64, LANES> + impl<const N: usize> Not for Simd<i64, N> - impl<const LANES: usize> Not for Simd<isize, LANES> + impl<const N: usize> Not for Simd<isize, N> - impl<const LANES: usize> Not for Simd<u8, LANES> + impl<const N: usize> Not for Simd<u8, N> - impl<const LANES: usize> Not for Simd<u16, LANES> + impl<const N: usize> Not for Simd<u16, N> - impl<const LANES: usize> Not for Simd<u32, LANES> + impl<const N: usize> Not for Simd<u32, N> - impl<const LANES: usize> Not for Simd<u64, LANES> + impl<const N: usize> Not for Simd<u64, N> - impl<const LANES: usize> Not for Simd<usize, LANES> + impl<const N: usize> Not for Simd<usize, N> } diff --git a/library/portable-simd/crates/core_simd/src/select.rs b/library/portable-simd/crates/core_simd/src/select.rs index 065c5987d3f..cdcf8eeec81 100644 --- a/library/portable-simd/crates/core_simd/src/select.rs +++ b/library/portable-simd/crates/core_simd/src/select.rs @@ -1,15 +1,15 @@ use crate::simd::intrinsics; use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount}; -impl<T, const LANES: usize> Mask<T, LANES> +impl<T, const N: usize> Mask<T, N> where T: MaskElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - /// Choose lanes from two vectors. + /// Choose elements from two vectors. /// - /// For each lane in the mask, choose the corresponding lane from `true_values` if - /// that lane mask is true, and `false_values` if that lane mask is false. + /// For each element in the mask, choose the corresponding element from `true_values` if + /// that element mask is true, and `false_values` if that element mask is false. /// /// # Examples /// ``` @@ -23,11 +23,7 @@ where /// ``` #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn select<U>( - self, - true_values: Simd<U, LANES>, - false_values: Simd<U, LANES>, - ) -> Simd<U, LANES> + pub fn select<U>(self, true_values: Simd<U, N>, false_values: Simd<U, N>) -> Simd<U, N> where U: SimdElement<Mask = T>, { @@ -36,10 +32,10 @@ where unsafe { intrinsics::simd_select(self.to_int(), true_values, false_values) } } - /// Choose lanes from two masks. + /// Choose elements from two masks. /// - /// For each lane in the mask, choose the corresponding lane from `true_values` if - /// that lane mask is true, and `false_values` if that lane mask is false. + /// For each element in the mask, choose the corresponding element from `true_values` if + /// that element mask is true, and `false_values` if that element mask is false. /// /// # Examples /// ``` diff --git a/library/portable-simd/crates/core_simd/src/simd/cmp.rs b/library/portable-simd/crates/core_simd/src/simd/cmp.rs new file mode 100644 index 00000000000..a8d81dbf20f --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/simd/cmp.rs @@ -0,0 +1,7 @@ +//! Traits for comparing and ordering vectors. + +mod eq; +mod ord; + +pub use eq::*; +pub use ord::*; diff --git a/library/portable-simd/crates/core_simd/src/eq.rs b/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs index 80763c07272..f132fa2cc0c 100644 --- a/library/portable-simd/crates/core_simd/src/eq.rs +++ b/library/portable-simd/crates/core_simd/src/simd/cmp/eq.rs @@ -1,5 +1,7 @@ use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdConstPtr, SimdElement, SimdMutPtr, SupportedLaneCount, + intrinsics, + ptr::{SimdConstPtr, SimdMutPtr}, + LaneCount, Mask, Simd, SimdElement, SupportedLaneCount, }; /// Parallel `PartialEq`. @@ -7,11 +9,11 @@ pub trait SimdPartialEq { /// The mask type returned by each comparison. type Mask; - /// Test if each lane is equal to the corresponding lane in `other`. + /// Test if each element is equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] fn simd_eq(self, other: Self) -> Self::Mask; - /// Test if each lane is equal to the corresponding lane in `other`. + /// Test if each element is equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] fn simd_ne(self, other: Self) -> Self::Mask; } @@ -19,11 +21,11 @@ pub trait SimdPartialEq { macro_rules! impl_number { { $($number:ty),* } => { $( - impl<const LANES: usize> SimdPartialEq for Simd<$number, LANES> + impl<const N: usize> SimdPartialEq for Simd<$number, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Mask = Mask<<$number as SimdElement>::Mask, LANES>; + type Mask = Mask<<$number as SimdElement>::Mask, N>; #[inline] fn simd_eq(self, other: Self) -> Self::Mask { @@ -48,9 +50,9 @@ impl_number! { f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } macro_rules! impl_mask { { $($integer:ty),* } => { $( - impl<const LANES: usize> SimdPartialEq for Mask<$integer, LANES> + impl<const N: usize> SimdPartialEq for Mask<$integer, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Mask = Self; @@ -74,11 +76,11 @@ macro_rules! impl_mask { impl_mask! { i8, i16, i32, i64, isize } -impl<T, const LANES: usize> SimdPartialEq for Simd<*const T, LANES> +impl<T, const N: usize> SimdPartialEq for Simd<*const T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Mask = Mask<isize, LANES>; + type Mask = Mask<isize, N>; #[inline] fn simd_eq(self, other: Self) -> Self::Mask { @@ -91,11 +93,11 @@ where } } -impl<T, const LANES: usize> SimdPartialEq for Simd<*mut T, LANES> +impl<T, const N: usize> SimdPartialEq for Simd<*mut T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Mask = Mask<isize, LANES>; + type Mask = Mask<isize, N>; #[inline] fn simd_eq(self, other: Self) -> Self::Mask { diff --git a/library/portable-simd/crates/core_simd/src/ord.rs b/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs index b2455190e82..4e9d49ea221 100644 --- a/library/portable-simd/crates/core_simd/src/ord.rs +++ b/library/portable-simd/crates/core_simd/src/simd/cmp/ord.rs @@ -1,44 +1,47 @@ use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdConstPtr, SimdMutPtr, SimdPartialEq, SupportedLaneCount, + cmp::SimdPartialEq, + intrinsics, + ptr::{SimdConstPtr, SimdMutPtr}, + LaneCount, Mask, Simd, SupportedLaneCount, }; /// Parallel `PartialOrd`. pub trait SimdPartialOrd: SimdPartialEq { - /// Test if each lane is less than the corresponding lane in `other`. + /// Test if each element is less than the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] fn simd_lt(self, other: Self) -> Self::Mask; - /// Test if each lane is less than or equal to the corresponding lane in `other`. + /// Test if each element is less than or equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] fn simd_le(self, other: Self) -> Self::Mask; - /// Test if each lane is greater than the corresponding lane in `other`. + /// Test if each element is greater than the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] fn simd_gt(self, other: Self) -> Self::Mask; - /// Test if each lane is greater than or equal to the corresponding lane in `other`. + /// Test if each element is greater than or equal to the corresponding element in `other`. #[must_use = "method returns a new mask and does not mutate the original value"] fn simd_ge(self, other: Self) -> Self::Mask; } /// Parallel `Ord`. pub trait SimdOrd: SimdPartialOrd { - /// Returns the lane-wise maximum with `other`. + /// Returns the element-wise maximum with `other`. #[must_use = "method returns a new vector and does not mutate the original value"] fn simd_max(self, other: Self) -> Self; - /// Returns the lane-wise minimum with `other`. + /// Returns the element-wise minimum with `other`. #[must_use = "method returns a new vector and does not mutate the original value"] fn simd_min(self, other: Self) -> Self; - /// Restrict each lane to a certain interval. + /// Restrict each element to a certain interval. /// - /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is + /// For each element, returns `max` if `self` is greater than `max`, and `min` if `self` is /// less than `min`. Otherwise returns `self`. /// /// # Panics /// - /// Panics if `min > max` on any lane. + /// Panics if `min > max` on any element. #[must_use = "method returns a new vector and does not mutate the original value"] fn simd_clamp(self, min: Self, max: Self) -> Self; } @@ -46,9 +49,9 @@ pub trait SimdOrd: SimdPartialOrd { macro_rules! impl_integer { { $($integer:ty),* } => { $( - impl<const LANES: usize> SimdPartialOrd for Simd<$integer, LANES> + impl<const N: usize> SimdPartialOrd for Simd<$integer, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { @@ -79,9 +82,9 @@ macro_rules! impl_integer { } } - impl<const LANES: usize> SimdOrd for Simd<$integer, LANES> + impl<const N: usize> SimdOrd for Simd<$integer, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_max(self, other: Self) -> Self { @@ -98,7 +101,7 @@ macro_rules! impl_integer { fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", + "each element in `min` must be less than or equal to the corresponding element in `max`", ); self.simd_max(min).simd_min(max) } @@ -112,9 +115,9 @@ impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize } macro_rules! impl_float { { $($float:ty),* } => { $( - impl<const LANES: usize> SimdPartialOrd for Simd<$float, LANES> + impl<const N: usize> SimdPartialOrd for Simd<$float, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { @@ -153,9 +156,9 @@ impl_float! { f32, f64 } macro_rules! impl_mask { { $($integer:ty),* } => { $( - impl<const LANES: usize> SimdPartialOrd for Mask<$integer, LANES> + impl<const N: usize> SimdPartialOrd for Mask<$integer, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { @@ -186,9 +189,9 @@ macro_rules! impl_mask { } } - impl<const LANES: usize> SimdOrd for Mask<$integer, LANES> + impl<const N: usize> SimdOrd for Mask<$integer, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_max(self, other: Self) -> Self { @@ -205,7 +208,7 @@ macro_rules! impl_mask { fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", + "each element in `min` must be less than or equal to the corresponding element in `max`", ); self.simd_max(min).simd_min(max) } @@ -216,9 +219,9 @@ macro_rules! impl_mask { impl_mask! { i8, i16, i32, i64, isize } -impl<T, const LANES: usize> SimdPartialOrd for Simd<*const T, LANES> +impl<T, const N: usize> SimdPartialOrd for Simd<*const T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { @@ -241,9 +244,9 @@ where } } -impl<T, const LANES: usize> SimdOrd for Simd<*const T, LANES> +impl<T, const N: usize> SimdOrd for Simd<*const T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_max(self, other: Self) -> Self { @@ -260,15 +263,15 @@ where fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", + "each element in `min` must be less than or equal to the corresponding element in `max`", ); self.simd_max(min).simd_min(max) } } -impl<T, const LANES: usize> SimdPartialOrd for Simd<*mut T, LANES> +impl<T, const N: usize> SimdPartialOrd for Simd<*mut T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_lt(self, other: Self) -> Self::Mask { @@ -291,9 +294,9 @@ where } } -impl<T, const LANES: usize> SimdOrd for Simd<*mut T, LANES> +impl<T, const N: usize> SimdOrd for Simd<*mut T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { #[inline] fn simd_max(self, other: Self) -> Self { @@ -310,7 +313,7 @@ where fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", + "each element in `min` must be less than or equal to the corresponding element in `max`", ); self.simd_max(min).simd_min(max) } diff --git a/library/portable-simd/crates/core_simd/src/elements.rs b/library/portable-simd/crates/core_simd/src/simd/num.rs index dc7f52a4d57..22a4802ec6c 100644 --- a/library/portable-simd/crates/core_simd/src/elements.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num.rs @@ -1,15 +1,13 @@ -mod const_ptr; +//! Traits for vectors with numeric elements. + mod float; mod int; -mod mut_ptr; mod uint; mod sealed { pub trait Sealed {} } -pub use const_ptr::*; pub use float::*; pub use int::*; -pub use mut_ptr::*; pub use uint::*; diff --git a/library/portable-simd/crates/core_simd/src/elements/float.rs b/library/portable-simd/crates/core_simd/src/simd/num/float.rs index 501c1c5ddd3..fc0b99e87a6 100644 --- a/library/portable-simd/crates/core_simd/src/elements/float.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/float.rs @@ -1,7 +1,7 @@ use super::sealed::Sealed; use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialEq, SimdPartialOrd, - SupportedLaneCount, + cmp::{SimdPartialEq, SimdPartialOrd}, + intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SupportedLaneCount, }; /// Operations on SIMD vectors of floats. @@ -28,7 +28,7 @@ pub trait SimdFloat: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{SimdFloat, SimdInt, Simd}; + /// # use simd::prelude::*; /// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]); /// let ints = floats.cast::<i32>(); /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0])); @@ -63,64 +63,64 @@ pub trait SimdFloat: Copy + Sealed { Self::Scalar: core::convert::FloatToInt<I>; /// Raw transmutation to an unsigned integer vector type with the - /// same size and number of lanes. + /// same size and number of elements. #[must_use = "method returns a new vector and does not mutate the original value"] fn to_bits(self) -> Self::Bits; /// Raw transmutation from an unsigned integer vector type with the - /// same size and number of lanes. + /// same size and number of elements. #[must_use = "method returns a new vector and does not mutate the original value"] fn from_bits(bits: Self::Bits) -> Self; - /// Produces a vector where every lane has the absolute value of the - /// equivalently-indexed lane in `self`. + /// Produces a vector where every element has the absolute value of the + /// equivalently-indexed element in `self`. #[must_use = "method returns a new vector and does not mutate the original value"] fn abs(self) -> Self; - /// Takes the reciprocal (inverse) of each lane, `1/x`. + /// Takes the reciprocal (inverse) of each element, `1/x`. #[must_use = "method returns a new vector and does not mutate the original value"] fn recip(self) -> Self; - /// Converts each lane from radians to degrees. + /// Converts each element from radians to degrees. #[must_use = "method returns a new vector and does not mutate the original value"] fn to_degrees(self) -> Self; - /// Converts each lane from degrees to radians. + /// Converts each element from degrees to radians. #[must_use = "method returns a new vector and does not mutate the original value"] fn to_radians(self) -> Self; - /// Returns true for each lane if it has a positive sign, including + /// Returns true for each element if it has a positive sign, including /// `+0.0`, `NaN`s with positive sign bit and positive infinity. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_sign_positive(self) -> Self::Mask; - /// Returns true for each lane if it has a negative sign, including + /// Returns true for each element if it has a negative sign, including /// `-0.0`, `NaN`s with negative sign bit and negative infinity. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_sign_negative(self) -> Self::Mask; - /// Returns true for each lane if its value is `NaN`. + /// Returns true for each element if its value is `NaN`. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_nan(self) -> Self::Mask; - /// Returns true for each lane if its value is positive infinity or negative infinity. + /// Returns true for each element if its value is positive infinity or negative infinity. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_infinite(self) -> Self::Mask; - /// Returns true for each lane if its value is neither infinite nor `NaN`. + /// Returns true for each element if its value is neither infinite nor `NaN`. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_finite(self) -> Self::Mask; - /// Returns true for each lane if its value is subnormal. + /// Returns true for each element if its value is subnormal. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_subnormal(self) -> Self::Mask; - /// Returns true for each lane if its value is neither zero, infinite, + /// Returns true for each element if its value is neither zero, infinite, /// subnormal, nor `NaN`. #[must_use = "method returns a new mask and does not mutate the original value"] fn is_normal(self) -> Self::Mask; - /// Replaces each lane with a number that represents its sign. + /// Replaces each element with a number that represents its sign. /// /// * `1.0` if the number is positive, `+0.0`, or `INFINITY` /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY` @@ -128,33 +128,33 @@ pub trait SimdFloat: Copy + Sealed { #[must_use = "method returns a new vector and does not mutate the original value"] fn signum(self) -> Self; - /// Returns each lane with the magnitude of `self` and the sign of `sign`. + /// Returns each element with the magnitude of `self` and the sign of `sign`. /// - /// For any lane containing a `NAN`, a `NAN` with the sign of `sign` is returned. + /// For any element containing a `NAN`, a `NAN` with the sign of `sign` is returned. #[must_use = "method returns a new vector and does not mutate the original value"] fn copysign(self, sign: Self) -> Self; - /// Returns the minimum of each lane. + /// Returns the minimum of each element. /// /// If one of the values is `NAN`, then the other value is returned. #[must_use = "method returns a new vector and does not mutate the original value"] fn simd_min(self, other: Self) -> Self; - /// Returns the maximum of each lane. + /// Returns the maximum of each element. /// /// If one of the values is `NAN`, then the other value is returned. #[must_use = "method returns a new vector and does not mutate the original value"] fn simd_max(self, other: Self) -> Self; - /// Restrict each lane to a certain interval unless it is NaN. + /// Restrict each element to a certain interval unless it is NaN. /// - /// For each lane in `self`, returns the corresponding lane in `max` if the lane is - /// greater than `max`, and the corresponding lane in `min` if the lane is less - /// than `min`. Otherwise returns the lane in `self`. + /// For each element in `self`, returns the corresponding element in `max` if the element is + /// greater than `max`, and the corresponding element in `min` if the element is less + /// than `min`. Otherwise returns the element in `self`. #[must_use = "method returns a new vector and does not mutate the original value"] fn simd_clamp(self, min: Self, max: Self) -> Self; - /// Returns the sum of the lanes of the vector. + /// Returns the sum of the elements of the vector. /// /// # Examples /// @@ -162,13 +162,13 @@ pub trait SimdFloat: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; + /// # use simd::prelude::*; /// let v = f32x2::from_array([1., 2.]); /// assert_eq!(v.reduce_sum(), 3.); /// ``` fn reduce_sum(self) -> Self::Scalar; - /// Reducing multiply. Returns the product of the lanes of the vector. + /// Reducing multiply. Returns the product of the elements of the vector. /// /// # Examples /// @@ -176,18 +176,18 @@ pub trait SimdFloat: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; + /// # use simd::prelude::*; /// let v = f32x2::from_array([3., 4.]); /// assert_eq!(v.reduce_product(), 12.); /// ``` fn reduce_product(self) -> Self::Scalar; - /// Returns the maximum lane in the vector. + /// Returns the maximum element in the vector. /// /// Returns values based on equality, so a vector containing both `0.` and `-0.` may /// return either. /// - /// This function will not return `NaN` unless all lanes are `NaN`. + /// This function will not return `NaN` unless all elements are `NaN`. /// /// # Examples /// @@ -195,7 +195,7 @@ pub trait SimdFloat: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; + /// # use simd::prelude::*; /// let v = f32x2::from_array([1., 2.]); /// assert_eq!(v.reduce_max(), 2.); /// @@ -209,12 +209,12 @@ pub trait SimdFloat: Copy + Sealed { /// ``` fn reduce_max(self) -> Self::Scalar; - /// Returns the minimum lane in the vector. + /// Returns the minimum element in the vector. /// /// Returns values based on equality, so a vector containing both `0.` and `-0.` may /// return either. /// - /// This function will not return `NaN` unless all lanes are `NaN`. + /// This function will not return `NaN` unless all elements are `NaN`. /// /// # Examples /// @@ -222,7 +222,7 @@ pub trait SimdFloat: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{f32x2, SimdFloat}; + /// # use simd::prelude::*; /// let v = f32x2::from_array([3., 7.]); /// assert_eq!(v.reduce_min(), 3.); /// @@ -240,20 +240,20 @@ pub trait SimdFloat: Copy + Sealed { macro_rules! impl_trait { { $($ty:ty { bits: $bits_ty:ty, mask: $mask_ty:ty }),* } => { $( - impl<const LANES: usize> Sealed for Simd<$ty, LANES> + impl<const N: usize> Sealed for Simd<$ty, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } - impl<const LANES: usize> SimdFloat for Simd<$ty, LANES> + impl<const N: usize> SimdFloat for Simd<$ty, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Mask = Mask<<$mask_ty as SimdElement>::Mask, LANES>; + type Mask = Mask<<$mask_ty as SimdElement>::Mask, N>; type Scalar = $ty; - type Bits = Simd<$bits_ty, LANES>; - type Cast<T: SimdElement> = Simd<T, LANES>; + type Bits = Simd<$bits_ty, N>; + type Cast<T: SimdElement> = Simd<T, N>; #[inline] fn cast<T: SimdCast>(self) -> Self::Cast<T> @@ -273,14 +273,14 @@ macro_rules! impl_trait { } #[inline] - fn to_bits(self) -> Simd<$bits_ty, LANES> { + fn to_bits(self) -> Simd<$bits_ty, N> { assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Self::Bits>()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&self) } } #[inline] - fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self { + fn from_bits(bits: Simd<$bits_ty, N>) -> Self { assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Self::Bits>()); // Safety: transmuting between vector types is safe unsafe { core::mem::transmute_copy(&bits) } @@ -336,7 +336,10 @@ macro_rules! impl_trait { #[inline] fn is_subnormal(self) -> Self::Mask { - self.abs().simd_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0)) + // On some architectures (e.g. armv7 and some ppc) subnormals are flushed to zero, + // so this comparison must be done with integers. + let not_zero = self.abs().to_bits().simd_ne(Self::splat(0.0).to_bits()); + not_zero & (self.to_bits() & Self::splat(Self::Scalar::INFINITY).to_bits()).simd_eq(Simd::splat(0)) } #[inline] @@ -373,7 +376,7 @@ macro_rules! impl_trait { fn simd_clamp(self, min: Self, max: Self) -> Self { assert!( min.simd_le(max).all(), - "each lane in `min` must be less than or equal to the corresponding lane in `max`", + "each element in `min` must be less than or equal to the corresponding element in `max`", ); let mut x = self; x = x.simd_lt(min).select(min, x); diff --git a/library/portable-simd/crates/core_simd/src/elements/int.rs b/library/portable-simd/crates/core_simd/src/simd/num/int.rs index 6db89ff9a65..1f1aa272782 100644 --- a/library/portable-simd/crates/core_simd/src/elements/int.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/int.rs @@ -1,6 +1,7 @@ use super::sealed::Sealed; use crate::simd::{ - intrinsics, LaneCount, Mask, Simd, SimdCast, SimdElement, SimdPartialOrd, SupportedLaneCount, + cmp::SimdPartialOrd, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement, + SupportedLaneCount, }; /// Operations on SIMD vectors of signed integers. @@ -11,6 +12,9 @@ pub trait SimdInt: Copy + Sealed { /// Scalar type contained by this SIMD vector type. type Scalar; + /// A SIMD vector of unsigned integers with the same element size. + type Unsigned; + /// A SIMD vector with a different element type. type Cast<T: SimdElement>; @@ -28,7 +32,7 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; + /// # use simd::prelude::*; /// use core::i32::{MIN, MAX}; /// let x = Simd::from_array([MIN, 0, 1, MAX]); /// let max = Simd::splat(MAX); @@ -46,7 +50,7 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; + /// # use simd::prelude::*; /// use core::i32::{MIN, MAX}; /// let x = Simd::from_array([MIN, -2, -1, MAX]); /// let max = Simd::splat(MAX); @@ -57,14 +61,14 @@ pub trait SimdInt: Copy + Sealed { fn saturating_sub(self, second: Self) -> Self; /// Lanewise absolute value, implemented in Rust. - /// Every lane becomes its absolute value. + /// Every element becomes its absolute value. /// /// # Examples /// ``` /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; + /// # use simd::prelude::*; /// use core::i32::{MIN, MAX}; /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]); /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0])); @@ -79,7 +83,7 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; + /// # use simd::prelude::*; /// use core::i32::{MIN, MAX}; /// let xs = Simd::from_array([MIN, -2, 0, 3]); /// let unsat = xs.abs(); @@ -97,7 +101,7 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdInt}; + /// # use simd::prelude::*; /// use core::i32::{MIN, MAX}; /// let x = Simd::from_array([MIN, -2, 3, MAX]); /// let unsat = -x; @@ -107,19 +111,19 @@ pub trait SimdInt: Copy + Sealed { /// ``` fn saturating_neg(self) -> Self; - /// Returns true for each positive lane and false if it is zero or negative. + /// Returns true for each positive element and false if it is zero or negative. fn is_positive(self) -> Self::Mask; - /// Returns true for each negative lane and false if it is zero or positive. + /// Returns true for each negative element and false if it is zero or positive. fn is_negative(self) -> Self::Mask; - /// Returns numbers representing the sign of each lane. + /// Returns numbers representing the sign of each element. /// * `0` if the number is zero /// * `1` if the number is positive /// * `-1` if the number is negative fn signum(self) -> Self; - /// Returns the sum of the lanes of the vector, with wrapping addition. + /// Returns the sum of the elements of the vector, with wrapping addition. /// /// # Examples /// @@ -127,7 +131,7 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; + /// # use simd::prelude::*; /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_sum(), 10); /// @@ -137,7 +141,7 @@ pub trait SimdInt: Copy + Sealed { /// ``` fn reduce_sum(self) -> Self::Scalar; - /// Returns the product of the lanes of the vector, with wrapping multiplication. + /// Returns the product of the elements of the vector, with wrapping multiplication. /// /// # Examples /// @@ -145,7 +149,7 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; + /// # use simd::prelude::*; /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_product(), 24); /// @@ -155,7 +159,7 @@ pub trait SimdInt: Copy + Sealed { /// ``` fn reduce_product(self) -> Self::Scalar; - /// Returns the maximum lane in the vector. + /// Returns the maximum element in the vector. /// /// # Examples /// @@ -163,13 +167,13 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; + /// # use simd::prelude::*; /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_max(), 4); /// ``` fn reduce_max(self) -> Self::Scalar; - /// Returns the minimum lane in the vector. + /// Returns the minimum element in the vector. /// /// # Examples /// @@ -177,38 +181,58 @@ pub trait SimdInt: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{i32x4, SimdInt}; + /// # use simd::prelude::*; /// let v = i32x4::from_array([1, 2, 3, 4]); /// assert_eq!(v.reduce_min(), 1); /// ``` fn reduce_min(self) -> Self::Scalar; - /// Returns the cumulative bitwise "and" across the lanes of the vector. + /// Returns the cumulative bitwise "and" across the elements of the vector. fn reduce_and(self) -> Self::Scalar; - /// Returns the cumulative bitwise "or" across the lanes of the vector. + /// Returns the cumulative bitwise "or" across the elements of the vector. fn reduce_or(self) -> Self::Scalar; - /// Returns the cumulative bitwise "xor" across the lanes of the vector. + /// Returns the cumulative bitwise "xor" across the elements of the vector. fn reduce_xor(self) -> Self::Scalar; + + /// Reverses the byte order of each element. + fn swap_bytes(self) -> Self; + + /// Reverses the order of bits in each elemnent. + /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc. + fn reverse_bits(self) -> Self; + + /// Returns the number of leading zeros in the binary representation of each element. + fn leading_zeros(self) -> Self::Unsigned; + + /// Returns the number of trailing zeros in the binary representation of each element. + fn trailing_zeros(self) -> Self::Unsigned; + + /// Returns the number of leading ones in the binary representation of each element. + fn leading_ones(self) -> Self::Unsigned; + + /// Returns the number of trailing ones in the binary representation of each element. + fn trailing_ones(self) -> Self::Unsigned; } macro_rules! impl_trait { - { $($ty:ty),* } => { + { $($ty:ident ($unsigned:ident)),* } => { $( - impl<const LANES: usize> Sealed for Simd<$ty, LANES> + impl<const N: usize> Sealed for Simd<$ty, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } - impl<const LANES: usize> SimdInt for Simd<$ty, LANES> + impl<const N: usize> SimdInt for Simd<$ty, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Mask = Mask<<$ty as SimdElement>::Mask, LANES>; + type Mask = Mask<<$ty as SimdElement>::Mask, N>; type Scalar = $ty; - type Cast<T: SimdElement> = Simd<T, LANES>; + type Unsigned = Simd<$unsigned, N>; + type Cast<T: SimdElement> = Simd<T, N>; #[inline] fn cast<T: SimdCast>(self) -> Self::Cast<T> { @@ -307,9 +331,41 @@ macro_rules! impl_trait { // Safety: `self` is an integer vector unsafe { intrinsics::simd_reduce_xor(self) } } + + #[inline] + fn swap_bytes(self) -> Self { + // Safety: `self` is an integer vector + unsafe { intrinsics::simd_bswap(self) } + } + + #[inline] + fn reverse_bits(self) -> Self { + // Safety: `self` is an integer vector + unsafe { intrinsics::simd_bitreverse(self) } + } + + #[inline] + fn leading_zeros(self) -> Self::Unsigned { + self.cast::<$unsigned>().leading_zeros() + } + + #[inline] + fn trailing_zeros(self) -> Self::Unsigned { + self.cast::<$unsigned>().trailing_zeros() + } + + #[inline] + fn leading_ones(self) -> Self::Unsigned { + self.cast::<$unsigned>().leading_ones() + } + + #[inline] + fn trailing_ones(self) -> Self::Unsigned { + self.cast::<$unsigned>().trailing_ones() + } } )* } } -impl_trait! { i8, i16, i32, i64, isize } +impl_trait! { i8 (u8), i16 (u16), i32 (u32), i64 (u64), isize (usize) } diff --git a/library/portable-simd/crates/core_simd/src/elements/uint.rs b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs index 3926c395ec9..c955ee8fe8b 100644 --- a/library/portable-simd/crates/core_simd/src/elements/uint.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs @@ -16,6 +16,12 @@ pub trait SimdUint: Copy + Sealed { #[must_use] fn cast<T: SimdCast>(self) -> Self::Cast<T>; + /// Wrapping negation. + /// + /// Like [`u32::wrapping_neg`], all applications of this function will wrap, with the exception + /// of `-0`. + fn wrapping_neg(self) -> Self; + /// Lanewise saturating add. /// /// # Examples @@ -23,7 +29,7 @@ pub trait SimdUint: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdUint}; + /// # use simd::prelude::*; /// use core::u32::MAX; /// let x = Simd::from_array([2, 1, 0, MAX]); /// let max = Simd::splat(MAX); @@ -41,7 +47,7 @@ pub trait SimdUint: Copy + Sealed { /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdUint}; + /// # use simd::prelude::*; /// use core::u32::MAX; /// let x = Simd::from_array([2, 1, 0, MAX]); /// let max = Simd::splat(MAX); @@ -51,43 +57,62 @@ pub trait SimdUint: Copy + Sealed { /// assert_eq!(sat, Simd::splat(0)); fn saturating_sub(self, second: Self) -> Self; - /// Returns the sum of the lanes of the vector, with wrapping addition. + /// Returns the sum of the elements of the vector, with wrapping addition. fn reduce_sum(self) -> Self::Scalar; - /// Returns the product of the lanes of the vector, with wrapping multiplication. + /// Returns the product of the elements of the vector, with wrapping multiplication. fn reduce_product(self) -> Self::Scalar; - /// Returns the maximum lane in the vector. + /// Returns the maximum element in the vector. fn reduce_max(self) -> Self::Scalar; - /// Returns the minimum lane in the vector. + /// Returns the minimum element in the vector. fn reduce_min(self) -> Self::Scalar; - /// Returns the cumulative bitwise "and" across the lanes of the vector. + /// Returns the cumulative bitwise "and" across the elements of the vector. fn reduce_and(self) -> Self::Scalar; - /// Returns the cumulative bitwise "or" across the lanes of the vector. + /// Returns the cumulative bitwise "or" across the elements of the vector. fn reduce_or(self) -> Self::Scalar; - /// Returns the cumulative bitwise "xor" across the lanes of the vector. + /// Returns the cumulative bitwise "xor" across the elements of the vector. fn reduce_xor(self) -> Self::Scalar; + + /// Reverses the byte order of each element. + fn swap_bytes(self) -> Self; + + /// Reverses the order of bits in each elemnent. + /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc. + fn reverse_bits(self) -> Self; + + /// Returns the number of leading zeros in the binary representation of each element. + fn leading_zeros(self) -> Self; + + /// Returns the number of trailing zeros in the binary representation of each element. + fn trailing_zeros(self) -> Self; + + /// Returns the number of leading ones in the binary representation of each element. + fn leading_ones(self) -> Self; + + /// Returns the number of trailing ones in the binary representation of each element. + fn trailing_ones(self) -> Self; } macro_rules! impl_trait { - { $($ty:ty),* } => { + { $($ty:ident ($signed:ident)),* } => { $( - impl<const LANES: usize> Sealed for Simd<$ty, LANES> + impl<const N: usize> Sealed for Simd<$ty, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { } - impl<const LANES: usize> SimdUint for Simd<$ty, LANES> + impl<const N: usize> SimdUint for Simd<$ty, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { type Scalar = $ty; - type Cast<T: SimdElement> = Simd<T, LANES>; + type Cast<T: SimdElement> = Simd<T, N>; #[inline] fn cast<T: SimdCast>(self) -> Self::Cast<T> { @@ -96,6 +121,12 @@ macro_rules! impl_trait { } #[inline] + fn wrapping_neg(self) -> Self { + use crate::simd::num::SimdInt; + (-self.cast::<$signed>()).cast() + } + + #[inline] fn saturating_add(self, second: Self) -> Self { // Safety: `self` is a vector unsafe { intrinsics::simd_saturating_add(self, second) } @@ -148,9 +179,43 @@ macro_rules! impl_trait { // Safety: `self` is an integer vector unsafe { intrinsics::simd_reduce_xor(self) } } + + #[inline] + fn swap_bytes(self) -> Self { + // Safety: `self` is an integer vector + unsafe { intrinsics::simd_bswap(self) } + } + + #[inline] + fn reverse_bits(self) -> Self { + // Safety: `self` is an integer vector + unsafe { intrinsics::simd_bitreverse(self) } + } + + #[inline] + fn leading_zeros(self) -> Self { + // Safety: `self` is an integer vector + unsafe { intrinsics::simd_ctlz(self) } + } + + #[inline] + fn trailing_zeros(self) -> Self { + // Safety: `self` is an integer vector + unsafe { intrinsics::simd_cttz(self) } + } + + #[inline] + fn leading_ones(self) -> Self { + (!self).leading_zeros() + } + + #[inline] + fn trailing_ones(self) -> Self { + (!self).trailing_zeros() + } } )* } } -impl_trait! { u8, u16, u32, u64, usize } +impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) } diff --git a/library/portable-simd/crates/core_simd/src/simd/prelude.rs b/library/portable-simd/crates/core_simd/src/simd/prelude.rs index e8fdc932d49..4b7c744c013 100644 --- a/library/portable-simd/crates/core_simd/src/simd/prelude.rs +++ b/library/portable-simd/crates/core_simd/src/simd/prelude.rs @@ -7,8 +7,10 @@ #[doc(no_inline)] pub use super::{ - simd_swizzle, Mask, Simd, SimdConstPtr, SimdFloat, SimdInt, SimdMutPtr, SimdOrd, SimdPartialEq, - SimdPartialOrd, SimdUint, + cmp::{SimdOrd, SimdPartialEq, SimdPartialOrd}, + num::{SimdFloat, SimdInt, SimdUint}, + ptr::{SimdConstPtr, SimdMutPtr}, + simd_swizzle, Mask, Simd, }; #[rustfmt::skip] diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr.rs new file mode 100644 index 00000000000..3f8e6669118 --- /dev/null +++ b/library/portable-simd/crates/core_simd/src/simd/ptr.rs @@ -0,0 +1,11 @@ +//! Traits for vectors of pointers. + +mod const_ptr; +mod mut_ptr; + +mod sealed { + pub trait Sealed {} +} + +pub use const_ptr::*; +pub use mut_ptr::*; diff --git a/library/portable-simd/crates/core_simd/src/elements/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index f215f9a61d0..97fe3fb600d 100644 --- a/library/portable-simd/crates/core_simd/src/elements/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -1,15 +1,17 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount}; +use crate::simd::{ + cmp::SimdPartialEq, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount, +}; /// Operations on SIMD vectors of constant pointers. pub trait SimdConstPtr: Copy + Sealed { - /// Vector of `usize` with the same number of lanes. + /// Vector of `usize` with the same number of elements. type Usize; - /// Vector of `isize` with the same number of lanes. + /// Vector of `isize` with the same number of elements. type Isize; - /// Vector of const pointers with the same number of lanes. + /// Vector of const pointers with the same number of elements. type CastPtr<T>; /// Vector of mutable pointers to the same type. @@ -18,17 +20,17 @@ pub trait SimdConstPtr: Copy + Sealed { /// Mask type used for manipulating this SIMD vector type. type Mask; - /// Returns `true` for each lane that is null. + /// Returns `true` for each element that is null. fn is_null(self) -> Self::Mask; /// Casts to a pointer of another type. /// - /// Equivalent to calling [`pointer::cast`] on each lane. + /// Equivalent to calling [`pointer::cast`] on each element. fn cast<T>(self) -> Self::CastPtr<T>; /// Changes constness without changing the type. /// - /// Equivalent to calling [`pointer::cast_mut`] on each lane. + /// Equivalent to calling [`pointer::cast_mut`] on each element. fn cast_mut(self) -> Self::MutPtr; /// Gets the "address" portion of the pointer. @@ -39,7 +41,7 @@ pub trait SimdConstPtr: Copy + Sealed { /// This method semantically discards *provenance* and /// *address-space* information. To properly restore that information, use [`Self::with_addr`]. /// - /// Equivalent to calling [`pointer::addr`] on each lane. + /// Equivalent to calling [`pointer::addr`] on each element. fn addr(self) -> Self::Usize; /// Creates a new pointer with the given address. @@ -47,7 +49,7 @@ pub trait SimdConstPtr: Copy + Sealed { /// This performs the same operation as a cast, but copies the *address-space* and /// *provenance* of `self` to the new pointer. /// - /// Equivalent to calling [`pointer::with_addr`] on each lane. + /// Equivalent to calling [`pointer::with_addr`] on each element. fn with_addr(self, addr: Self::Usize) -> Self; /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use @@ -56,39 +58,36 @@ pub trait SimdConstPtr: Copy + Sealed { /// Convert an address back to a pointer, picking up a previously "exposed" provenance. /// - /// Equivalent to calling [`core::ptr::from_exposed_addr`] on each lane. + /// Equivalent to calling [`core::ptr::from_exposed_addr`] on each element. fn from_exposed_addr(addr: Self::Usize) -> Self; /// Calculates the offset from a pointer using wrapping arithmetic. /// - /// Equivalent to calling [`pointer::wrapping_offset`] on each lane. + /// Equivalent to calling [`pointer::wrapping_offset`] on each element. fn wrapping_offset(self, offset: Self::Isize) -> Self; /// Calculates the offset from a pointer using wrapping arithmetic. /// - /// Equivalent to calling [`pointer::wrapping_add`] on each lane. + /// Equivalent to calling [`pointer::wrapping_add`] on each element. fn wrapping_add(self, count: Self::Usize) -> Self; /// Calculates the offset from a pointer using wrapping arithmetic. /// - /// Equivalent to calling [`pointer::wrapping_sub`] on each lane. + /// Equivalent to calling [`pointer::wrapping_sub`] on each element. fn wrapping_sub(self, count: Self::Usize) -> Self; } -impl<T, const LANES: usize> Sealed for Simd<*const T, LANES> where - LaneCount<LANES>: SupportedLaneCount -{ -} +impl<T, const N: usize> Sealed for Simd<*const T, N> where LaneCount<N>: SupportedLaneCount {} -impl<T, const LANES: usize> SimdConstPtr for Simd<*const T, LANES> +impl<T, const N: usize> SimdConstPtr for Simd<*const T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Usize = Simd<usize, LANES>; - type Isize = Simd<isize, LANES>; - type CastPtr<U> = Simd<*const U, LANES>; - type MutPtr = Simd<*mut T, LANES>; - type Mask = Mask<isize, LANES>; + type Usize = Simd<usize, N>; + type Isize = Simd<isize, N>; + type CastPtr<U> = Simd<*const U, N>; + type MutPtr = Simd<*mut T, N>; + type Mask = Mask<isize, N>; #[inline] fn is_null(self) -> Self::Mask { diff --git a/library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index 4bdc6a14ce4..e35633d0433 100644 --- a/library/portable-simd/crates/core_simd/src/elements/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -1,15 +1,17 @@ use super::sealed::Sealed; -use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SimdUint, SupportedLaneCount}; +use crate::simd::{ + cmp::SimdPartialEq, intrinsics, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount, +}; /// Operations on SIMD vectors of mutable pointers. pub trait SimdMutPtr: Copy + Sealed { - /// Vector of `usize` with the same number of lanes. + /// Vector of `usize` with the same number of elements. type Usize; - /// Vector of `isize` with the same number of lanes. + /// Vector of `isize` with the same number of elements. type Isize; - /// Vector of const pointers with the same number of lanes. + /// Vector of const pointers with the same number of elements. type CastPtr<T>; /// Vector of constant pointers to the same type. @@ -18,17 +20,17 @@ pub trait SimdMutPtr: Copy + Sealed { /// Mask type used for manipulating this SIMD vector type. type Mask; - /// Returns `true` for each lane that is null. + /// Returns `true` for each element that is null. fn is_null(self) -> Self::Mask; /// Casts to a pointer of another type. /// - /// Equivalent to calling [`pointer::cast`] on each lane. + /// Equivalent to calling [`pointer::cast`] on each element. fn cast<T>(self) -> Self::CastPtr<T>; /// Changes constness without changing the type. /// - /// Equivalent to calling [`pointer::cast_const`] on each lane. + /// Equivalent to calling [`pointer::cast_const`] on each element. fn cast_const(self) -> Self::ConstPtr; /// Gets the "address" portion of the pointer. @@ -36,7 +38,7 @@ pub trait SimdMutPtr: Copy + Sealed { /// This method discards pointer semantic metadata, so the result cannot be /// directly cast into a valid pointer. /// - /// Equivalent to calling [`pointer::addr`] on each lane. + /// Equivalent to calling [`pointer::addr`] on each element. fn addr(self) -> Self::Usize; /// Creates a new pointer with the given address. @@ -44,7 +46,7 @@ pub trait SimdMutPtr: Copy + Sealed { /// This performs the same operation as a cast, but copies the *address-space* and /// *provenance* of `self` to the new pointer. /// - /// Equivalent to calling [`pointer::with_addr`] on each lane. + /// Equivalent to calling [`pointer::with_addr`] on each element. fn with_addr(self, addr: Self::Usize) -> Self; /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use @@ -53,37 +55,36 @@ pub trait SimdMutPtr: Copy + Sealed { /// Convert an address back to a pointer, picking up a previously "exposed" provenance. /// - /// Equivalent to calling [`core::ptr::from_exposed_addr_mut`] on each lane. + /// Equivalent to calling [`core::ptr::from_exposed_addr_mut`] on each element. fn from_exposed_addr(addr: Self::Usize) -> Self; /// Calculates the offset from a pointer using wrapping arithmetic. /// - /// Equivalent to calling [`pointer::wrapping_offset`] on each lane. + /// Equivalent to calling [`pointer::wrapping_offset`] on each element. fn wrapping_offset(self, offset: Self::Isize) -> Self; /// Calculates the offset from a pointer using wrapping arithmetic. /// - /// Equivalent to calling [`pointer::wrapping_add`] on each lane. + /// Equivalent to calling [`pointer::wrapping_add`] on each element. fn wrapping_add(self, count: Self::Usize) -> Self; /// Calculates the offset from a pointer using wrapping arithmetic. /// - /// Equivalent to calling [`pointer::wrapping_sub`] on each lane. + /// Equivalent to calling [`pointer::wrapping_sub`] on each element. fn wrapping_sub(self, count: Self::Usize) -> Self; } -impl<T, const LANES: usize> Sealed for Simd<*mut T, LANES> where LaneCount<LANES>: SupportedLaneCount -{} +impl<T, const N: usize> Sealed for Simd<*mut T, N> where LaneCount<N>: SupportedLaneCount {} -impl<T, const LANES: usize> SimdMutPtr for Simd<*mut T, LANES> +impl<T, const N: usize> SimdMutPtr for Simd<*mut T, N> where - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - type Usize = Simd<usize, LANES>; - type Isize = Simd<isize, LANES>; - type CastPtr<U> = Simd<*mut U, LANES>; - type ConstPtr = Simd<*const T, LANES>; - type Mask = Mask<isize, LANES>; + type Usize = Simd<usize, N>; + type Isize = Simd<isize, N>; + type CastPtr<U> = Simd<*mut U, N>; + type ConstPtr = Simd<*const T, N>; + type Mask = Mask<isize, N>; #[inline] fn is_null(self) -> Self::Mask { diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs index 68f20516cf5..ec8548d5574 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle.rs @@ -1,17 +1,15 @@ use crate::simd::intrinsics; -use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; +use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount}; -/// Constructs a new SIMD vector by copying elements from selected lanes in other vectors. +/// Constructs a new SIMD vector by copying elements from selected elements in other vectors. /// -/// When swizzling one vector, lanes are selected by a `const` array of `usize`, -/// like [`Swizzle`]. +/// When swizzling one vector, elements are selected like [`Swizzle::swizzle`]. /// -/// When swizzling two vectors, lanes are selected by a `const` array of [`Which`], -/// like [`Swizzle2`]. +/// When swizzling two vectors, elements are selected like [`Swizzle::concat_swizzle`]. /// /// # Examples /// -/// With a single SIMD vector, the const array specifies lane indices in that vector: +/// With a single SIMD vector, the const array specifies element indices in that vector: /// ``` /// # #![feature(portable_simd)] /// # use core::simd::{u32x2, u32x4, simd_swizzle}; @@ -21,25 +19,27 @@ use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; /// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]); /// assert_eq!(r.to_array(), [13, 10, 11, 12]); /// -/// // Changing the number of lanes +/// // Changing the number of elements /// let r: u32x2 = simd_swizzle!(v, [3, 1]); /// assert_eq!(r.to_array(), [13, 11]); /// ``` /// -/// With two input SIMD vectors, the const array uses `Which` to specify the source of each index: +/// With two input SIMD vectors, the const array specifies element indices in the concatenation of +/// those vectors: /// ``` /// # #![feature(portable_simd)] -/// # use core::simd::{u32x2, u32x4, simd_swizzle, Which}; -/// use Which::{First, Second}; +/// # #[cfg(feature = "as_crate")] use core_simd::simd; +/// # #[cfg(not(feature = "as_crate"))] use core::simd; +/// # use simd::{u32x2, u32x4, simd_swizzle}; /// let a = u32x4::from_array([0, 1, 2, 3]); /// let b = u32x4::from_array([4, 5, 6, 7]); /// /// // Keeping the same size -/// let r: u32x4 = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]); +/// let r: u32x4 = simd_swizzle!(a, b, [0, 1, 6, 7]); /// assert_eq!(r.to_array(), [0, 1, 6, 7]); /// -/// // Changing the number of lanes -/// let r: u32x2 = simd_swizzle!(a, b, [First(0), Second(0)]); +/// // Changing the number of elements +/// let r: u32x2 = simd_swizzle!(a, b, [0, 4]); /// assert_eq!(r.to_array(), [0, 4]); /// ``` #[allow(unused_macros)] @@ -50,7 +50,7 @@ pub macro simd_swizzle { { use $crate::simd::Swizzle; struct Impl; - impl<const LANES: usize> Swizzle<LANES, {$index.len()}> for Impl { + impl Swizzle<{$index.len()}> for Impl { const INDEX: [usize; {$index.len()}] = $index; } Impl::swizzle($vector) @@ -60,204 +60,194 @@ pub macro simd_swizzle { $first:expr, $second:expr, $index:expr $(,)? ) => { { - use $crate::simd::{Which, Swizzle2}; + use $crate::simd::Swizzle; struct Impl; - impl<const LANES: usize> Swizzle2<LANES, {$index.len()}> for Impl { - const INDEX: [Which; {$index.len()}] = $index; + impl Swizzle<{$index.len()}> for Impl { + const INDEX: [usize; {$index.len()}] = $index; } - Impl::swizzle2($first, $second) + Impl::concat_swizzle($first, $second) } } } -/// Specifies a lane index into one of two SIMD vectors. -/// -/// This is an input type for [Swizzle2] and helper macros like [simd_swizzle]. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Which { - /// Index of a lane in the first input SIMD vector. - First(usize), - /// Index of a lane in the second input SIMD vector. - Second(usize), -} - /// Create a vector from the elements of another vector. -pub trait Swizzle<const INPUT_LANES: usize, const OUTPUT_LANES: usize> { - /// Map from the lanes of the input vector to the output vector. - const INDEX: [usize; OUTPUT_LANES]; +pub trait Swizzle<const N: usize> { + /// Map from the elements of the input vector to the output vector. + const INDEX: [usize; N]; - /// Create a new vector from the lanes of `vector`. + /// Create a new vector from the elements of `vector`. /// /// Lane `i` of the output is `vector[Self::INDEX[i]]`. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES> + fn swizzle<T, const M: usize>(vector: Simd<T, M>) -> Simd<T, N> where T: SimdElement, - LaneCount<INPUT_LANES>: SupportedLaneCount, - LaneCount<OUTPUT_LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, + LaneCount<M>: SupportedLaneCount, { - // Safety: `vector` is a vector, and `INDEX_IMPL` is a const array of u32. - unsafe { intrinsics::simd_shuffle(vector, vector, Self::INDEX_IMPL) } + // Safety: `vector` is a vector, and the index is a const array of u32. + unsafe { + intrinsics::simd_shuffle( + vector, + vector, + const { + let mut output = [0; N]; + let mut i = 0; + while i < N { + let index = Self::INDEX[i]; + assert!(index as u32 as usize == index); + assert!( + index < M, + "source element index exceeds input vector length" + ); + output[i] = index as u32; + i += 1; + } + output + }, + ) + } } -} - -/// Create a vector from the elements of two other vectors. -pub trait Swizzle2<const INPUT_LANES: usize, const OUTPUT_LANES: usize> { - /// Map from the lanes of the input vectors to the output vector - const INDEX: [Which; OUTPUT_LANES]; - /// Create a new vector from the lanes of `first` and `second`. + /// Create a new vector from the elements of `first` and `second`. /// - /// Lane `i` is `first[j]` when `Self::INDEX[i]` is `First(j)`, or `second[j]` when it is - /// `Second(j)`. + /// Lane `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of + /// `first` and `second`. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - fn swizzle2<T>( - first: Simd<T, INPUT_LANES>, - second: Simd<T, INPUT_LANES>, - ) -> Simd<T, OUTPUT_LANES> + fn concat_swizzle<T, const M: usize>(first: Simd<T, M>, second: Simd<T, M>) -> Simd<T, N> where T: SimdElement, - LaneCount<INPUT_LANES>: SupportedLaneCount, - LaneCount<OUTPUT_LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, + LaneCount<M>: SupportedLaneCount, { - // Safety: `first` and `second` are vectors, and `INDEX_IMPL` is a const array of u32. - unsafe { intrinsics::simd_shuffle(first, second, Self::INDEX_IMPL) } - } -} - -/// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here. -/// This trait hides `INDEX_IMPL` from the public API. -trait SwizzleImpl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> { - const INDEX_IMPL: [u32; OUTPUT_LANES]; -} - -impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> SwizzleImpl<INPUT_LANES, OUTPUT_LANES> - for T -where - T: Swizzle<INPUT_LANES, OUTPUT_LANES> + ?Sized, -{ - const INDEX_IMPL: [u32; OUTPUT_LANES] = { - let mut output = [0; OUTPUT_LANES]; - let mut i = 0; - while i < OUTPUT_LANES { - let index = Self::INDEX[i]; - assert!(index as u32 as usize == index); - assert!(index < INPUT_LANES, "source lane exceeds input lane count",); - output[i] = index as u32; - i += 1; + // Safety: `first` and `second` are vectors, and the index is a const array of u32. + unsafe { + intrinsics::simd_shuffle( + first, + second, + const { + let mut output = [0; N]; + let mut i = 0; + while i < N { + let index = Self::INDEX[i]; + assert!(index as u32 as usize == index); + assert!( + index < 2 * M, + "source element index exceeds input vector length" + ); + output[i] = index as u32; + i += 1; + } + output + }, + ) } - output - }; -} - -/// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here. -/// This trait hides `INDEX_IMPL` from the public API. -trait Swizzle2Impl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> { - const INDEX_IMPL: [u32; OUTPUT_LANES]; -} + } -impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> Swizzle2Impl<INPUT_LANES, OUTPUT_LANES> - for T -where - T: Swizzle2<INPUT_LANES, OUTPUT_LANES> + ?Sized, -{ - const INDEX_IMPL: [u32; OUTPUT_LANES] = { - let mut output = [0; OUTPUT_LANES]; - let mut i = 0; - while i < OUTPUT_LANES { - let (offset, index) = match Self::INDEX[i] { - Which::First(index) => (false, index), - Which::Second(index) => (true, index), - }; - assert!(index < INPUT_LANES, "source lane exceeds input lane count",); + /// Create a new mask from the elements of `mask`. + /// + /// Element `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of + /// `first` and `second`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original inputs"] + fn swizzle_mask<T, const M: usize>(mask: Mask<T, M>) -> Mask<T, N> + where + T: MaskElement, + LaneCount<N>: SupportedLaneCount, + LaneCount<M>: SupportedLaneCount, + { + // SAFETY: all elements of this mask come from another mask + unsafe { Mask::from_int_unchecked(Self::swizzle(mask.to_int())) } + } - // lanes are indexed by the first vector, then second vector - let index = if offset { index + INPUT_LANES } else { index }; - assert!(index as u32 as usize == index); - output[i] = index as u32; - i += 1; - } - output - }; + /// Create a new mask from the elements of `first` and `second`. + /// + /// Element `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of + /// `first` and `second`. + #[inline] + #[must_use = "method returns a new mask and does not mutate the original inputs"] + fn concat_swizzle_mask<T, const M: usize>(first: Mask<T, M>, second: Mask<T, M>) -> Mask<T, N> + where + T: MaskElement, + LaneCount<N>: SupportedLaneCount, + LaneCount<M>: SupportedLaneCount, + { + // SAFETY: all elements of this mask come from another mask + unsafe { Mask::from_int_unchecked(Self::concat_swizzle(first.to_int(), second.to_int())) } + } } -impl<T, const LANES: usize> Simd<T, LANES> +impl<T, const N: usize> Simd<T, N> where T: SimdElement, - LaneCount<LANES>: SupportedLaneCount, + LaneCount<N>: SupportedLaneCount, { - /// Reverse the order of the lanes in the vector. + /// Reverse the order of the elements in the vector. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn reverse(self) -> Self { - const fn reverse_index<const LANES: usize>() -> [usize; LANES] { - let mut index = [0; LANES]; - let mut i = 0; - while i < LANES { - index[i] = LANES - i - 1; - i += 1; - } - index - } - struct Reverse; - impl<const LANES: usize> Swizzle<LANES, LANES> for Reverse { - const INDEX: [usize; LANES] = reverse_index::<LANES>(); + impl<const N: usize> Swizzle<N> for Reverse { + const INDEX: [usize; N] = const { + let mut index = [0; N]; + let mut i = 0; + while i < N { + index[i] = N - i - 1; + i += 1; + } + index + }; } Reverse::swizzle(self) } /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end - /// while the last `LANES - OFFSET` elements move to the front. After calling `rotate_lanes_left`, - /// the element previously in lane `OFFSET` will become the first element in the slice. + /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`, + /// the element previously at index `OFFSET` will become the first element in the slice. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn rotate_lanes_left<const OFFSET: usize>(self) -> Self { - const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] { - let offset = OFFSET % LANES; - let mut index = [0; LANES]; - let mut i = 0; - while i < LANES { - index[i] = (i + offset) % LANES; - i += 1; - } - index - } - + pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self { struct Rotate<const OFFSET: usize>; - impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> { - const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>(); + impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> { + const INDEX: [usize; N] = const { + let offset = OFFSET % N; + let mut index = [0; N]; + let mut i = 0; + while i < N { + index[i] = (i + offset) % N; + i += 1; + } + index + }; } Rotate::<OFFSET>::swizzle(self) } - /// Rotates the vector such that the first `LANES - OFFSET` elements of the vector move to - /// the end while the last `OFFSET` elements move to the front. After calling `rotate_lanes_right`, - /// the element previously at index `LANES - OFFSET` will become the first element in the slice. + /// Rotates the vector such that the first `self.len() - OFFSET` elements of the vector move to + /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`, + /// the element previously at index `self.len() - OFFSET` will become the first element in the slice. #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] - pub fn rotate_lanes_right<const OFFSET: usize>(self) -> Self { - const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] { - let offset = LANES - OFFSET % LANES; - let mut index = [0; LANES]; - let mut i = 0; - while i < LANES { - index[i] = (i + offset) % LANES; - i += 1; - } - index - } - + pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self { struct Rotate<const OFFSET: usize>; - impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> { - const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>(); + impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> { + const INDEX: [usize; N] = const { + let offset = N - OFFSET % N; + let mut index = [0; N]; + let mut i = 0; + while i < N { + index[i] = (i + offset) % N; + i += 1; + } + index + }; } Rotate::<OFFSET>::swizzle(self) @@ -265,7 +255,7 @@ where /// Interleave two vectors. /// - /// The resulting vectors contain lanes taken alternatively from `self` and `other`, first + /// The resulting vectors contain elements taken alternatively from `self` and `other`, first /// filling the first result, and then the second. /// /// The reverse of this operation is [`Simd::deinterleave`]. @@ -282,18 +272,13 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn interleave(self, other: Self) -> (Self, Self) { - const fn interleave<const LANES: usize>(high: bool) -> [Which; LANES] { - let mut idx = [Which::First(0); LANES]; + const fn interleave<const N: usize>(high: bool) -> [usize; N] { + let mut idx = [0; N]; let mut i = 0; - while i < LANES { - // Treat the source as a concatenated vector - let dst_index = if high { i + LANES } else { i }; - let src_index = dst_index / 2 + (dst_index % 2) * LANES; - idx[i] = if src_index < LANES { - Which::First(src_index) - } else { - Which::Second(src_index % LANES) - }; + while i < N { + let dst_index = if high { i + N } else { i }; + let src_index = dst_index / 2 + (dst_index % 2) * N; + idx[i] = src_index; i += 1; } idx @@ -302,24 +287,27 @@ where struct Lo; struct Hi; - impl<const LANES: usize> Swizzle2<LANES, LANES> for Lo { - const INDEX: [Which; LANES] = interleave::<LANES>(false); + impl<const N: usize> Swizzle<N> for Lo { + const INDEX: [usize; N] = interleave::<N>(false); } - impl<const LANES: usize> Swizzle2<LANES, LANES> for Hi { - const INDEX: [Which; LANES] = interleave::<LANES>(true); + impl<const N: usize> Swizzle<N> for Hi { + const INDEX: [usize; N] = interleave::<N>(true); } - (Lo::swizzle2(self, other), Hi::swizzle2(self, other)) + ( + Lo::concat_swizzle(self, other), + Hi::concat_swizzle(self, other), + ) } /// Deinterleave two vectors. /// - /// The first result takes every other lane of `self` and then `other`, starting with - /// the first lane. + /// The first result takes every other element of `self` and then `other`, starting with + /// the first element. /// - /// The second result takes every other lane of `self` and then `other`, starting with - /// the second lane. + /// The second result takes every other element of `self` and then `other`, starting with + /// the second element. /// /// The reverse of this operation is [`Simd::interleave`]. /// @@ -335,17 +323,11 @@ where #[inline] #[must_use = "method returns a new vector and does not mutate the original inputs"] pub fn deinterleave(self, other: Self) -> (Self, Self) { - const fn deinterleave<const LANES: usize>(second: bool) -> [Which; LANES] { - let mut idx = [Which::First(0); LANES]; + const fn deinterleave<const N: usize>(second: bool) -> [usize; N] { + let mut idx = [0; N]; let mut i = 0; - while i < LANES { - // Treat the source as a concatenated vector - let src_index = i * 2 + second as usize; - idx[i] = if src_index < LANES { - Which::First(src_index) - } else { - Which::Second(src_index % LANES) - }; + while i < N { + idx[i] = i * 2 + second as usize; i += 1; } idx @@ -354,14 +336,52 @@ where struct Even; struct Odd; - impl<const LANES: usize> Swizzle2<LANES, LANES> for Even { - const INDEX: [Which; LANES] = deinterleave::<LANES>(false); + impl<const N: usize> Swizzle<N> for Even { + const INDEX: [usize; N] = deinterleave::<N>(false); } - impl<const LANES: usize> Swizzle2<LANES, LANES> for Odd { - const INDEX: [Which; LANES] = deinterleave::<LANES>(true); + impl<const N: usize> Swizzle<N> for Odd { + const INDEX: [usize; N] = deinterleave::<N>(true); } - (Even::swizzle2(self, other), Odd::swizzle2(self, other)) + ( + Even::concat_swizzle(self, other), + Odd::concat_swizzle(self, other), + ) + } + + /// Resize a vector. + /// + /// If `M` > `N`, extends the length of a vector, setting the new elements to `value`. + /// If `M` < `N`, truncates the vector to the first `M` elements. + /// + /// ``` + /// # #![feature(portable_simd)] + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::u32x4; + /// let x = u32x4::from_array([0, 1, 2, 3]); + /// assert_eq!(x.resize::<8>(9).to_array(), [0, 1, 2, 3, 9, 9, 9, 9]); + /// assert_eq!(x.resize::<2>(9).to_array(), [0, 1]); + /// ``` + #[inline] + #[must_use = "method returns a new vector and does not mutate the original inputs"] + pub fn resize<const M: usize>(self, value: T) -> Simd<T, M> + where + LaneCount<M>: SupportedLaneCount, + { + struct Resize<const N: usize>; + impl<const N: usize, const M: usize> Swizzle<M> for Resize<N> { + const INDEX: [usize; M] = const { + let mut index = [0; M]; + let mut i = 0; + while i < M { + index[i] = if i < N { i } else { N }; + i += 1; + } + index + }; + } + Resize::<N>::concat_swizzle(self, Simd::splat(value)) } } diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs index ce621792534..bd8a38e350d 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs @@ -86,7 +86,7 @@ where #[inline] #[allow(clippy::let_and_return)] unsafe fn avx2_pshufb(bytes: Simd<u8, 32>, idxs: Simd<u8, 32>) -> Simd<u8, 32> { - use crate::simd::SimdPartialOrd; + use crate::simd::cmp::SimdPartialOrd; #[cfg(target_arch = "x86")] use core::arch::x86; #[cfg(target_arch = "x86_64")] @@ -149,7 +149,7 @@ where // On x86, make sure the top bit is set. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] let idxs = { - use crate::simd::SimdPartialOrd; + use crate::simd::cmp::SimdPartialOrd; idxs.simd_lt(Simd::splat(N as u8)) .select(idxs, Simd::splat(u8::MAX)) }; diff --git a/library/portable-simd/crates/core_simd/src/to_bytes.rs b/library/portable-simd/crates/core_simd/src/to_bytes.rs index b36b1a347b2..222526c4ab3 100644 --- a/library/portable-simd/crates/core_simd/src/to_bytes.rs +++ b/library/portable-simd/crates/core_simd/src/to_bytes.rs @@ -1,24 +1,125 @@ +use crate::simd::{ + num::{SimdFloat, SimdInt, SimdUint}, + LaneCount, Simd, SimdElement, SupportedLaneCount, +}; + +mod sealed { + use super::*; + pub trait Sealed {} + impl<T: SimdElement, const N: usize> Sealed for Simd<T, N> where LaneCount<N>: SupportedLaneCount {} +} +use sealed::Sealed; + +/// Convert SIMD vectors to vectors of bytes +pub trait ToBytes: Sealed { + /// This type, reinterpreted as bytes. + type Bytes: Copy + + Unpin + + Send + + Sync + + AsRef<[u8]> + + AsMut<[u8]> + + SimdUint<Scalar = u8> + + 'static; + + /// Return the memory representation of this integer as a byte array in native byte + /// order. + fn to_ne_bytes(self) -> Self::Bytes; + + /// Return the memory representation of this integer as a byte array in big-endian + /// (network) byte order. + fn to_be_bytes(self) -> Self::Bytes; + + /// Return the memory representation of this integer as a byte array in little-endian + /// byte order. + fn to_le_bytes(self) -> Self::Bytes; + + /// Create a native endian integer value from its memory representation as a byte array + /// in native endianness. + fn from_ne_bytes(bytes: Self::Bytes) -> Self; + + /// Create an integer value from its representation as a byte array in big endian. + fn from_be_bytes(bytes: Self::Bytes) -> Self; + + /// Create an integer value from its representation as a byte array in little endian. + fn from_le_bytes(bytes: Self::Bytes) -> Self; +} + +macro_rules! swap_bytes { + { f32, $x:expr } => { Simd::from_bits($x.to_bits().swap_bytes()) }; + { f64, $x:expr } => { Simd::from_bits($x.to_bits().swap_bytes()) }; + { $ty:ty, $x:expr } => { $x.swap_bytes() } +} + macro_rules! impl_to_bytes { - { $ty:ty, $size:literal } => { - impl<const LANES: usize> crate::simd::Simd<$ty, LANES> - where - crate::simd::LaneCount<LANES>: crate::simd::SupportedLaneCount, - crate::simd::LaneCount<{{ $size * LANES }}>: crate::simd::SupportedLaneCount, - { - /// Return the memory representation of this integer as a byte array in native byte - /// order. - pub fn to_ne_bytes(self) -> crate::simd::Simd<u8, {{ $size * LANES }}> { + { $ty:tt, 1 } => { impl_to_bytes! { $ty, 1 * [1, 2, 4, 8, 16, 32, 64] } }; + { $ty:tt, 2 } => { impl_to_bytes! { $ty, 2 * [1, 2, 4, 8, 16, 32] } }; + { $ty:tt, 4 } => { impl_to_bytes! { $ty, 4 * [1, 2, 4, 8, 16] } }; + { $ty:tt, 8 } => { impl_to_bytes! { $ty, 8 * [1, 2, 4, 8] } }; + { $ty:tt, 16 } => { impl_to_bytes! { $ty, 16 * [1, 2, 4] } }; + { $ty:tt, 32 } => { impl_to_bytes! { $ty, 32 * [1, 2] } }; + { $ty:tt, 64 } => { impl_to_bytes! { $ty, 64 * [1] } }; + + { $ty:tt, $size:literal * [$($elems:literal),*] } => { + $( + impl ToBytes for Simd<$ty, $elems> { + type Bytes = Simd<u8, { $size * $elems }>; + + #[inline] + fn to_ne_bytes(self) -> Self::Bytes { // Safety: transmuting between vectors is safe - unsafe { core::mem::transmute_copy(&self) } + unsafe { + #![allow(clippy::useless_transmute)] + core::mem::transmute(self) + } + } + + #[inline] + fn to_be_bytes(mut self) -> Self::Bytes { + if !cfg!(target_endian = "big") { + self = swap_bytes!($ty, self); + } + self.to_ne_bytes() + } + + #[inline] + fn to_le_bytes(mut self) -> Self::Bytes { + if !cfg!(target_endian = "little") { + self = swap_bytes!($ty, self); + } + self.to_ne_bytes() } - /// Create a native endian integer value from its memory representation as a byte array - /// in native endianness. - pub fn from_ne_bytes(bytes: crate::simd::Simd<u8, {{ $size * LANES }}>) -> Self { + #[inline] + fn from_ne_bytes(bytes: Self::Bytes) -> Self { // Safety: transmuting between vectors is safe - unsafe { core::mem::transmute_copy(&bytes) } + unsafe { + #![allow(clippy::useless_transmute)] + core::mem::transmute(bytes) + } + } + + #[inline] + fn from_be_bytes(bytes: Self::Bytes) -> Self { + let ret = Self::from_ne_bytes(bytes); + if cfg!(target_endian = "big") { + ret + } else { + swap_bytes!($ty, ret) + } + } + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + let ret = Self::from_ne_bytes(bytes); + if cfg!(target_endian = "little") { + ret + } else { + swap_bytes!($ty, ret) + } } } + )* } } @@ -39,3 +140,6 @@ impl_to_bytes! { i64, 8 } impl_to_bytes! { isize, 4 } #[cfg(target_pointer_width = "64")] impl_to_bytes! { isize, 8 } + +impl_to_bytes! { f32, 4 } +impl_to_bytes! { f64, 8 } diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs index 9aa7bacfce9..105c06741c5 100644 --- a/library/portable-simd/crates/core_simd/src/vector.rs +++ b/library/portable-simd/crates/core_simd/src/vector.rs @@ -1,6 +1,8 @@ use crate::simd::{ - intrinsics, LaneCount, Mask, MaskElement, SimdConstPtr, SimdMutPtr, SimdPartialOrd, - SupportedLaneCount, Swizzle, + cmp::SimdPartialOrd, + intrinsics, + ptr::{SimdConstPtr, SimdMutPtr}, + LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle, }; use core::convert::{TryFrom, TryInto}; @@ -110,7 +112,7 @@ where T: SimdElement, { /// Number of elements in this vector. - pub const LANES: usize = N; + pub const LEN: usize = N; /// Returns the number of elements in this SIMD vector. /// @@ -118,13 +120,16 @@ where /// /// ``` /// # #![feature(portable_simd)] - /// # use core::simd::u32x4; + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::u32x4; /// let v = u32x4::splat(0); - /// assert_eq!(v.lanes(), 4); + /// assert_eq!(v.len(), 4); /// ``` #[inline] - pub const fn lanes(&self) -> usize { - Self::LANES + #[allow(clippy::len_without_is_empty)] + pub const fn len(&self) -> usize { + Self::LEN } /// Constructs a new SIMD vector with all elements set to the given value. @@ -133,7 +138,9 @@ where /// /// ``` /// # #![feature(portable_simd)] - /// # use core::simd::u32x4; + /// # #[cfg(feature = "as_crate")] use core_simd::simd; + /// # #[cfg(not(feature = "as_crate"))] use core::simd; + /// # use simd::u32x4; /// let v = u32x4::splat(8); /// assert_eq!(v.as_array(), &[8, 8, 8, 8]); /// ``` @@ -142,10 +149,10 @@ where // This is preferred over `[value; N]`, since it's explicitly a splat: // https://github.com/rust-lang/rust/issues/97804 struct Splat; - impl<const N: usize> Swizzle<1, N> for Splat { + impl<const N: usize> Swizzle<N> for Splat { const INDEX: [usize; N] = [0; N]; } - Splat::swizzle(Simd::<T, 1>::from([value])) + Splat::swizzle::<T, 1>(Simd::<T, 1>::from([value])) } /// Returns an array reference containing the entire SIMD vector. @@ -271,7 +278,7 @@ where #[track_caller] pub const fn from_slice(slice: &[T]) -> Self { assert!( - slice.len() >= Self::LANES, + slice.len() >= Self::LEN, "slice length must be at least the number of elements" ); // SAFETY: We just checked that the slice contains @@ -301,7 +308,7 @@ where #[track_caller] pub fn copy_to_slice(self, slice: &mut [T]) { assert!( - slice.len() >= Self::LANES, + slice.len() >= Self::LEN, "slice length must be at least the number of elements" ); // SAFETY: We just checked that the slice contains @@ -394,7 +401,7 @@ where /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdPartialOrd, Mask}; + /// # use simd::{Simd, cmp::SimdPartialOrd, Mask}; /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; /// let idxs = Simd::from_array([9, 3, 0, 5]); // Includes an out-of-bounds index /// let alt = Simd::from_array([-5, -4, -3, -2]); @@ -434,7 +441,7 @@ where /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdConstPtr}; + /// # use simd::prelude::*; /// let values = [6, 2, 4, 9]; /// let offsets = Simd::from_array([1, 0, 0, 3]); /// let source = Simd::splat(values.as_ptr()).wrapping_add(offsets); @@ -467,7 +474,7 @@ where /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Mask, Simd, SimdConstPtr}; + /// # use simd::prelude::*; /// let values = [6, 2, 4, 9]; /// let enable = Mask::from_array([true, true, false, true]); /// let offsets = Simd::from_array([1, 0, 0, 3]); @@ -550,7 +557,7 @@ where /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdPartialOrd, Mask}; + /// # use simd::{Simd, cmp::SimdPartialOrd, Mask}; /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; /// let idxs = Simd::from_array([9, 3, 0, 0]); /// let vals = Simd::from_array([-27, 82, -41, 124]); @@ -604,7 +611,7 @@ where /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Simd, SimdMutPtr}; + /// # use simd::{Simd, ptr::SimdMutPtr}; /// let mut values = [0; 4]; /// let offset = Simd::from_array([3, 2, 1, 0]); /// let ptrs = Simd::splat(values.as_mut_ptr()).wrapping_add(offset); @@ -631,7 +638,7 @@ where /// # #![feature(portable_simd)] /// # #[cfg(feature = "as_crate")] use core_simd::simd; /// # #[cfg(not(feature = "as_crate"))] use core::simd; - /// # use simd::{Mask, Simd, SimdMutPtr}; + /// # use simd::{Mask, Simd, ptr::SimdMutPtr}; /// let mut values = [0; 4]; /// let offset = Simd::from_array([3, 2, 1, 0]); /// let ptrs = Simd::splat(values.as_mut_ptr()).wrapping_add(offset); diff --git a/library/portable-simd/crates/core_simd/src/vendor.rs b/library/portable-simd/crates/core_simd/src/vendor.rs index 9fb70218c95..6223bedb4e1 100644 --- a/library/portable-simd/crates/core_simd/src/vendor.rs +++ b/library/portable-simd/crates/core_simd/src/vendor.rs @@ -21,7 +21,7 @@ macro_rules! from_transmute { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod x86; -#[cfg(any(target_arch = "wasm32"))] +#[cfg(target_arch = "wasm32")] mod wasm32; #[cfg(any(target_arch = "aarch64", target_arch = "arm",))] diff --git a/library/portable-simd/crates/core_simd/src/vendor/x86.rs b/library/portable-simd/crates/core_simd/src/vendor/x86.rs index 0dd47015ed2..66aaf90eef5 100644 --- a/library/portable-simd/crates/core_simd/src/vendor/x86.rs +++ b/library/portable-simd/crates/core_simd/src/vendor/x86.rs @@ -1,6 +1,6 @@ use crate::simd::*; -#[cfg(any(target_arch = "x86"))] +#[cfg(target_arch = "x86")] use core::arch::x86::*; #[cfg(target_arch = "x86_64")] diff --git a/library/portable-simd/crates/core_simd/tests/cast.rs b/library/portable-simd/crates/core_simd/tests/cast.rs index 00545936ea2..185e1945faa 100644 --- a/library/portable-simd/crates/core_simd/tests/cast.rs +++ b/library/portable-simd/crates/core_simd/tests/cast.rs @@ -3,7 +3,7 @@ macro_rules! cast_types { ($start:ident, $($target:ident),*) => { mod $start { #[allow(unused)] - use core_simd::simd::{Simd, SimdInt, SimdUint, SimdFloat}; + use core_simd::simd::prelude::*; type Vector<const N: usize> = Simd<$start, N>; $( mod $target { diff --git a/library/portable-simd/crates/core_simd/tests/masks.rs b/library/portable-simd/crates/core_simd/tests/masks.rs index 9f8bad1c36c..00fc2a24e27 100644 --- a/library/portable-simd/crates/core_simd/tests/masks.rs +++ b/library/portable-simd/crates/core_simd/tests/masks.rs @@ -72,7 +72,6 @@ macro_rules! test_mask_api { #[test] fn roundtrip_bitmask_conversion() { - use core_simd::simd::ToBitMask; let values = [ true, false, false, true, false, false, true, false, true, true, false, false, false, false, false, true, @@ -85,8 +84,6 @@ macro_rules! test_mask_api { #[test] fn roundtrip_bitmask_conversion_short() { - use core_simd::simd::ToBitMask; - let values = [ false, false, false, true, ]; @@ -125,18 +122,17 @@ macro_rules! test_mask_api { cast_impl::<isize>(); } - #[cfg(feature = "generic_const_exprs")] #[test] - fn roundtrip_bitmask_array_conversion() { - use core_simd::simd::ToBitMaskArray; + fn roundtrip_bitmask_vector_conversion() { + use core_simd::simd::ToBytes; let values = [ true, false, false, true, false, false, true, false, true, true, false, false, false, false, false, true, ]; let mask = Mask::<$type, 16>::from_array(values); - let bitmask = mask.to_bitmask_array(); - assert_eq!(bitmask, [0b01001001, 0b10000011]); - assert_eq!(Mask::<$type, 16>::from_bitmask_array(bitmask), mask); + let bitmask = mask.to_bitmask_vector(); + assert_eq!(bitmask.resize::<2>(0).to_ne_bytes()[..2], [0b01001001, 0b10000011]); + assert_eq!(Mask::<$type, 16>::from_bitmask_vector(bitmask), mask); } } } diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs index 3a02f3f01e1..aa565a13752 100644 --- a/library/portable-simd/crates/core_simd/tests/ops_macros.rs +++ b/library/portable-simd/crates/core_simd/tests/ops_macros.rs @@ -6,7 +6,7 @@ macro_rules! impl_unary_op_test { { $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => { test_helpers::test_lanes! { fn $fn<const LANES: usize>() { - test_helpers::test_unary_elementwise( + test_helpers::test_unary_elementwise_flush_subnormals( &<core_simd::simd::Simd<$scalar, LANES> as core::ops::$trait>::$fn, &$scalar_fn, &|_| true, @@ -31,7 +31,7 @@ macro_rules! impl_binary_op_test { test_helpers::test_lanes! { fn normal<const LANES: usize>() { - test_helpers::test_binary_elementwise( + test_helpers::test_binary_elementwise_flush_subnormals( &<Simd<$scalar, LANES> as core::ops::$trait>::$fn, &$scalar_fn, &|_, _| true, @@ -39,7 +39,7 @@ macro_rules! impl_binary_op_test { } fn assign<const LANES: usize>() { - test_helpers::test_binary_elementwise( + test_helpers::test_binary_elementwise_flush_subnormals( &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a }, &$scalar_fn, &|_, _| true, @@ -68,6 +68,7 @@ macro_rules! impl_binary_checked_op_test { test_helpers::test_lanes! { fn normal<const LANES: usize>() { + #![allow(clippy::redundant_closure_call)] test_helpers::test_binary_elementwise( &<Simd<$scalar, LANES> as core::ops::$trait>::$fn, &$scalar_fn, @@ -76,6 +77,7 @@ macro_rules! impl_binary_checked_op_test { } fn assign<const LANES: usize>() { + #![allow(clippy::redundant_closure_call)] test_helpers::test_binary_elementwise( &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a }, &$scalar_fn, @@ -94,11 +96,43 @@ macro_rules! impl_binary_checked_op_test { macro_rules! impl_common_integer_tests { { $vector:ident, $scalar:ident } => { test_helpers::test_lanes! { + fn shr<const LANES: usize>() { + use core::ops::Shr; + let shr = |x: $scalar, y: $scalar| x.wrapping_shr(y as _); + test_helpers::test_binary_elementwise( + &<$vector::<LANES> as Shr<$vector::<LANES>>>::shr, + &shr, + &|_, _| true, + ); + test_helpers::test_binary_scalar_rhs_elementwise( + &<$vector::<LANES> as Shr<$scalar>>::shr, + &shr, + &|_, _| true, + ); + } + + fn shl<const LANES: usize>() { + use core::ops::Shl; + let shl = |x: $scalar, y: $scalar| x.wrapping_shl(y as _); + test_helpers::test_binary_elementwise( + &<$vector::<LANES> as Shl<$vector::<LANES>>>::shl, + &shl, + &|_, _| true, + ); + test_helpers::test_binary_scalar_rhs_elementwise( + &<$vector::<LANES> as Shl<$scalar>>::shl, + &shl, + &|_, _| true, + ); + } + fn reduce_sum<const LANES: usize>() { test_helpers::test_1(&|x| { + use test_helpers::subnormals::{flush, flush_in}; test_helpers::prop_assert_biteq! ( $vector::<LANES>::from_array(x).reduce_sum(), x.iter().copied().fold(0 as $scalar, $scalar::wrapping_add), + flush(x.iter().copied().map(flush_in).fold(0 as $scalar, $scalar::wrapping_add)), ); Ok(()) }); @@ -106,9 +140,11 @@ macro_rules! impl_common_integer_tests { fn reduce_product<const LANES: usize>() { test_helpers::test_1(&|x| { + use test_helpers::subnormals::{flush, flush_in}; test_helpers::prop_assert_biteq! ( $vector::<LANES>::from_array(x).reduce_product(), x.iter().copied().fold(1 as $scalar, $scalar::wrapping_mul), + flush(x.iter().copied().map(flush_in).fold(1 as $scalar, $scalar::wrapping_mul)), ); Ok(()) }); @@ -163,6 +199,54 @@ macro_rules! impl_common_integer_tests { Ok(()) }); } + + fn swap_bytes<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &$vector::<LANES>::swap_bytes, + &$scalar::swap_bytes, + &|_| true, + ) + } + + fn reverse_bits<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &$vector::<LANES>::reverse_bits, + &$scalar::reverse_bits, + &|_| true, + ) + } + + fn leading_zeros<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &$vector::<LANES>::leading_zeros, + &|x| x.leading_zeros() as _, + &|_| true, + ) + } + + fn trailing_zeros<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &$vector::<LANES>::trailing_zeros, + &|x| x.trailing_zeros() as _, + &|_| true, + ) + } + + fn leading_ones<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &$vector::<LANES>::leading_ones, + &|x| x.leading_ones() as _, + &|_| true, + ) + } + + fn trailing_ones<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &$vector::<LANES>::trailing_ones, + &|x| x.trailing_ones() as _, + &|_| true, + ) + } } } } @@ -172,7 +256,7 @@ macro_rules! impl_common_integer_tests { macro_rules! impl_signed_tests { { $scalar:tt } => { mod $scalar { - use core_simd::simd::SimdInt; + use core_simd::simd::num::SimdInt; type Vector<const LANES: usize> = core_simd::simd::Simd<Scalar, LANES>; type Scalar = $scalar; @@ -224,7 +308,7 @@ macro_rules! impl_signed_tests { } fn simd_min<const LANES: usize>() { - use core_simd::simd::SimdOrd; + use core_simd::simd::cmp::SimdOrd; let a = Vector::<LANES>::splat(Scalar::MIN); let b = Vector::<LANES>::splat(0); assert_eq!(a.simd_min(b), a); @@ -234,7 +318,7 @@ macro_rules! impl_signed_tests { } fn simd_max<const LANES: usize>() { - use core_simd::simd::SimdOrd; + use core_simd::simd::cmp::SimdOrd; let a = Vector::<LANES>::splat(Scalar::MIN); let b = Vector::<LANES>::splat(0); assert_eq!(a.simd_max(b), b); @@ -244,7 +328,7 @@ macro_rules! impl_signed_tests { } fn simd_clamp<const LANES: usize>() { - use core_simd::simd::SimdOrd; + use core_simd::simd::cmp::SimdOrd; let min = Vector::<LANES>::splat(Scalar::MIN); let max = Vector::<LANES>::splat(Scalar::MAX); let zero = Vector::<LANES>::splat(0); @@ -313,7 +397,7 @@ macro_rules! impl_signed_tests { macro_rules! impl_unsigned_tests { { $scalar:tt } => { mod $scalar { - use core_simd::simd::SimdUint; + use core_simd::simd::num::SimdUint; type Vector<const LANES: usize> = core_simd::simd::Simd<Scalar, LANES>; type Scalar = $scalar; @@ -327,6 +411,16 @@ macro_rules! impl_unsigned_tests { } } + test_helpers::test_lanes! { + fn wrapping_neg<const LANES: usize>() { + test_helpers::test_unary_elementwise( + &Vector::<LANES>::wrapping_neg, + &Scalar::wrapping_neg, + &|_| true, + ); + } + } + impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add); impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub); impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul); @@ -348,7 +442,7 @@ macro_rules! impl_unsigned_tests { macro_rules! impl_float_tests { { $scalar:tt, $int_scalar:tt } => { mod $scalar { - use core_simd::simd::SimdFloat; + use core_simd::simd::num::SimdFloat; type Vector<const LANES: usize> = core_simd::simd::Simd<Scalar, LANES>; type Scalar = $scalar; @@ -433,7 +527,7 @@ macro_rules! impl_float_tests { } fn to_degrees<const LANES: usize>() { - test_helpers::test_unary_elementwise( + test_helpers::test_unary_elementwise_flush_subnormals( &Vector::<LANES>::to_degrees, &Scalar::to_degrees, &|_| true, @@ -441,7 +535,7 @@ macro_rules! impl_float_tests { } fn to_radians<const LANES: usize>() { - test_helpers::test_unary_elementwise( + test_helpers::test_unary_elementwise_flush_subnormals( &Vector::<LANES>::to_radians, &Scalar::to_radians, &|_| true, @@ -511,7 +605,12 @@ macro_rules! impl_float_tests { } fn simd_clamp<const LANES: usize>() { + if cfg!(all(target_arch = "powerpc64", target_feature = "vsx")) { + // https://gitlab.com/qemu-project/qemu/-/issues/1780 + return; + } test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| { + use test_helpers::subnormals::flush_in; for (min, max) in min.iter_mut().zip(max.iter_mut()) { if max < min { core::mem::swap(min, max); @@ -528,8 +627,20 @@ macro_rules! impl_float_tests { for i in 0..LANES { result_scalar[i] = value[i].clamp(min[i], max[i]); } + let mut result_scalar_flush = [Scalar::default(); LANES]; + for i in 0..LANES { + // Comparisons flush-to-zero, but return value selection is _not_ flushed. + let mut value = value[i]; + if flush_in(value) < flush_in(min[i]) { + value = min[i]; + } + if flush_in(value) > flush_in(max[i]) { + value = max[i]; + } + result_scalar_flush[i] = value + } let result_vector = Vector::from_array(value).simd_clamp(min.into(), max.into()).to_array(); - test_helpers::prop_assert_biteq!(result_scalar, result_vector); + test_helpers::prop_assert_biteq!(result_vector, result_scalar, result_scalar_flush); Ok(()) }) } diff --git a/library/portable-simd/crates/core_simd/tests/pointers.rs b/library/portable-simd/crates/core_simd/tests/pointers.rs index 0ae8f83b8b9..a90ff928ced 100644 --- a/library/portable-simd/crates/core_simd/tests/pointers.rs +++ b/library/portable-simd/crates/core_simd/tests/pointers.rs @@ -1,6 +1,9 @@ #![feature(portable_simd, strict_provenance)] -use core_simd::simd::{Simd, SimdConstPtr, SimdMutPtr}; +use core_simd::simd::{ + ptr::{SimdConstPtr, SimdMutPtr}, + Simd, +}; macro_rules! common_tests { { $constness:ident } => { diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs index aacf7bd3bcc..847766ec41e 100644 --- a/library/portable-simd/crates/core_simd/tests/round.rs +++ b/library/portable-simd/crates/core_simd/tests/round.rs @@ -43,7 +43,7 @@ macro_rules! float_rounding_test { } fn fract<const LANES: usize>() { - test_helpers::test_unary_elementwise( + test_helpers::test_unary_elementwise_flush_subnormals( &Vector::<LANES>::fract, &Scalar::fract, &|_| true, @@ -53,7 +53,7 @@ macro_rules! float_rounding_test { test_helpers::test_lanes! { fn to_int_unchecked<const LANES: usize>() { - use core_simd::simd::SimdFloat; + use core_simd::simd::num::SimdFloat; // The maximum integer that can be represented by the equivalently sized float has // all of the mantissa digits set to 1, pushed up to the MSB. const ALL_MANTISSA_BITS: IntScalar = ((1 << <Scalar>::MANTISSA_DIGITS) - 1); diff --git a/library/portable-simd/crates/core_simd/tests/swizzle.rs b/library/portable-simd/crates/core_simd/tests/swizzle.rs index 8cd7c33e823..522d71439b7 100644 --- a/library/portable-simd/crates/core_simd/tests/swizzle.rs +++ b/library/portable-simd/crates/core_simd/tests/swizzle.rs @@ -11,10 +11,10 @@ wasm_bindgen_test_configure!(run_in_browser); #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn swizzle() { struct Index; - impl Swizzle<4, 4> for Index { + impl Swizzle<4> for Index { const INDEX: [usize; 4] = [2, 1, 3, 0]; } - impl Swizzle<4, 2> for Index { + impl Swizzle<2> for Index { const INDEX: [usize; 2] = [1, 1]; } @@ -34,18 +34,18 @@ fn reverse() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn rotate() { let a = Simd::from_array([1, 2, 3, 4]); - assert_eq!(a.rotate_lanes_left::<0>().to_array(), [1, 2, 3, 4]); - assert_eq!(a.rotate_lanes_left::<1>().to_array(), [2, 3, 4, 1]); - assert_eq!(a.rotate_lanes_left::<2>().to_array(), [3, 4, 1, 2]); - assert_eq!(a.rotate_lanes_left::<3>().to_array(), [4, 1, 2, 3]); - assert_eq!(a.rotate_lanes_left::<4>().to_array(), [1, 2, 3, 4]); - assert_eq!(a.rotate_lanes_left::<5>().to_array(), [2, 3, 4, 1]); - assert_eq!(a.rotate_lanes_right::<0>().to_array(), [1, 2, 3, 4]); - assert_eq!(a.rotate_lanes_right::<1>().to_array(), [4, 1, 2, 3]); - assert_eq!(a.rotate_lanes_right::<2>().to_array(), [3, 4, 1, 2]); - assert_eq!(a.rotate_lanes_right::<3>().to_array(), [2, 3, 4, 1]); - assert_eq!(a.rotate_lanes_right::<4>().to_array(), [1, 2, 3, 4]); - assert_eq!(a.rotate_lanes_right::<5>().to_array(), [4, 1, 2, 3]); + assert_eq!(a.rotate_elements_left::<0>().to_array(), [1, 2, 3, 4]); + assert_eq!(a.rotate_elements_left::<1>().to_array(), [2, 3, 4, 1]); + assert_eq!(a.rotate_elements_left::<2>().to_array(), [3, 4, 1, 2]); + assert_eq!(a.rotate_elements_left::<3>().to_array(), [4, 1, 2, 3]); + assert_eq!(a.rotate_elements_left::<4>().to_array(), [1, 2, 3, 4]); + assert_eq!(a.rotate_elements_left::<5>().to_array(), [2, 3, 4, 1]); + assert_eq!(a.rotate_elements_right::<0>().to_array(), [1, 2, 3, 4]); + assert_eq!(a.rotate_elements_right::<1>().to_array(), [4, 1, 2, 3]); + assert_eq!(a.rotate_elements_right::<2>().to_array(), [3, 4, 1, 2]); + assert_eq!(a.rotate_elements_right::<3>().to_array(), [2, 3, 4, 1]); + assert_eq!(a.rotate_elements_right::<4>().to_array(), [1, 2, 3, 4]); + assert_eq!(a.rotate_elements_right::<5>().to_array(), [4, 1, 2, 3]); } #[test] diff --git a/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs index 646cd5f3383..f21a937f01c 100644 --- a/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs +++ b/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs @@ -1,6 +1,5 @@ #![feature(portable_simd)] use core::{fmt, ops::RangeInclusive}; -use proptest; use test_helpers::{self, biteq, make_runner, prop_assert_biteq}; fn swizzle_dyn_scalar_ver<const N: usize>(values: [u8; N], idxs: [u8; N]) -> [u8; N] { diff --git a/library/portable-simd/crates/core_simd/tests/to_bytes.rs b/library/portable-simd/crates/core_simd/tests/to_bytes.rs index be0ee4349c5..66a7981cdc3 100644 --- a/library/portable-simd/crates/core_simd/tests/to_bytes.rs +++ b/library/portable-simd/crates/core_simd/tests/to_bytes.rs @@ -1,14 +1,20 @@ -#![feature(portable_simd, generic_const_exprs, adt_const_params)] -#![allow(incomplete_features)] -#![cfg(feature = "generic_const_exprs")] +#![feature(portable_simd)] -use core_simd::simd::Simd; +use core_simd::simd::{Simd, ToBytes}; #[test] fn byte_convert() { let int = Simd::<u32, 2>::from_array([0xdeadbeef, 0x8badf00d]); - let bytes = int.to_ne_bytes(); - assert_eq!(int[0].to_ne_bytes(), bytes[..4]); - assert_eq!(int[1].to_ne_bytes(), bytes[4..]); - assert_eq!(Simd::<u32, 2>::from_ne_bytes(bytes), int); + let ne_bytes = int.to_ne_bytes(); + let be_bytes = int.to_be_bytes(); + let le_bytes = int.to_le_bytes(); + assert_eq!(int[0].to_ne_bytes(), ne_bytes[..4]); + assert_eq!(int[1].to_ne_bytes(), ne_bytes[4..]); + assert_eq!(int[0].to_be_bytes(), be_bytes[..4]); + assert_eq!(int[1].to_be_bytes(), be_bytes[4..]); + assert_eq!(int[0].to_le_bytes(), le_bytes[..4]); + assert_eq!(int[1].to_le_bytes(), le_bytes[4..]); + assert_eq!(Simd::<u32, 2>::from_ne_bytes(ne_bytes), int); + assert_eq!(Simd::<u32, 2>::from_be_bytes(be_bytes), int); + assert_eq!(Simd::<u32, 2>::from_le_bytes(le_bytes), int); } diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs index 4ac60b10c92..1fef17242ca 100644 --- a/library/portable-simd/crates/std_float/src/lib.rs +++ b/library/portable-simd/crates/std_float/src/lib.rs @@ -1,5 +1,10 @@ #![cfg_attr(feature = "as_crate", no_std)] // We are std! -#![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))] +#![cfg_attr( + feature = "as_crate", + feature(platform_intrinsics), + feature(portable_simd), + allow(internal_features) +)] #[cfg(not(feature = "as_crate"))] use core::simd; #[cfg(feature = "as_crate")] @@ -144,7 +149,7 @@ where #[cfg(test)] mod tests { use super::*; - use simd::*; + use simd::prelude::*; #[test] fn everything_works() { diff --git a/library/portable-simd/crates/test_helpers/Cargo.toml b/library/portable-simd/crates/test_helpers/Cargo.toml index 1d2bc8b519a..23dae7c9338 100644 --- a/library/portable-simd/crates/test_helpers/Cargo.toml +++ b/library/portable-simd/crates/test_helpers/Cargo.toml @@ -4,10 +4,8 @@ version = "0.1.0" edition = "2021" publish = false -[dependencies.proptest] -version = "0.10" -default-features = false -features = ["alloc"] +[dependencies] +proptest = { version = "0.10", default-features = false, features = ["alloc"] } [features] all_lane_counts = [] diff --git a/library/portable-simd/crates/test_helpers/src/biteq.rs b/library/portable-simd/crates/test_helpers/src/biteq.rs index 7d91260d838..cbc20cda0d6 100644 --- a/library/portable-simd/crates/test_helpers/src/biteq.rs +++ b/library/portable-simd/crates/test_helpers/src/biteq.rs @@ -113,6 +113,27 @@ impl<T: BitEq> core::fmt::Debug for BitEqWrapper<'_, T> { } } +#[doc(hidden)] +pub struct BitEqEitherWrapper<'a, T>(pub &'a T, pub &'a T); + +impl<T: BitEq> PartialEq<BitEqEitherWrapper<'_, T>> for BitEqWrapper<'_, T> { + fn eq(&self, other: &BitEqEitherWrapper<'_, T>) -> bool { + self.0.biteq(other.0) || self.0.biteq(other.1) + } +} + +impl<T: BitEq> core::fmt::Debug for BitEqEitherWrapper<'_, T> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + if self.0.biteq(self.1) { + self.0.fmt(f) + } else { + self.0.fmt(f)?; + write!(f, " or ")?; + self.1.fmt(f) + } + } +} + #[macro_export] macro_rules! prop_assert_biteq { { $a:expr, $b:expr $(,)? } => { @@ -122,5 +143,14 @@ macro_rules! prop_assert_biteq { let b = $b; proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqWrapper(&b)); } - } + }; + { $a:expr, $b:expr, $c:expr $(,)? } => { + { + use $crate::biteq::{BitEqWrapper, BitEqEitherWrapper}; + let a = $a; + let b = $b; + let c = $c; + proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqEitherWrapper(&b, &c)); + } + }; } diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs index b26cdc311a2..b80c745aaf2 100644 --- a/library/portable-simd/crates/test_helpers/src/lib.rs +++ b/library/portable-simd/crates/test_helpers/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(stdsimd, powerpc_target_feature)] + pub mod array; #[cfg(target_arch = "wasm32")] @@ -6,6 +8,9 @@ pub mod wasm; #[macro_use] pub mod biteq; +pub mod subnormals; +use subnormals::FlushSubnormals; + /// Specifies the default strategy for testing a type. /// /// This strategy should be what "makes sense" to test. @@ -151,7 +156,6 @@ pub fn test_3< } /// Test a unary vector function against a unary scalar function, applied elementwise. -#[inline(never)] pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const LANES: usize>( fv: &dyn Fn(Vector) -> VectorResult, fs: &dyn Fn(Scalar) -> ScalarResult, @@ -178,6 +182,48 @@ pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const } /// Test a unary vector function against a unary scalar function, applied elementwise. +/// +/// Where subnormals are flushed, use approximate equality. +pub fn test_unary_elementwise_flush_subnormals< + Scalar, + ScalarResult, + Vector, + VectorResult, + const LANES: usize, +>( + fv: &dyn Fn(Vector) -> VectorResult, + fs: &dyn Fn(Scalar) -> ScalarResult, + check: &dyn Fn([Scalar; LANES]) -> bool, +) where + Scalar: Copy + core::fmt::Debug + DefaultStrategy + FlushSubnormals, + ScalarResult: Copy + biteq::BitEq + core::fmt::Debug + DefaultStrategy + FlushSubnormals, + Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy, + VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy, +{ + let flush = |x: Scalar| subnormals::flush(fs(subnormals::flush_in(x))); + test_1(&|x: [Scalar; LANES]| { + proptest::prop_assume!(check(x)); + let result_v: [ScalarResult; LANES] = fv(x.into()).into(); + let result_s: [ScalarResult; LANES] = x + .iter() + .copied() + .map(fs) + .collect::<Vec<_>>() + .try_into() + .unwrap(); + let result_sf: [ScalarResult; LANES] = x + .iter() + .copied() + .map(flush) + .collect::<Vec<_>>() + .try_into() + .unwrap(); + crate::prop_assert_biteq!(result_v, result_s, result_sf); + Ok(()) + }); +} + +/// Test a unary vector function against a unary scalar function, applied elementwise. #[inline(never)] pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>( fv: &dyn Fn(Vector) -> Mask, @@ -204,7 +250,6 @@ pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>( } /// Test a binary vector function against a binary scalar function, applied elementwise. -#[inline(never)] pub fn test_binary_elementwise< Scalar1, Scalar2, @@ -241,6 +286,85 @@ pub fn test_binary_elementwise< }); } +/// Test a binary vector function against a binary scalar function, applied elementwise. +/// +/// Where subnormals are flushed, use approximate equality. +pub fn test_binary_elementwise_flush_subnormals< + Scalar1, + Scalar2, + ScalarResult, + Vector1, + Vector2, + VectorResult, + const LANES: usize, +>( + fv: &dyn Fn(Vector1, Vector2) -> VectorResult, + fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult, + check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool, +) where + Scalar1: Copy + core::fmt::Debug + DefaultStrategy + FlushSubnormals, + Scalar2: Copy + core::fmt::Debug + DefaultStrategy + FlushSubnormals, + ScalarResult: Copy + biteq::BitEq + core::fmt::Debug + DefaultStrategy + FlushSubnormals, + Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy, + Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy, + VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy, +{ + let flush = |x: Scalar1, y: Scalar2| { + subnormals::flush(fs(subnormals::flush_in(x), subnormals::flush_in(y))) + }; + test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| { + proptest::prop_assume!(check(x, y)); + let result_v: [ScalarResult; LANES] = fv(x.into(), y.into()).into(); + let result_s: [ScalarResult; LANES] = x + .iter() + .copied() + .zip(y.iter().copied()) + .map(|(x, y)| fs(x, y)) + .collect::<Vec<_>>() + .try_into() + .unwrap(); + let result_sf: [ScalarResult; LANES] = x + .iter() + .copied() + .zip(y.iter().copied()) + .map(|(x, y)| flush(x, y)) + .collect::<Vec<_>>() + .try_into() + .unwrap(); + crate::prop_assert_biteq!(result_v, result_s, result_sf); + Ok(()) + }); +} + +/// Test a unary vector function against a unary scalar function, applied elementwise. +#[inline(never)] +pub fn test_binary_mask_elementwise<Scalar1, Scalar2, Vector1, Vector2, Mask, const LANES: usize>( + fv: &dyn Fn(Vector1, Vector2) -> Mask, + fs: &dyn Fn(Scalar1, Scalar2) -> bool, + check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool, +) where + Scalar1: Copy + core::fmt::Debug + DefaultStrategy, + Scalar2: Copy + core::fmt::Debug + DefaultStrategy, + Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy, + Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy, + Mask: Into<[bool; LANES]> + From<[bool; LANES]> + Copy, +{ + test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| { + proptest::prop_assume!(check(x, y)); + let result_v: [bool; LANES] = fv(x.into(), y.into()).into(); + let result_s: [bool; LANES] = x + .iter() + .copied() + .zip(y.iter().copied()) + .map(|(x, y)| fs(x, y)) + .collect::<Vec<_>>() + .try_into() + .unwrap(); + crate::prop_assert_biteq!(result_v, result_s); + Ok(()) + }); +} + /// Test a binary vector-scalar function against a binary scalar function, applied elementwise. #[inline(never)] pub fn test_binary_scalar_rhs_elementwise< diff --git a/library/portable-simd/crates/test_helpers/src/subnormals.rs b/library/portable-simd/crates/test_helpers/src/subnormals.rs new file mode 100644 index 00000000000..ec0f1fb24b9 --- /dev/null +++ b/library/portable-simd/crates/test_helpers/src/subnormals.rs @@ -0,0 +1,91 @@ +pub trait FlushSubnormals: Sized { + fn flush(self) -> Self { + self + } +} + +impl<T> FlushSubnormals for *const T {} +impl<T> FlushSubnormals for *mut T {} + +macro_rules! impl_float { + { $($ty:ty),* } => { + $( + impl FlushSubnormals for $ty { + fn flush(self) -> Self { + let is_f32 = core::mem::size_of::<Self>() == 4; + let ppc_flush = is_f32 && cfg!(all( + any(target_arch = "powerpc", all(target_arch = "powerpc64", target_endian = "big")), + target_feature = "altivec", + not(target_feature = "vsx"), + )); + let arm_flush = is_f32 && cfg!(all(target_arch = "arm", target_feature = "neon")); + let flush = ppc_flush || arm_flush; + if flush && self.is_subnormal() { + <$ty>::copysign(0., self) + } else { + self + } + } + } + )* + } +} + +macro_rules! impl_else { + { $($ty:ty),* } => { + $( + impl FlushSubnormals for $ty {} + )* + } +} + +impl_float! { f32, f64 } +impl_else! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } + +/// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs. +/// https://gitlab.com/qemu-project/qemu/-/issues/1779 +#[cfg(all( + any(target_arch = "powerpc", target_arch = "powerpc64"), + target_feature = "altivec" +))] +fn in_buggy_qemu() -> bool { + use std::sync::OnceLock; + static BUGGY: OnceLock<bool> = OnceLock::new(); + + fn add(x: f32, y: f32) -> f32 { + #[cfg(target_arch = "powerpc")] + use core::arch::powerpc::*; + #[cfg(target_arch = "powerpc64")] + use core::arch::powerpc64::*; + + let array: [f32; 4] = + unsafe { core::mem::transmute(vec_add(vec_splats(x), vec_splats(y))) }; + array[0] + } + + *BUGGY.get_or_init(|| add(-1.0857398e-38, 0.).is_sign_negative()) +} + +#[cfg(all( + any(target_arch = "powerpc", target_arch = "powerpc64"), + target_feature = "altivec" +))] +pub fn flush_in<T: FlushSubnormals>(x: T) -> T { + if in_buggy_qemu() { + x + } else { + x.flush() + } +} + +#[cfg(not(all( + any(target_arch = "powerpc", target_arch = "powerpc64"), + target_feature = "altivec" +)))] +pub fn flush_in<T: FlushSubnormals>(x: T) -> T { + x.flush() +} + +pub fn flush<T: FlushSubnormals>(x: T) -> T { + x.flush() +} diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index fa9d48771b6..81973182148 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -6,9 +6,10 @@ use crate::cmp; use crate::collections::TryReserveError; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::ops; +use crate::ops::{self, Range}; use crate::rc::Rc; -use crate::str::FromStr; +use crate::slice; +use crate::str::{from_utf8 as str_from_utf8, FromStr}; use crate::sync::Arc; use crate::sys::os_str::{Buf, Slice}; @@ -963,6 +964,83 @@ impl OsStr { self.inner.as_encoded_bytes() } + /// Takes a substring based on a range that corresponds to the return value of + /// [`OsStr::as_encoded_bytes`]. + /// + /// The range's start and end must lie on valid `OsStr` boundaries. + /// A valid `OsStr` boundary is one of: + /// - The start of the string + /// - The end of the string + /// - Immediately before a valid non-empty UTF-8 substring + /// - Immediately after a valid non-empty UTF-8 substring + /// + /// # Panics + /// + /// Panics if `range` does not lie on valid `OsStr` boundaries or if it + /// exceeds the end of the string. + /// + /// # Example + /// + /// ``` + /// #![feature(os_str_slice)] + /// + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo=bar"); + /// let bytes = os_str.as_encoded_bytes(); + /// if let Some(index) = bytes.iter().position(|b| *b == b'=') { + /// let key = os_str.slice_encoded_bytes(..index); + /// let value = os_str.slice_encoded_bytes(index + 1..); + /// assert_eq!(key, "foo"); + /// assert_eq!(value, "bar"); + /// } + /// ``` + #[unstable(feature = "os_str_slice", issue = "118485")] + pub fn slice_encoded_bytes<R: ops::RangeBounds<usize>>(&self, range: R) -> &Self { + #[track_caller] + fn check_valid_boundary(bytes: &[u8], index: usize) { + if index == 0 || index == bytes.len() { + return; + } + + // Fast path + if bytes[index - 1].is_ascii() || bytes[index].is_ascii() { + return; + } + + let (before, after) = bytes.split_at(index); + + // UTF-8 takes at most 4 bytes per codepoint, so we don't + // need to check more than that. + let after = after.get(..4).unwrap_or(after); + match str_from_utf8(after) { + Ok(_) => return, + Err(err) if err.valid_up_to() != 0 => return, + Err(_) => (), + } + + for len in 2..=4.min(index) { + let before = &before[index - len..]; + if str_from_utf8(before).is_ok() { + return; + } + } + + panic!("byte index {index} is not an OsStr boundary"); + } + + let encoded_bytes = self.as_encoded_bytes(); + let Range { start, end } = slice::range(range, ..encoded_bytes.len()); + check_valid_boundary(encoded_bytes, start); + check_valid_boundary(encoded_bytes, end); + + // SAFETY: `slice::range` ensures that `start` and `end` are valid + let slice = unsafe { encoded_bytes.get_unchecked(start..end) }; + + // SAFETY: `slice` comes from `self` and we validated the boundaries + unsafe { Self::from_encoded_bytes_unchecked(slice) } + } + /// Converts this string to its ASCII lower case equivalent in-place. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index d7926749aae..2765398d3e6 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -177,3 +177,53 @@ fn into_rc() { assert_eq!(&*rc2, os_str); assert_eq!(&*arc2, os_str); } + +#[test] +fn slice_encoded_bytes() { + let os_str = OsStr::new("123θგ🦀"); + // ASCII + let digits = os_str.slice_encoded_bytes(..3); + assert_eq!(digits, "123"); + let three = os_str.slice_encoded_bytes(2..3); + assert_eq!(three, "3"); + // 2-byte UTF-8 + let theta = os_str.slice_encoded_bytes(3..5); + assert_eq!(theta, "θ"); + // 3-byte UTF-8 + let gani = os_str.slice_encoded_bytes(5..8); + assert_eq!(gani, "გ"); + // 4-byte UTF-8 + let crab = os_str.slice_encoded_bytes(8..); + assert_eq!(crab, "🦀"); +} + +#[test] +#[should_panic(expected = "byte index 2 is not an OsStr boundary")] +fn slice_mid_char() { + let crab = OsStr::new("🦀"); + let _ = crab.slice_encoded_bytes(..2); +} + +#[cfg(windows)] +#[test] +#[should_panic(expected = "byte index 3 is not an OsStr boundary")] +fn slice_between_surrogates() { + use crate::os::windows::ffi::OsStringExt; + + let os_string = OsString::from_wide(&[0xD800, 0xD800]); + assert_eq!(os_string.as_encoded_bytes(), &[0xED, 0xA0, 0x80, 0xED, 0xA0, 0x80]); + let _ = os_string.slice_encoded_bytes(..3); +} + +#[cfg(windows)] +#[test] +fn slice_surrogate_edge() { + use crate::os::windows::ffi::OsStringExt; + + let os_string = OsString::from_wide(&[0xD800]); + let mut with_crab = os_string.clone(); + with_crab.push("🦀"); + + assert_eq!(with_crab.slice_encoded_bytes(..3), os_string); + assert_eq!(with_crab.slice_encoded_bytes(3..), "🦀"); +} diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 547a7b7052f..3b6fbf95faf 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -74,7 +74,7 @@ macro_rules! error_contains { // tests most of the time, but at least we do if the user has the right // permissions. pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { - if cfg!(unix) { + if cfg!(not(windows)) || env::var_os("CI").is_some() { return true; } let link = tmpdir.join("some_hopefully_unique_link_name"); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 21ca5d12559..52b1fe822d6 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -342,6 +342,7 @@ #![feature(round_ties_even)] #![feature(slice_internals)] #![feature(slice_ptr_get)] +#![feature(slice_range)] #![feature(std_internals)] #![feature(str_internals)] #![feature(strict_provenance)] @@ -584,9 +585,10 @@ pub mod time; #[unstable(feature = "portable_simd", issue = "86656")] mod std_float; -#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")] #[unstable(feature = "portable_simd", issue = "86656")] pub mod simd { + #![doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")] + #[doc(inline)] pub use crate::std_float::StdFloat; #[doc(inline)] diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index aaddf5ca09c..65af2aed6de 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -10,6 +10,7 @@ use std::io::{BufRead, BufReader}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::Command; +use std::sync::OnceLock; use std::time::{Duration, Instant}; use crate::core::build_steps::llvm; @@ -25,12 +26,10 @@ use crate::EXTRA_CHECK_CFGS; use crate::{Build, CLang, DocTests, GitRepo, Mode}; pub use crate::Compiler; -// FIXME: -// - use std::lazy for `Lazy` -// - use std::cell for `OnceCell` -// Once they get stabilized and reach beta. + use clap::ValueEnum; -use once_cell::sync::{Lazy, OnceCell}; +// FIXME: replace with std::lazy after it gets stabilized and reaches beta +use once_cell::sync::Lazy; #[cfg(test)] #[path = "../tests/builder.rs"] @@ -496,7 +495,7 @@ impl<'a> ShouldRun<'a> { /// /// [`path`]: ShouldRun::path pub fn paths(mut self, paths: &[&str]) -> Self { - static SUBMODULES_PATHS: OnceCell<Vec<String>> = OnceCell::new(); + static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new(); let init_submodules_paths = |src: &PathBuf| { let file = File::open(src.join(".gitmodules")).unwrap(); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 9ef90798590..22e8ce8365b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -17,6 +17,7 @@ use std::io::IsTerminal; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; +use std::sync::OnceLock; use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; @@ -25,7 +26,6 @@ use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{exe, output, t}; use build_helper::exit; -use once_cell::sync::OnceCell; use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1907,7 +1907,7 @@ impl Config { } pub(crate) fn download_rustc_commit(&self) -> Option<&str> { - static DOWNLOAD_RUSTC: OnceCell<Option<String>> = OnceCell::new(); + static DOWNLOAD_RUSTC: OnceLock<Option<String>> = OnceLock::new(); if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() { // avoid trying to actually download the commit return self.download_rustc_commit.as_deref(); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 3327aed9600..0a5844a6859 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -5,10 +5,10 @@ use std::{ io::{BufRead, BufReader, BufWriter, ErrorKind, Write}, path::{Path, PathBuf}, process::{Command, Stdio}, + sync::OnceLock, }; use build_helper::ci::CiEnv; -use once_cell::sync::OnceCell; use xz2::bufread::XzDecoder; use crate::core::build_steps::llvm::detect_llvm_sha; @@ -16,7 +16,7 @@ use crate::core::config::RustfmtMetadata; use crate::utils::helpers::{check_run, exe, program_out_of_date}; use crate::{t, Config}; -static SHOULD_FIX_BINS_AND_DYLIBS: OnceCell<bool> = OnceCell::new(); +static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new(); /// `Config::try_run` wrapper for this module to avoid warnings on `try_run`, since we don't have access to a `builder` yet. fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> { @@ -131,7 +131,7 @@ impl Config { println!("attempting to patch {}", fname.display()); // Only build `.nix-deps` once. - static NIX_DEPS_DIR: OnceCell<PathBuf> = OnceCell::new(); + static NIX_DEPS_DIR: OnceLock<PathBuf> = OnceLock::new(); let mut nix_build_succeeded = true; let nix_deps_dir = NIX_DEPS_DIR.get_or_init(|| { // Run `nix-build` to "build" each dependency (which will likely reuse diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 480dd757915..60a89e9bf07 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -25,12 +25,12 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::{Command, Output, Stdio}; use std::str; +use std::sync::OnceLock; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; use build_helper::util::fail; use filetime::FileTime; -use once_cell::sync::OnceCell; use sha2::digest::Digest; use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::channel::GitInfo; @@ -906,7 +906,7 @@ impl Build { /// Returns the sysroot of the snapshot compiler. fn rustc_snapshot_sysroot(&self) -> &Path { - static SYSROOT_CACHE: OnceCell<PathBuf> = once_cell::sync::OnceCell::new(); + static SYSROOT_CACHE: OnceLock<PathBuf> = OnceLock::new(); SYSROOT_CACHE.get_or_init(|| { let mut rustc = Command::new(&self.initial_rustc); rustc.args(&["--print", "sysroot"]); diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 89fa2b805cd..f878d634743 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -11,11 +11,11 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::str; +use std::sync::OnceLock; use std::time::{Instant, SystemTime, UNIX_EPOCH}; use crate::core::builder::Builder; use crate::core::config::{Config, TargetSelection}; -use crate::OnceCell; pub use crate::utils::dylib::{dylib_path, dylib_path_var}; @@ -444,7 +444,7 @@ pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf { } pub fn lld_flag_no_threads(is_windows: bool) -> &'static str { - static LLD_NO_THREADS: OnceCell<(&'static str, &'static str)> = OnceCell::new(); + static LLD_NO_THREADS: OnceLock<(&'static str, &'static str)> = OnceLock::new(); let (windows, other) = LLD_NO_THREADS.get_or_init(|| { let out = output(Command::new("lld").arg("-flavor").arg("ld").arg("--version")); let newer = match (out.find(char::is_numeric), out.find('.')) { diff --git a/src/doc/unstable-book/src/compiler-flags/function-return.md b/src/doc/unstable-book/src/compiler-flags/function-return.md new file mode 100644 index 00000000000..d044a6f68aa --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/function-return.md @@ -0,0 +1,25 @@ +# `function-return` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116853. + +------------------------ + +Option `-Zfunction-return` controls how function returns are converted. + +It is equivalent to [Clang]'s and [GCC]'s `-mfunction-return`. The Linux kernel +uses it for RETHUNK builds. For details, see [LLVM commit 2240d72f15f3] ("[X86] +initial -mfunction-return=thunk-extern support") which introduces the feature. + +Supported values for this option are: + + - `keep`: do not convert function returns. + - `thunk-extern`: convert function returns (`ret`) to jumps (`jmp`) + to an external symbol called `__x86_return_thunk`. + +Like in Clang, GCC's values `thunk` and `thunk-inline` are not supported. + +Only x86 and non-large code models are supported. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mfunction-return +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mfunction-return +[LLVM commit 2240d72f15f3]: https://github.com/llvm/llvm-project/commit/2240d72f15f3b7b9d9fb65450f9bf635fd310f6f diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bed8f6ffef5..a9c0ab557cb 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -367,7 +367,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( if ending == Ending::Newline { let mut clause = " ".repeat(indent.saturating_sub(1)); - write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?; + write!(clause, "<div class=\"where\">where{where_preds},</div>")?; clause } else { // insert a newline after a single space but before multiple spaces at the start diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 51ec33bd832..e076c1b92e6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1441,15 +1441,10 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { ); } - //use the "where" class here to make it small - write!( - &mut out, - "<span class=\"where fmt-newline\">{}</span>", - impl_.print(false, cx) - ); + write!(&mut out, "<div class=\"where\">{}</div>", impl_.print(false, cx)); for it in &impl_.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { - out.push_str("<span class=\"where fmt-newline\"> "); + out.push_str("<div class=\"where\"> "); let empty_set = FxHashSet::default(); let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); assoc_type( @@ -1462,7 +1457,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { 0, cx, ); - out.push_str(";</span>"); + out.push_str(";</div>"); } } } @@ -1948,7 +1943,7 @@ pub(crate) fn render_impl_summary( if show_def_docs { for it in &inner_impl.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { - w.write_str("<span class=\"where fmt-newline\"> "); + w.write_str("<div class=\"where\"> "); assoc_type( w, it, @@ -1959,7 +1954,7 @@ pub(crate) fn render_impl_summary( 0, cx, ); - w.write_str(";</span>"); + w.write_str(";</div>"); } } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index d8250c273b0..b898eb5d381 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -703,11 +703,8 @@ pre, .rustdoc.src .example-wrap { background: var(--table-alt-row-background-color); } -/* Shift "where ..." part of method or fn definition down a line */ -.method .where, -.fn .where, -.where.fmt-newline { - display: block; +/* "where ..." clauses with block display are also smaller */ +div.where { white-space: pre-wrap; font-size: 0.875rem; } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 26333c732095d207aa05932ce863d850fb30938 +Subproject 623b788496b3e51dc2f9282373cf0f6971a229b diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index f42928c2cd1..999ee7acfe7 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -52,7 +52,9 @@ jobs: run: cargo generate-lockfile - name: Cache - uses: Swatinem/rust-cache@v1.3.0 + uses: Swatinem/rust-cache@v2.7.0 + with: + save-if: ${{ github.ref == 'refs/heads/master' }} - name: cargo collect-metadata run: cargo collect-metadata diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index e74df808e06..2e9b755caa0 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5128,6 +5128,7 @@ Released 2018-09-13 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns +[`impl_hash_borrow_with_str_and_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_hash_borrow_with_str_and_bytes [`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher @@ -5189,6 +5190,7 @@ Released 2018-09-13 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain [`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero +[`join_absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#join_absolute_paths [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups @@ -5380,6 +5382,7 @@ Released 2018-09-13 [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used [`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map [`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else +[`option_map_or_err_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_err_ok [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or @@ -5542,6 +5545,7 @@ Released 2018-09-13 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr +[`test_attr_in_doctest`]: https://rust-lang.github.io/rust-clippy/master/index.html#test_attr_in_doctest [`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display @@ -5738,4 +5742,5 @@ Released 2018-09-13 [`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow +[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items <!-- end autogenerated links to configuration documentation --> diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index 1803fc2d2f3..e30a5f9fe10 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -202,7 +202,7 @@ is. This file has already imported some initial things we will need: ```rust use rustc_lint::{EarlyLintPass, EarlyContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_ast::ast::*; ``` @@ -518,6 +518,8 @@ define_Conf! { [`clippy_config::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_config/msrvs/index.html +Afterwards update the documentation for the book as described in [Adding configuration to a lint](#adding-configuration-to-a-lint). + ## Author lint If you have trouble implementing your lint, there is also the internal `author` diff --git a/src/tools/clippy/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md index d7c2775b896..a8c9660da4c 100644 --- a/src/tools/clippy/book/src/development/type_checking.md +++ b/src/tools/clippy/book/src/development/type_checking.md @@ -119,7 +119,7 @@ an `u32`. As far as `hir::Ty` is concerned those might be different types. But a understands that they're the same type, in-depth lifetimes, etc... To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or -outside of bodies the [`TypeckResults::node_type()`][node_type] method. +the [`TypeckResults::node_type()`][node_type] method inside of bodies. > **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 841a5b6d007..2bb89321cef 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -150,6 +150,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) +* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) ## `cognitive-complexity-threshold` @@ -791,3 +792,16 @@ for _ in &mut *rmvec {} * [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop) +## `check-private-items` + + +**Default Value:** `false` + +--- +**Affected lints:** +* [`missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) +* [`unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) +* [`missing_panics_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc) +* [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) + + diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 47259776921..88611eb7087 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -249,7 +249,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] @@ -543,6 +543,10 @@ define_Conf! { /// for _ in &mut *rmvec {} /// ``` (enforce_iter_loop_reborrow: bool = false), + /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC + /// + /// Whether to also run the listed lints on private items. + (check_private_items: bool = false), } /// Search for the configuration file. diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index 011d54629d4..b3ef666e306 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -23,6 +23,7 @@ msrv_aliases! { 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } 1,55,0 { SEEK_REWIND } + 1,54,0 { INTO_KEYS } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index ddc20f7f37f..31a42734c13 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -283,7 +283,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { use clippy_utils::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; - use rustc_session::{{declare_tool_lint, impl_lint_pass}}; + use rustc_session::impl_lint_pass; "# ) @@ -292,7 +292,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { r#" {pass_import} use rustc_lint::{{{context_import}, {pass_type}}}; - use rustc_session::{{declare_lint_pass, declare_tool_lint}}; + use rustc_session::declare_lint_pass; "# ) diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs index 582423603eb..83d15c0c425 100644 --- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs @@ -5,7 +5,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs index 98299e1e4bd..39fc49dee37 100644 --- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_errors::Applicability; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index e85878eb570..57a5cd8fba8 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -5,7 +5,7 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimit use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index b4f778f12b9..409ae0c85ac 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index 9799e703afe..657d52d0e9e 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index b9dda49ca41..e052d36f115 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs index 9717aa9e981..feb6437ee26 100644 --- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs +++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs @@ -3,7 +3,7 @@ use std::fmt; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; #[derive(Clone, Copy, PartialEq, Eq)] enum AsmStyle { diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index b90914e936a..a15ec199a28 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index 71ec87a8874..aec22965b1b 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index ec2447dae96..3e5a01c45df 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 2dcaf1f0167..da38422874b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, impl_lint_pass}; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span, DUMMY_SP}; use semver::Version; @@ -120,7 +120,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for `#[deprecated]` annotations with a `since` - /// field that is not a valid semantic version. + /// field that is not a valid semantic version. Also allows "TBD" to signal + /// future deprecation. /// /// ### Why is this bad? /// For checking the version of the deprecation, it must be @@ -405,20 +406,26 @@ declare_clippy_lint! { /// Checks for `#[cfg(features = "...")]` and suggests to replace it with /// `#[cfg(feature = "...")]`. /// + /// It also checks if `cfg(test)` was misspelled. + /// /// ### Why is this bad? - /// Misspelling `feature` as `features` can be sometimes hard to spot. It + /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It /// may cause conditional compilation not work quietly. /// /// ### Example /// ```no_run /// #[cfg(features = "some-feature")] /// fn conditional() { } + /// #[cfg(tests)] + /// mod tests { } /// ``` /// /// Use instead: /// ```no_run /// #[cfg(feature = "some-feature")] /// fn conditional() { } + /// #[cfg(test)] + /// mod tests { } /// ``` #[clippy::version = "1.69.0"] pub MAYBE_MISUSED_CFG, @@ -473,7 +480,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { && let MetaItemKind::NameValue(lit) = &mi.kind && mi.has_name(sym::since) { - check_semver(cx, item.span(), lit); + check_deprecated_since(cx, item.span(), lit); } } } @@ -754,9 +761,9 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut } } -fn check_semver(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { +fn check_deprecated_since(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind { - if Version::parse(is.as_str()).is_ok() { + if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { return; } } @@ -923,21 +930,35 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { for item in items { if let NestedMetaItem::MetaItem(meta) = item { - if meta.has_name(sym!(features)) + if let Some(ident) = meta.ident() + && ident.name.as_str() == "features" && let Some(val) = meta.value_str() { span_lint_and_sugg( cx, MAYBE_MISUSED_CFG, meta.span, - "feature may misspelled as features", - "use", + "'feature' may be misspelled as 'features'", + "did you mean", format!("feature = \"{val}\""), Applicability::MaybeIncorrect, ); } if let MetaItemKind::List(list) = &meta.kind { check_nested_misused_cfg(cx, list); + // If this is not a list, then we check for `cfg(test)`. + } else if let Some(ident) = meta.ident() + && matches!(ident.name.as_str(), "tests" | "Test") + { + span_lint_and_sugg( + cx, + MAYBE_MISUSED_CFG, + meta.span, + &format!("'test' may be misspelled as '{}'", ident.name.as_str()), + "did you mean", + "test".to_string(), + Applicability::MaybeIncorrect, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 06b74b972b7..9894a163961 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Body, CoroutineKind, CoroutineSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs index 28bd3fc7011..692309629b7 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 665dbd6f708..74201e9cc30 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs index 156cb34df9c..cfb76cab6dc 100644 --- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs +++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs @@ -2,7 +2,7 @@ use clippy_utils::higher::If; use rustc_ast::LitKind; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 2cb599964d2..e11f83f2260 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index 789cd3b6c21..d3d4f3c41c8 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -8,7 +8,7 @@ use rustc_hir::{ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 9c78c6e532d..ef12fe344e4 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::IsSuggestable; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { @@ -45,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault { && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind && let ExprKind::Call(arg_path, ..) = arg.kind && !in_external_macro(cx.sess(), expr.span) - && (expr.span.eq_ctxt(arg.span) || is_vec_expn(cx, arg)) + && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) && seg.ident.name == sym::new && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) && is_default_equivalent(cx, arg) @@ -81,10 +81,10 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } } -fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span) - .next() - .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id)) +fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { + macro_backtrace(expr.span).next().map_or(false, |call| { + cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) + }) } #[derive(Default)] diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index 3a872e54c9a..fea6924d89e 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -8,7 +8,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 49a90a2f3c2..e05b8f66d86 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -27,7 +27,7 @@ use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 69fa0821e3f..92810ea2aa0 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 74ecaa60c7c..60f436dc5d2 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -10,7 +10,7 @@ use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, BytePos, Span}; diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index e5aaf88ab6c..07b02c98df1 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -18,7 +18,7 @@ use clippy_utils::sugg::Sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index 1dfc2e251d9..d0c989cfff3 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -5,7 +5,7 @@ use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Symbol; diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index 0fe973b49a3..2c23c0b4f15 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait; use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 3b6d4886ba3..d91af76f5e0 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::DefIdSet; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs index db850edd640..50fd76a3a47 100644 --- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index 637d5aae1be..d4828778be2 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -4,7 +4,7 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index 97b736dfd8f..7a3d5a07091 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index 4774917c7b5..9424a9103db 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 85854a0dfb7..b440e267efe 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -140,6 +140,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::doc::MISSING_SAFETY_DOC_INFO, crate::doc::NEEDLESS_DOCTEST_MAIN_INFO, crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO, + crate::doc::TEST_ATTR_IN_DOCTEST_INFO, crate::doc::UNNECESSARY_SAFETY_DOC_INFO, crate::double_parens::DOUBLE_PARENS_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, @@ -204,6 +205,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::if_not_else::IF_NOT_ELSE_INFO, crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO, crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO, + crate::impl_hash_with_borrow_str_and_bytes::IMPL_HASH_BORROW_WITH_STR_AND_BYTES_INFO, crate::implicit_hasher::IMPLICIT_HASHER_INFO, crate::implicit_return::IMPLICIT_RETURN_INFO, crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, @@ -376,6 +378,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_SKIP_NEXT_INFO, crate::methods::ITER_SKIP_ZERO_INFO, crate::methods::ITER_WITH_DRAIN_INFO, + crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, @@ -403,6 +406,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OK_EXPECT_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, + crate::methods::OPTION_MAP_OR_ERR_OK_INFO, crate::methods::OPTION_MAP_OR_NONE_INFO, crate::methods::OR_FUN_CALL_INFO, crate::methods::OR_THEN_UNWRAP_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index b325449c5a3..d8a070b785d 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -9,7 +9,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index b90d01b765a..9ce5acfbcc2 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index 553b670fdb7..2472e2ee76f 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index fb29703957d..64a924a776a 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -8,7 +8,7 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 8c6749a95fa..db01ff2cd22 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -3,7 +3,7 @@ use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, FieldDef, GenericArg, List}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index cbeb0050be0..854324f845b 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 9db56fa8ad0..53ef6d7e387 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::{self, Adt, AdtDef, GenericArgsRef, Ty, TypeckResults}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 64573ac4d53..61faaa10b8a 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 324b5e0798e..656b3d9bfaf 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index d23aeebb5a8..1868d3cd391 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -4,7 +4,7 @@ use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index a1dd4805b9c..09dad5554ad 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -3,7 +3,7 @@ use clippy_utils::is_test_module_or_function; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Item, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index 96a7f0e4fde..d5205e65cef 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use unicode_script::{Script, UnicodeScript}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 3578fb640fc..130f56b698f 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -5,7 +5,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs b/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs new file mode 100644 index 00000000000..01191e811b0 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs @@ -0,0 +1,20 @@ +use std::ops::Range; + +use clippy_utils::diagnostics::span_lint; +use rustc_lint::LateContext; + +use super::{Fragments, DOC_LINK_WITH_QUOTES}; + +pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) { + if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'')) + || (trimmed_text.starts_with('"') && trimmed_text.ends_with('"'))) + && let Some(span) = fragments.span(cx, range) + { + span_lint( + cx, + DOC_LINK_WITH_QUOTES, + span, + "possible intra-doc link using quotes instead of backticks", + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs new file mode 100644 index 00000000000..c0b11eb0dd1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs @@ -0,0 +1,109 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_lint::LateContext; +use rustc_span::{BytePos, Pos, Span}; +use url::Url; + +use crate::doc::DOC_MARKDOWN; + +pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) { + for word in text.split(|c: char| c.is_whitespace() || c == '\'') { + // Trim punctuation as in `some comment (see foo::bar).` + // ^^ + // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. + let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); + + // Remove leading or trailing single `:` which may be part of a sentence. + if word.starts_with(':') && !word.starts_with("::") { + word = word.trim_start_matches(':'); + } + if word.ends_with(':') && !word.ends_with("::") { + word = word.trim_end_matches(':'); + } + + if valid_idents.contains(word) || word.chars().all(|c| c == ':') { + continue; + } + + // Adjust for the current word + let offset = word.as_ptr() as usize - text.as_ptr() as usize; + let span = Span::new( + span.lo() + BytePos::from_usize(offset), + span.lo() + BytePos::from_usize(offset + word.len()), + span.ctxt(), + span.parent(), + ); + + check_word(cx, word, span); + } +} + +fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { + /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and + /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case + /// letter (`NASA` is ok). + /// Plurals are also excluded (`IDs` is ok). + fn is_camel_case(s: &str) -> bool { + if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { + return false; + } + + let s = s.strip_suffix('s').unwrap_or(s); + + s.chars().all(char::is_alphanumeric) + && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 + && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 + } + + fn has_underscore(s: &str) -> bool { + s != "_" && !s.contains("\\_") && s.contains('_') + } + + fn has_hyphen(s: &str) -> bool { + s != "-" && s.contains('-') + } + + if let Ok(url) = Url::parse(word) { + // try to get around the fact that `foo::bar` parses as a valid URL + if !url.cannot_be_a_base() { + span_lint( + cx, + DOC_MARKDOWN, + span, + "you should put bare URLs between `<`/`>` or make a proper Markdown link", + ); + + return; + } + } + + // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) + if has_underscore(word) && has_hyphen(word) { + return; + } + + if has_underscore(word) || word.contains("::") || is_camel_case(word) { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_then( + cx, + DOC_MARKDOWN, + span, + "item in documentation is missing backticks", + |diag| { + let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); + diag.span_suggestion_with_style( + span, + "try", + format!("`{snippet}`"), + applicability, + // always show the suggestion in a separate line, since the + // inline presentation adds another pair of backticks + SuggestionStyle::ShowAlways, + ); + }, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs new file mode 100644 index 00000000000..4cbfa97a8a3 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -0,0 +1,86 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{is_doc_hidden, return_ty}; +use rustc_hir::{BodyId, FnSig, OwnerId, Unsafety}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; + +pub fn check( + cx: &LateContext<'_>, + owner_id: OwnerId, + sig: &FnSig<'_>, + headers: DocHeaders, + body_id: Option<BodyId>, + panic_span: Option<Span>, + check_private_items: bool, +) { + if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) { + return; // Private functions do not require doc comments + } + + // do not lint if any parent has `#[doc(hidden)]` attribute (#7347) + if !check_private_items + && cx + .tcx + .hir() + .parent_iter(owner_id.into()) + .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) + { + return; + } + + let span = cx.tcx.def_span(owner_id); + match (headers.safety, sig.header.unsafety) { + (false, Unsafety::Unsafe) => span_lint( + cx, + MISSING_SAFETY_DOC, + span, + "unsafe function's docs miss `# Safety` section", + ), + (true, Unsafety::Normal) => span_lint( + cx, + UNNECESSARY_SAFETY_DOC, + span, + "safe function's docs have unnecessary `# Safety` section", + ), + _ => (), + } + if !headers.panics && panic_span.is_some() { + span_lint_and_note( + cx, + MISSING_PANICS_DOC, + span, + "docs for function which may panic missing `# Panics` section", + panic_span, + "first possible panic found here", + ); + } + if !headers.errors { + if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); + } else if let Some(body_id) = body_id + && let Some(future) = cx.tcx.lang_items().future_trait() + && let typeck = cx.tcx.typeck_body(body_id) + && let body = cx.tcx.hir().body(body_id) + && let ret_ty = typeck.expr_ty(body.value) + && implements_trait(cx, ret_ty, future, &[]) + && let ty::Coroutine(_, subs, _) = ret_ty.kind() + && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) + { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index ca277e7eded..ba452775015 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1,21 +1,16 @@ use clippy_utils::attrs::is_doc_hidden; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::Visitable; +use clippy_utils::{is_entrypoint_fn, method_chain_args}; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; -use rustc_ast::ast::{Async, Attribute, Fn, FnRetTy, ItemKind}; -use rustc_ast::token::CommentKind; -use rustc_ast::{AttrKind, AttrStyle}; +use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; -use rustc_errors::emitter::EmitterWriter; -use rustc_errors::{Applicability, Handler, SuggestionStyle}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Expr}; @@ -23,20 +18,21 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_parse::maybe_new_parser_from_source_str; -use rustc_parse::parser::ForceCollect; use rustc_resolve::rustdoc::{ add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment, }; -use rustc_session::parse::ParseSess; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{sym, BytePos, FileName, Pos, Span}; +use rustc_span::{sym, Span}; use std::ops::Range; -use std::{io, thread}; use url::Url; +mod link_with_quotes; +mod markdown; +mod missing_headers; +mod needless_doctest_main; +mod suspicious_doc_comments; + declare_clippy_lint! { /// ### What it does /// Checks for the presence of `_`, `::` or camel-case words @@ -205,6 +201,39 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for `#[test]` in doctests unless they are marked with + /// either `ignore`, `no_run` or `compile_fail`. + /// + /// ### Why is this bad? + /// Code in examples marked as `#[test]` will somewhat + /// surprisingly not be run by `cargo test`. If you really want + /// to show how to test stuff in an example, mark it `no_run` to + /// make the intent clear. + /// + /// ### Examples + /// ```no_run + /// /// An example of a doctest with a `main()` function + /// /// + /// /// # Examples + /// /// + /// /// ``` + /// /// #[test] + /// /// fn equality_works() { + /// /// assert_eq!(1_u8, 1); + /// /// } + /// /// ``` + /// fn test_attr_in_doctest() { + /// unimplemented!(); + /// } + /// ``` + #[clippy::version = "1.40.0"] + pub TEST_ATTR_IN_DOCTEST, + suspicious, + "presence of `#[test]` in code examples" +} + +declare_clippy_lint! { + /// ### What it does /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) /// outside of code blocks /// ### Why is this bad? @@ -309,34 +338,36 @@ declare_clippy_lint! { "suspicious usage of (outer) doc comments" } -#[expect(clippy::module_name_repetitions)] #[derive(Clone)] -pub struct DocMarkdown { +pub struct Documentation { valid_idents: FxHashSet<String>, in_trait_impl: bool, + check_private_items: bool, } -impl DocMarkdown { - pub fn new(valid_idents: &[String]) -> Self { +impl Documentation { + pub fn new(valid_idents: &[String], check_private_items: bool) -> Self { Self { valid_idents: valid_idents.iter().cloned().collect(), in_trait_impl: false, + check_private_items, } } } -impl_lint_pass!(DocMarkdown => [ +impl_lint_pass!(Documentation => [ DOC_LINK_WITH_QUOTES, DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN, + TEST_ATTR_IN_DOCTEST, UNNECESSARY_SAFETY_DOC, SUSPICIOUS_DOC_COMMENTS ]); -impl<'tcx> LateLintPass<'tcx> for DocMarkdown { +impl<'tcx> LateLintPass<'tcx> for Documentation { fn check_crate(&mut self, cx: &LateContext<'tcx>) { let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); check_attrs(cx, &self.valid_idents, attrs); @@ -351,13 +382,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { hir::ItemKind::Fn(ref sig, _, body_id) => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { let body = cx.tcx.hir().body(body_id); - let mut fpu = FindPanicUnwrap { + + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( cx, - typeck_results: cx.tcx.typeck(item.owner_id.def_id), - panic_span: None, - }; - fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); + item.owner_id, + sig, + headers, + Some(body_id), + panic_span, + self.check_private_items, + ); } }, hir::ItemKind::Impl(impl_) => { @@ -395,7 +430,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { }; if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { if !in_external_macro(cx.tcx.sess, item.span) { - lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None); + missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items); } } } @@ -410,87 +445,16 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { } if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind { let body = cx.tcx.hir().body(body_id); - let mut fpu = FindPanicUnwrap { - cx, - typeck_results: cx.tcx.typeck(item.owner_id.def_id), - panic_span: None, - }; - fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); - } - } -} - -fn lint_for_missing_headers( - cx: &LateContext<'_>, - owner_id: hir::OwnerId, - sig: &hir::FnSig<'_>, - headers: DocHeaders, - body_id: Option<hir::BodyId>, - panic_span: Option<Span>, -) { - if !cx.effective_visibilities.is_exported(owner_id.def_id) { - return; // Private functions do not require doc comments - } - // do not lint if any parent has `#[doc(hidden)]` attribute (#7347) - if cx - .tcx - .hir() - .parent_iter(owner_id.into()) - .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) - { - return; - } - - let span = cx.tcx.def_span(owner_id); - match (headers.safety, sig.header.unsafety) { - (false, hir::Unsafety::Unsafe) => span_lint( - cx, - MISSING_SAFETY_DOC, - span, - "unsafe function's docs miss `# Safety` section", - ), - (true, hir::Unsafety::Normal) => span_lint( - cx, - UNNECESSARY_SAFETY_DOC, - span, - "safe function's docs have unnecessary `# Safety` section", - ), - _ => (), - } - if !headers.panics && panic_span.is_some() { - span_lint_and_note( - cx, - MISSING_PANICS_DOC, - span, - "docs for function which may panic missing `# Panics` section", - panic_span, - "first possible panic found here", - ); - } - if !headers.errors { - if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { - span_lint( - cx, - MISSING_ERRORS_DOC, - span, - "docs for function returning `Result` missing `# Errors` section", - ); - } else if let Some(body_id) = body_id - && let Some(future) = cx.tcx.lang_items().future_trait() - && let typeck = cx.tcx.typeck_body(body_id) - && let body = cx.tcx.hir().body(body_id) - && let ret_ty = typeck.expr_ty(body.value) - && implements_trait(cx, ret_ty, future, &[]) - && let ty::Coroutine(_, subs, _) = ret_ty.kind() - && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) - { - span_lint( + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( cx, - MISSING_ERRORS_DOC, - span, - "docs for function returning `Result` missing `# Errors` section", + item.owner_id, + sig, + headers, + Some(body_id), + panic_span, + self.check_private_items, ); } } @@ -515,6 +479,13 @@ struct DocHeaders { panics: bool, } +/// Does some pre-processing on raw, desugared `#[doc]` attributes such as parsing them and +/// then delegates to `check_doc`. +/// Some lints are already checked here if they can work with attributes directly and don't need +/// to work with markdown. +/// Others are checked elsewhere, e.g. in `check_doc` if they need access to markdown, or +/// back in the various late lint pass methods if they need the final doc headers, like "Safety" or +/// "Panics" sections. fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> { /// We don't want the parser to choke on intra doc links. Since we don't /// actually care about rendering them, just pretend that all broken links @@ -528,7 +499,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ return None; } - check_almost_inner_doc(cx, attrs); + suspicious_doc_comments::check(cx, attrs); let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); let mut doc = String::new(); @@ -558,45 +529,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ )) } -/// Looks for `///!` and `/**!` comments, which were probably meant to be `//!` and `/*!` -fn check_almost_inner_doc(cx: &LateContext<'_>, attrs: &[Attribute]) { - let replacements: Vec<_> = attrs - .iter() - .filter_map(|attr| { - if let AttrKind::DocComment(com_kind, sym) = attr.kind - && let AttrStyle::Outer = attr.style - && let Some(com) = sym.as_str().strip_prefix('!') - { - let sugg = match com_kind { - CommentKind::Line => format!("//!{com}"), - CommentKind::Block => format!("/*!{com}*/"), - }; - Some((attr.span, sugg)) - } else { - None - } - }) - .collect(); - - if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { - span_lint_and_then( - cx, - SUSPICIOUS_DOC_COMMENTS, - lo_span.to(hi_span), - "this is an outer doc comment and does not apply to the parent module or crate", - |diag| { - diag.multipart_suggestion( - "use an inner doc comment to document the parent module or crate", - replacements, - Applicability::MaybeIncorrect, - ); - }, - ); - } -} - const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"]; +/// Checks parsed documentation. +/// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`, +/// so lints here will generally access that information. +/// Returns documentation headers -- whether a "Safety", "Errors", "Panic" section was found #[allow(clippy::too_many_lines)] // Only a big match statement fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>( cx: &LateContext<'_>, @@ -611,6 +549,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize let mut in_heading = false; let mut is_rust = false; let mut no_test = false; + let mut ignore = false; let mut edition = None; let mut ticks_unbalanced = false; let mut text_to_check: Vec<(CowStr<'_>, Range<usize>)> = Vec::new(); @@ -626,6 +565,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize break; } else if item == "no_test" { no_test = true; + } else if item == "no_run" || item == "compile_fail" { + ignore = true; } if let Some(stripped) = item.strip_prefix("edition") { is_rust = true; @@ -639,6 +580,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize End(CodeBlock(_)) => { in_code = false; is_rust = false; + ignore = false; }, Start(Link(_, url, _)) => in_link = Some(url), End(Link(..)) => in_link = None, @@ -665,7 +607,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize } else { for (text, range) in text_to_check { if let Some(span) = fragments.span(cx, range) { - check_text(cx, valid_idents, &text, span); + markdown::check(cx, valid_idents, &text, span); } } } @@ -692,11 +634,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize if in_code { if is_rust && !no_test { let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition()); - check_code(cx, &text, edition, range.clone(), fragments); + needless_doctest_main::check(cx, &text, edition, range.clone(), fragments, ignore); } } else { if in_link.is_some() { - check_link_quotes(cx, trimmed_text, range.clone(), fragments); + link_with_quotes::check(cx, trimmed_text, range.clone(), fragments); } if let Some(link) = in_link.as_ref() && let Ok(url) = Url::parse(link) @@ -713,208 +655,28 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize headers } -fn check_link_quotes(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) { - if trimmed_text.starts_with('\'') - && trimmed_text.ends_with('\'') - && let Some(span) = fragments.span(cx, range) - { - span_lint( - cx, - DOC_LINK_WITH_QUOTES, - span, - "possible intra-doc link using quotes instead of backticks", - ); - } -} - -fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) { - fn has_needless_main(code: String, edition: Edition) -> bool { - rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_globals_then(edition, || { - let filename = FileName::anon_source_code(&code); - - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); - let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); - #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sess = ParseSess::with_span_handler(handler, sm); - - let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { - Ok(p) => p, - Err(errs) => { - drop(errs); - return false; - }, - }; - - let mut relevant_main_found = false; - loop { - match parser.parse_item(ForceCollect::No) { - Ok(Some(item)) => match &item.kind { - ItemKind::Fn(box Fn { - sig, body: Some(block), .. - }) if item.ident.name == sym::main => { - let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); - let returns_nothing = match &sig.decl.output { - FnRetTy::Default(..) => true, - FnRetTy::Ty(ty) if ty.kind.is_unit() => true, - FnRetTy::Ty(_) => false, - }; - - if returns_nothing && !is_async && !block.stmts.is_empty() { - // This main function should be linted, but only if there are no other functions - relevant_main_found = true; - } else { - // This main function should not be linted, we're done - return false; - } - }, - // Tests with one of these items are ignored - ItemKind::Static(..) - | ItemKind::Const(..) - | ItemKind::ExternCrate(..) - | ItemKind::ForeignMod(..) - // Another function was found; this case is ignored - | ItemKind::Fn(..) => return false, - _ => {}, - }, - Ok(None) => break, - Err(e) => { - e.cancel(); - return false; - }, - } - } - - relevant_main_found - }) - }) - .ok() - .unwrap_or_default() - } - - let trailing_whitespace = text.len() - text.trim_end().len(); - - // Because of the global session, we need to create a new session in a different thread with - // the edition we need. - let text = text.to_owned(); - if thread::spawn(move || has_needless_main(text, edition)) - .join() - .expect("thread::spawn failed") - && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) - { - span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); - } -} - -fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) { - for word in text.split(|c: char| c.is_whitespace() || c == '\'') { - // Trim punctuation as in `some comment (see foo::bar).` - // ^^ - // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. - let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); - - // Remove leading or trailing single `:` which may be part of a sentence. - if word.starts_with(':') && !word.starts_with("::") { - word = word.trim_start_matches(':'); - } - if word.ends_with(':') && !word.ends_with("::") { - word = word.trim_end_matches(':'); - } - - if valid_idents.contains(word) || word.chars().all(|c| c == ':') { - continue; - } - - // Adjust for the current word - let offset = word.as_ptr() as usize - text.as_ptr() as usize; - let span = Span::new( - span.lo() + BytePos::from_usize(offset), - span.lo() + BytePos::from_usize(offset + word.len()), - span.ctxt(), - span.parent(), - ); - - check_word(cx, word, span); - } -} - -fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { - /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and - /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case - /// letter (`NASA` is ok). - /// Plurals are also excluded (`IDs` is ok). - fn is_camel_case(s: &str) -> bool { - if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { - return false; - } - - let s = s.strip_suffix('s').unwrap_or(s); - - s.chars().all(char::is_alphanumeric) - && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 - && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 - } - - fn has_underscore(s: &str) -> bool { - s != "_" && !s.contains("\\_") && s.contains('_') - } - - fn has_hyphen(s: &str) -> bool { - s != "-" && s.contains('-') - } - - if let Ok(url) = Url::parse(word) { - // try to get around the fact that `foo::bar` parses as a valid URL - if !url.cannot_be_a_base() { - span_lint( - cx, - DOC_MARKDOWN, - span, - "you should put bare URLs between `<`/`>` or make a proper Markdown link", - ); - - return; - } - } - - // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) - if has_underscore(word) && has_hyphen(word) { - return; - } - - if has_underscore(word) || word.contains("::") || is_camel_case(word) { - let mut applicability = Applicability::MachineApplicable; - - span_lint_and_then( - cx, - DOC_MARKDOWN, - span, - "item in documentation is missing backticks", - |diag| { - let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); - diag.span_suggestion_with_style( - span, - "try", - format!("`{snippet}`"), - applicability, - // always show the suggestion in a separate line, since the - // inline presentation adds another pair of backticks - SuggestionStyle::ShowAlways, - ); - }, - ); - } -} - struct FindPanicUnwrap<'a, 'tcx> { cx: &'a LateContext<'tcx>, panic_span: Option<Span>, typeck_results: &'tcx ty::TypeckResults<'tcx>, } +impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> { + pub fn find_span( + cx: &'a LateContext<'tcx>, + typeck_results: &'tcx ty::TypeckResults<'tcx>, + body: impl Visitable<'tcx>, + ) -> Option<Span> { + let mut vis = Self { + cx, + panic_span: None, + typeck_results, + }; + body.visit(&mut vis); + vis.panic_span + } +} + impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs new file mode 100644 index 00000000000..e50e83834c1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -0,0 +1,135 @@ +use std::ops::Range; +use std::{io, thread}; + +use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST}; +use clippy_utils::diagnostics::span_lint; +use rustc_ast::{Async, Fn, FnRetTy, Item, ItemKind}; +use rustc_data_structures::sync::Lrc; +use rustc_errors::emitter::EmitterWriter; +use rustc_errors::Handler; +use rustc_lint::LateContext; +use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::parser::ForceCollect; +use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; +use rustc_span::source_map::{FilePathMapping, SourceMap}; +use rustc_span::{sym, FileName, Pos}; + +use super::Fragments; + +fn get_test_spans(item: &Item, test_attr_spans: &mut Vec<Range<usize>>) { + test_attr_spans.extend( + item.attrs + .iter() + .find(|attr| attr.has_name(sym::test)) + .map(|attr| attr.span.lo().to_usize()..item.ident.span.hi().to_usize()), + ); +} + +pub fn check( + cx: &LateContext<'_>, + text: &str, + edition: Edition, + range: Range<usize>, + fragments: Fragments<'_>, + ignore: bool, +) { + // return whether the code contains a needless `fn main` plus a vector of byte position ranges + // of all `#[test]` attributes in not ignored code examples + fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) { + rustc_driver::catch_fatal_errors(|| { + rustc_span::create_session_globals_then(edition, || { + let mut test_attr_spans = vec![]; + let filename = FileName::anon_source_code(&code); + + let fallback_bundle = + rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); + let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); + let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); + #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sess = ParseSess::with_span_handler(handler, sm); + + let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { + Ok(p) => p, + Err(errs) => { + drop(errs); + return (false, test_attr_spans); + }, + }; + + let mut relevant_main_found = false; + let mut eligible = true; + loop { + match parser.parse_item(ForceCollect::No) { + Ok(Some(item)) => match &item.kind { + ItemKind::Fn(box Fn { + sig, body: Some(block), .. + }) if item.ident.name == sym::main => { + if !ignore { + get_test_spans(&item, &mut test_attr_spans); + } + let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); + let returns_nothing = match &sig.decl.output { + FnRetTy::Default(..) => true, + FnRetTy::Ty(ty) if ty.kind.is_unit() => true, + FnRetTy::Ty(_) => false, + }; + + if returns_nothing && !is_async && !block.stmts.is_empty() { + // This main function should be linted, but only if there are no other functions + relevant_main_found = true; + } else { + // This main function should not be linted, we're done + eligible = false; + } + }, + // Another function was found; this case is ignored for needless_doctest_main + ItemKind::Fn(box Fn { .. }) => { + eligible = false; + if !ignore { + get_test_spans(&item, &mut test_attr_spans); + } + }, + // Tests with one of these items are ignored + ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::ExternCrate(..) + | ItemKind::ForeignMod(..) => { + eligible = false; + }, + _ => {}, + }, + Ok(None) => break, + Err(e) => { + e.cancel(); + return (false, test_attr_spans); + }, + } + } + + (relevant_main_found & eligible, test_attr_spans) + }) + }) + .ok() + .unwrap_or_default() + } + + let trailing_whitespace = text.len() - text.trim_end().len(); + + // Because of the global session, we need to create a new session in a different thread with + // the edition we need. + let text = text.to_owned(); + let (has_main, test_attr_spans) = thread::spawn(move || check_code_sample(text, edition, ignore)) + .join() + .expect("thread::spawn failed"); + if has_main && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) { + span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); + } + for span in test_attr_spans { + let span = (range.start + span.start)..(range.start + span.end); + if let Some(span) = fragments.span(cx, span) { + span_lint(cx, TEST_ATTR_IN_DOCTEST, span, "unit tests in doctest are not executed"); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs new file mode 100644 index 00000000000..d7ad30efec3 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -0,0 +1,48 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::SUSPICIOUS_DOC_COMMENTS; + +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { + let replacements: Vec<_> = collect_doc_replacements(attrs); + + if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { + span_lint_and_then( + cx, + SUSPICIOUS_DOC_COMMENTS, + lo_span.to(hi_span), + "this is an outer doc comment and does not apply to the parent module or crate", + |diag| { + diag.multipart_suggestion( + "use an inner doc comment to document the parent module or crate", + replacements, + Applicability::MaybeIncorrect, + ); + }, + ); + } +} + +fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { + attrs + .iter() + .filter_map(|attr| { + if let AttrKind::DocComment(com_kind, sym) = attr.kind + && let AttrStyle::Outer = attr.style + && let Some(com) = sym.as_str().strip_prefix('!') + { + let sugg = match com_kind { + CommentKind::Line => format!("//!{com}"), + CommentKind::Block => format!("/*!{com}*/"), + }; + Some((attr.span, sugg)) + } else { + None + } + }) + .collect() +} diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index 63f32173b05..b51bb7951b7 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 177e04dfa6b..124d78fc4ff 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; use clippy_utils::{get_parent_node, is_must_use_func_call}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index 7ff7068f0b0..471335c098f 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind}; use rustc_errors::MultiSpan; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{FileName, Span}; use std::collections::BTreeMap; use std::path::PathBuf; diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index 61db1c1abd1..47780cab9ed 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs index 17be95780cc..e97030cc8b6 100644 --- a/src/tools/clippy/clippy_lints/src/empty_drop.rs +++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs @@ -3,7 +3,7 @@ use clippy_utils::peel_blocks; use rustc_errors::Applicability; use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index a5699727b5b..420888b6ccb 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs index 4e2a8b73c0a..3cf67b3ecbf 100644 --- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, ItemKind, VariantData}; use rustc_errors::Applicability; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs index 6f5a0cb8801..b8a817e21b1 100644 --- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Symbol; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 3e3c62e85d0..ce0a1dfdc61 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -10,7 +10,7 @@ use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 003b5fc7261..30eb643c42e 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -7,7 +7,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, IntTy, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 630df9a84f5..3c435294252 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -46,9 +46,12 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { pats.iter().all(unary_pattern) } match &pat.kind { - PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => { - false - }, + PatKind::Slice(_, _, _) + | PatKind::Range(_, _, _) + | PatKind::Binding(..) + | PatKind::Wild + | PatKind::Never + | PatKind::Or(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs index 35b1d3f9bab..8dbb47fadc5 100644 --- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs +++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Visibility; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index af2d1c27d43..ae1e69a4f23 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index e0df87e08da..450cee4007c 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; @@ -220,7 +220,8 @@ fn check_inputs( params.len() == self_arg.map_or(0, |_| 1) + args.len() && params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| { matches!( - p.pat.kind,PatKind::Binding(BindingAnnotation::NONE, id, _, None) + p.pat.kind, + PatKind::Binding(BindingAnnotation::NONE, id, _, None) if path_to_local_id(arg, id) ) // Only allow adjustments which change regions (i.e. re-borrowing). diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 713957bff51..c5f7212c4c0 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -3,7 +3,7 @@ use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool}; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::spec::abi::Abi; diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs index 83480fc5eeb..4b0d11c5d1b 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_block, walk_item, Visitor}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index b7e62e082e4..3a621d967f4 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -3,7 +3,7 @@ use clippy_utils::source::indent_of; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs index 07d025f68c3..a974c10bc7d 100644 --- a/src/tools/clippy/clippy_lints/src/exit.rs +++ b/src/tools/clippy/clippy_lints/src/exit.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_entrypoint_fn; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 08cb2114a2b..4e2e1d1724a 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, ExpnId}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index d6c746901fc..538d29eb43d 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 753f75d83a8..0446943321a 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 663c33e8cee..38a16c5c8b0 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::fmt; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index d522873472b..c8b87e510ed 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_ast::ast; @@ -496,9 +496,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { if let BinOpKind::Sub = op { -sugg } else { sugg } }; - let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) + && cx.typeck_results().expr_ty(rhs).is_floating_point() + { (inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs)) - } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { + } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) + && cx.typeck_results().expr_ty(lhs).is_floating_point() + { (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "..")) } else { return; diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 18ed05c1ca6..8a0cd155d21 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index c9868255dcf..8af321e4d55 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -19,7 +19,7 @@ use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; use rustc_span::{sym, Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index ec87629a344..9360eb1fa91 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -5,7 +5,7 @@ use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs index ac45f5aedfa..3901dd984f9 100644 --- a/src/tools/clippy/clippy_lints/src/format_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_lang_item; use clippy_utils::{higher, match_def_path, paths}; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 2ab04682f1d..c3ef6f180c9 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs index 69bc0b726fc..0599e08e6c0 100644 --- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs +++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::Item; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 5477532bb95..fa1f98ba013 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -12,7 +12,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, sym}; use rustc_span::{Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index d9138d48b2c..c8d10dc4b92 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{RawPtr, TypeAndMut}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index 18d11ccc0b5..633ed96d6a6 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index bfd73debd76..96da2ec2a1a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -9,7 +9,7 @@ mod too_many_lines; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index ded90f5f911..9fb59a320d4 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -5,7 +5,7 @@ use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 644b9cdaeb2..5e354209cbf 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -5,7 +5,7 @@ use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs index cae561f7802..4dc1ff83771 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 66c10ab228f..cd6c46a71a8 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs index 76bdfb94eb8..0a2fd0c663e 100644 --- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs @@ -3,7 +3,7 @@ use hir::{Node, PatKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs new file mode 100644 index 00000000000..940adbae428 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs @@ -0,0 +1,106 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::implements_trait; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Item, ItemKind, Path, TraitRef}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// This lint is concerned with the semantics of `Borrow` and `Hash` for a + /// type that implements all three of `Hash`, `Borrow<str>` and `Borrow<[u8]>` + /// as it is impossible to satisfy the semantics of Borrow and `Hash` for + /// both `Borrow<str>` and `Borrow<[u8]>`. + /// + /// ### Why is this bad? + /// + /// When providing implementations for `Borrow<T>`, one should consider whether the different + /// implementations should act as facets or representations of the underlying type. Generic code + /// typically uses `Borrow<T>` when it relies on the identical behavior of these additional trait + /// implementations. These traits will likely appear as additional trait bounds. + /// + /// In particular `Eq`, `Ord` and `Hash` must be equivalent for borrowed and owned values: + /// `x.borrow() == y.borrow()` should give the same result as `x == y`. + /// It follows then that the following equivalence must hold: + /// `hash(x) == hash((x as Borrow<[u8]>).borrow()) == hash((x as Borrow<str>).borrow())` + /// + /// Unfortunately it doesn't hold as `hash("abc") != hash("abc".as_bytes())`. + /// This happens because the `Hash` impl for str passes an additional `0xFF` byte to + /// the hasher to avoid collisions. For example, given the tuples `("a", "bc")`, and `("ab", "c")`, + /// the two tuples would have the same hash value if the `0xFF` byte was not added. + /// + /// ### Example + /// + /// ``` + /// use std::borrow::Borrow; + /// use std::hash::{Hash, Hasher}; + /// + /// struct ExampleType { + /// data: String + /// } + /// + /// impl Hash for ExampleType { + /// fn hash<H: Hasher>(&self, state: &mut H) { + /// self.data.hash(state); + /// } + /// } + /// + /// impl Borrow<str> for ExampleType { + /// fn borrow(&self) -> &str { + /// &self.data + /// } + /// } + /// + /// impl Borrow<[u8]> for ExampleType { + /// fn borrow(&self) -> &[u8] { + /// self.data.as_bytes() + /// } + /// } + /// ``` + /// As a consequence, hashing a `&ExampleType` and hashing the result of the two + /// borrows will result in different values. + /// + #[clippy::version = "1.76.0"] + pub IMPL_HASH_BORROW_WITH_STR_AND_BYTES, + correctness, + "ensures that the semantics of `Borrow` for `Hash` are satisfied when `Borrow<str>` and `Borrow<[u8]>` are implemented" +} + +declare_lint_pass!(ImplHashWithBorrowStrBytes => [IMPL_HASH_BORROW_WITH_STR_AND_BYTES]); + +impl LateLintPass<'_> for ImplHashWithBorrowStrBytes { + /// We are emitting this lint at the Hash impl of a type that implements all + /// three of `Hash`, `Borrow<str>` and `Borrow<[u8]>`. + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if let ItemKind::Impl(imp) = item.kind + && let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash) + && Res::Def(DefKind::Trait, hash_id) == *res + && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow) + // since we are in the `Hash` impl, we don't need to check for that. + // we need only to check for `Borrow<str>` and `Borrow<[u8]>` + && implements_trait(cx, ty, borrow_id, &[cx.tcx.types.str_.into()]) + && implements_trait(cx, ty, borrow_id, &[Ty::new_slice(cx.tcx, cx.tcx.types.u8).into()]) + { + span_lint_and_then( + cx, + IMPL_HASH_BORROW_WITH_STR_AND_BYTES, + *span, + "the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented", + |diag| { + diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T>"); + diag.note( + "however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ..." + ); + diag.note("... as (`hash(\"abc\") != hash(\"abc\".as_bytes())`"); + diag.help("consider either removing one of the `Borrow` implementations (`Borrow<str>` or `Borrow<[u8]>`) ..."); + diag.help("... or not implementing `Hash` for this type"); + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 6594636d884..43eb6a9b838 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -9,7 +9,7 @@ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index c6bcf3ba40c..d68c5c4bac6 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, SyntaxContext}; diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index f2fac9a29cb..cc74844f294 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index fc66f86ae86..81df1a889c7 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 232d8eeb11b..9a66cbde53c 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.74.0"] pub IMPLIED_BOUNDS_IN_IMPLS, - nursery, + complexity, "specifying bounds that are implied by other bounds in `impl Trait` type" } declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]); diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index f6e1281a291..1075975f0a2 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use std::fmt::{self, Write as _}; diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index fa6536db796..b6f9d8b81f8 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 1ce7d85d382..0ae03d101ab 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index e9c53671a93..9ad02735878 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -3,7 +3,7 @@ use clippy_utils::higher; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::{sym, Symbol}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index aa732980b1f..5c926133c42 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use std::collections::hash_map::Entry; diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index fe5eb5ccac5..ca2ac60306b 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use rustc_target::spec::abi::Abi; diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs index 269311a67d6..e486563808a 100644 --- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::borrow::Cow; use std::cmp::Reverse; use std::collections::BinaryHeap; diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 899126565f7..bc236c5c71f 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 8e84c73666f..655f4b82aa4 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -6,7 +6,7 @@ use clippy_utils::ty; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs index 9ffcee07d28..b8e0eef7c7e 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs index de82935e66b..8bcd9b532bd 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -2,7 +2,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, IntTy, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::comparisons; diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 2b131d27b7b..b6aacba2517 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -6,7 +6,7 @@ use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index 9605d76fbf0..39223c20470 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Block, ItemKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs index 35e01862cee..3614fb8cc96 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -4,7 +4,7 @@ use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::hygiene::AstPass; use rustc_span::{sym, ExpnKind}; diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index fce3b0e18b7..b9fad726511 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs index 7755adc4c1d..8110c1970d9 100644 --- a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs +++ b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs @@ -7,7 +7,7 @@ use clippy_utils::paths::{ }; use clippy_utils::ty::is_type_diagnostic_item; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 3c291f25590..3a5756482a1 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; use std::iter; diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 7db088f986f..b561054b582 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -4,7 +4,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index 0bf9b8718cd..6feb1885576 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -8,7 +8,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Adt, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index 26a7278524e..eb7570e9b44 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_target::abi::Size; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 902b72ba5e4..1b5981ecc28 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -4,7 +4,7 @@ use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 5e312ab7240..fd33ba91bfd 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -4,7 +4,7 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index 33636eb687f..b397180a69c 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 8c6ef81cced..e121da776b2 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index da269ec61ff..270162ae771 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{BindingAnnotation, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 04f23a213f2..606c2ed72be 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{GenericArgKind, IsSuggestable}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index d4f410de957..5f3f9b43f45 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index c462c933082..1c59b2df853 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -144,6 +144,7 @@ mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; mod ignored_unit_patterns; +mod impl_hash_with_borrow_str_and_bytes; mod implicit_hasher; mod implicit_return; mod implicit_saturating_add; @@ -562,6 +563,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { vec_box_size_threshold, verbose_bit_mask_threshold, warn_on_all_wildcard_imports, + check_private_items, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -745,7 +747,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { avoid_breaking_exported_api, )) }); - store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents))); + store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); @@ -1066,6 +1068,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType)); + store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index bb0edec3373..17ca48683b3 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs index 0a5f5a80cb7..8a0955147bb 100644 --- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { @@ -53,18 +53,45 @@ declare_clippy_lint! { #[clippy::version = "1.70.0"] pub LINES_FILTER_MAP_OK, suspicious, - "filtering `std::io::Lines` with `filter_map()` or `flat_map()` might cause an infinite loop" + "filtering `std::io::Lines` with `filter_map()`, `flat_map()`, or `flatten()` might cause an infinite loop" } declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind + if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind && is_trait_method(cx, expr, sym::Iterator) - && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") + && let fm_method_str = fm_method.ident.as_str() + && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) + && should_lint(cx, fm_args, fm_method_str) { - let lint = match &fm_arg.kind { + span_lint_and_then( + cx, + LINES_FILTER_MAP_OK, + fm_span, + &format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), + |diag| { + diag.span_note( + fm_receiver.span, + "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); + diag.span_suggestion( + fm_span, + "replace with", + "map_while(Result::ok)", + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} + +fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool { + match args { + [] => method_str == "flatten", + [fm_arg] => { + match &fm_arg.kind { // Detect `Result::ok` ExprKind::Path(qpath) => cx .qpath_res(qpath, fm_arg.hir_id) @@ -86,29 +113,8 @@ impl LateLintPass<'_> for LinesFilterMapOk { } }, _ => false, - }; - if lint { - span_lint_and_then( - cx, - LINES_FILTER_MAP_OK, - fm_span, - &format!( - "`{}()` will run forever if the iterator repeatedly produces an `Err`", - fm_method.ident - ), - |diag| { - diag.span_note( - fm_receiver.span, - "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); - diag.span_suggestion( - fm_span, - "replace with", - "map_while(Result::ok)", - Applicability::MaybeIncorrect, - ); - }, - ); } - } + }, + _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 8f34a9b1fed..f33151cf4c5 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -9,7 +9,7 @@ use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use std::iter; diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 67c80fb8387..892336878c7 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -24,7 +24,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index d860b297a02..4773a1454b7 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -1,6 +1,6 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, snippet_with_applicability}; +use clippy_utils::source::{indent_of, snippet, snippet_with_applicability}; use clippy_utils::visitors::contains_break_or_continue; use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; @@ -87,14 +87,29 @@ pub(super) fn check<'tcx>( arg_snip = format!("({arg_snip})").into(); } - span_lint_and_sugg( - cx, - SINGLE_ELEMENT_LOOP, - expr.span, - "for loop over a single element", - "try", - format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), - applicability, - ); + if clippy_utils::higher::Range::hir(arg_expression).is_some() { + let range_expr = snippet(cx, arg_expression.span, "?").to_string(); + + let sugg = snippet(cx, arg_expression.span, ".."); + span_lint_and_sugg( + cx, + SINGLE_ELEMENT_LOOP, + arg.span, + format!("this loops only once with `{pat_snip}` being `{range_expr}`").as_str(), + "did you mean to iterate over the range instead?", + sugg.to_string(), + Applicability::Unspecified, + ); + } else { + span_lint_and_sugg( + cx, + SINGLE_ELEMENT_LOOP, + expr.span, + "for loop over a single element", + "try", + format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), + applicability, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 9b2e02058a6..8d3e7520a54 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -2,13 +2,14 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::{sym, Span}; +use std::collections::BTreeMap; declare_clippy_lint! { /// ### What it does @@ -136,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } } fn check_crate_post(&mut self, cx: &LateContext<'_>) { - let mut used = FxHashMap::default(); + let mut used = BTreeMap::new(); let mut check_dup = vec![]; for (import, span, hir_id) in &self.imports { let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name)); @@ -185,20 +186,16 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } } - let mut suggestions = vec![]; - for ((root, span, hir_id), path) in used { - if path.len() == 1 { - suggestions.push((span, format!("{root}::{}", path[0]), hir_id)); - } else { - suggestions.push((span, format!("{root}::{{{}}}", path.join(", ")), hir_id)); - } - } - // If mac_refs is not empty we have encountered an import we could not handle // such as `std::prelude::v1::foo` or some other macro that expands to an import. if self.mac_refs.is_empty() { - for (span, import, hir_id) in suggestions { - let help = format!("use {import};"); + for ((root, span, hir_id), path) in used { + let import = if let [single] = &path[..] { + format!("{root}::{single}") + } else { + format!("{root}::{{{}}}", path.join(", ")) + }; + span_lint_hir_and_then( cx, MACRO_USE_IMPORTS, @@ -209,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { diag.span_suggestion( *span, "remove the attribute and import the macro directly, try", - help, + format!("use {import};"), Applicability::MaybeIncorrect, ); }, diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs index ea1d25d80e1..a381b35cf2e 100644 --- a/src/tools/clippy/clippy_lints/src/main_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index 9a3da975f83..4f6a2cf017c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index a5d91c949bc..ee053ffe4ec 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -7,7 +7,7 @@ use rustc_hir::{ ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -187,14 +187,11 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) } fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, String)> { - match output.kind { - TyKind::Tup(tys) if tys.is_empty() => { - let sugg = "remove the return type"; - Some((sugg, String::new())) - }, - _ => { - let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) - }, + if let TyKind::Tup([]) = output.kind { + let sugg = "remove the return type"; + Some((sugg, String::new())) + } else { + let sugg = "return the output of the future directly"; + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) } } diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 69c65cf305c..96c652283da 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 09c90e38e11..385fe387a31 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -14,7 +14,7 @@ use rustc_hir::def::Res; use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; use std::ops::Deref; diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 0c4101ceb6b..31cfb41640d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index 472b4eb9006..252b3a83a18 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -6,7 +6,7 @@ use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 468f4170732..e433c5a3b32 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -8,7 +8,7 @@ use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 01eccb56a0a..92dc4d57ab1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::declare_tool_lint; + use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::slice; diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs index 23f47c86fcc..5732bdda7f2 100644 --- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 79cc98bfb7f..545b122930e 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{sym, Span}; @@ -118,7 +118,6 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { if let Some(Ok(field)) = iter.next() && iter.next().is_none() && field.ty.kind.is_unit() - && field.ident.map_or(true, |name| name.as_str().starts_with('_')) { span_lint_and_then( cx, @@ -158,7 +157,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { { let mut iter = def.variants.iter().filter_map(|v| { (matches!(v.data, hir::VariantData::Unit(_, _)) - && v.ident.as_str().starts_with('_') && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) .then_some((v.def_id, v.span)) @@ -173,9 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind - && let [.., name] = p.segments && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res - && name.ident.as_str().starts_with('_') { let variant_id = cx.tcx.parent(id); let enum_id = cx.tcx.parent(variant_id); diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index d24bfe18224..d585290f777 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{Span, DUMMY_SP}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index bc8372fbd41..e006df7d666 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 2f8682d0418..1fe247dacb9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; const ACCEPTABLE_METHODS: [&[&str]; 5] = [ diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs index 3b97d165998..1de686dbcb5 100644 --- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs +++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index f8afae0e1f5..737c70496c2 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability::MachineApplicable; use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, symbol, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index b41bf2d767e..7b04fd28b89 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -10,7 +10,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 147e72ea894..3b82c50a84e 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs index bf035969477..62cedc8847b 100644 --- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs @@ -5,7 +5,7 @@ use clippy_utils::{higher, is_res_lang_ctor}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index cbf478620ec..c823d07e2bd 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; use core::cmp::Ordering; @@ -104,9 +104,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { if !cx.tcx.features().non_exhaustive_omitted_patterns_lint || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) { - span_lint_and_then( + span_lint_hir_and_then( cx, MATCH_SAME_ARMS, + arm1.hir_id, arm1.span, "this match arm has an identical body to the `_` wildcard arm", |diag| { @@ -124,9 +125,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { (arm2, arm1) }; - span_lint_and_then( + span_lint_hir_and_then( cx, MATCH_SAME_ARMS, + keep_arm.hir_id, keep_arm.span, "this match arm has an identical body to another arm", |diag| { @@ -222,7 +224,7 @@ fn iter_matching_struct_fields<'a>( Iter(left.iter(), right.iter()) } -#[expect(clippy::similar_names)] +#[expect(clippy::similar_names, clippy::too_many_lines)] impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { @@ -334,8 +336,7 @@ impl<'a> NormalizedPat<'a> { /// type. fn has_overlapping_values(&self, other: &Self) -> bool { match (*self, *other) { - (Self::Wild, _) | (_, Self::Wild) => true, - (Self::Never, Self::Never) => true, + (Self::Wild, _) | (_, Self::Wild) | (Self::Never, Self::Never) => true, (Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => { pats.iter().any(|pat| pat.has_overlapping_values(other)) }, diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index dea46d4d360..4c7568f39b4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -31,7 +31,7 @@ use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::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_session::impl_lint_pass; use rustc_span::{Span, SpanData, SyntaxContext}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 4a44d596a46..f57b22374c8 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr, is_local_used}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; @@ -8,7 +8,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; +use std::borrow::Cow; use std::ops::ControlFlow; use super::REDUNDANT_GUARDS; @@ -41,7 +42,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => arm.pat.span, }; - emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard); + emit_redundant_guards( + cx, + outer_arm, + if_expr.span, + snippet(cx, pat_span, "<binding>"), + &binding, + arm.guard, + ); } // `Some(x) if let Some(2) = x` else if let Guard::IfLet(let_expr) = guard @@ -52,7 +60,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => let_expr.pat.span, }; - emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None); + emit_redundant_guards( + cx, + outer_arm, + let_expr.span, + snippet(cx, pat_span, "<binding>"), + &binding, + None, + ); } // `Some(x) if x == Some(2)` // `Some(x) if Some(2) == x` @@ -78,11 +93,76 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (ExprKind::AddrOf(..), None) | (_, Some(_)) => continue, _ => pat.span, }; - emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None); + emit_redundant_guards( + cx, + outer_arm, + if_expr.span, + snippet(cx, pat_span, "<binding>"), + &binding, + None, + ); + } else if let Guard::If(if_expr) = guard + && let ExprKind::MethodCall(path, recv, args, ..) = if_expr.kind + && let Some(binding) = get_pat_binding(cx, recv, outer_arm) + { + check_method_calls(cx, outer_arm, path.ident.name, recv, args, if_expr, &binding); } } } +fn check_method_calls<'tcx>( + cx: &LateContext<'tcx>, + arm: &Arm<'tcx>, + method: Symbol, + recv: &Expr<'_>, + args: &[Expr<'_>], + if_expr: &Expr<'_>, + binding: &PatBindingInfo, +) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + let slice_like = ty.is_slice() || ty.is_array(); + + let sugg = if method == sym!(is_empty) { + // `s if s.is_empty()` becomes "" + // `arr if arr.is_empty()` becomes [] + + if ty.is_str() { + r#""""#.into() + } else if slice_like { + "[]".into() + } else { + return; + } + } else if slice_like + && let Some(needle) = args.first() + && let ExprKind::AddrOf(.., needle) = needle.kind + && let ExprKind::Array(needles) = needle.kind + && needles.iter().all(|needle| expr_can_be_pat(cx, needle)) + { + // `arr if arr.starts_with(&[123])` becomes [123, ..] + // `arr if arr.ends_with(&[123])` becomes [.., 123] + // `arr if arr.starts_with(&[])` becomes [..] (why would anyone write this?) + + let mut sugg = snippet(cx, needle.span, "<needle>").into_owned(); + + if needles.is_empty() { + sugg.insert_str(1, ".."); + } else if method == sym!(starts_with) { + sugg.insert_str(sugg.len() - 1, ", .."); + } else if method == sym!(ends_with) { + sugg.insert_str(1, ".., "); + } else { + return; + } + + sugg.into() + } else { + return; + }; + + emit_redundant_guards(cx, arm, if_expr.span, sugg, binding, None); +} + struct PatBindingInfo { span: Span, byref_ident: Option<Ident>, @@ -134,19 +214,16 @@ fn emit_redundant_guards<'tcx>( cx: &LateContext<'tcx>, outer_arm: &Arm<'tcx>, guard_span: Span, - pat_span: Span, + binding_replacement: Cow<'static, str>, pat_binding: &PatBindingInfo, inner_guard: Option<Guard<'_>>, ) { - let mut app = Applicability::MaybeIncorrect; - span_lint_and_then( cx, REDUNDANT_GUARDS, guard_span.source_callsite(), "redundant guard", |diag| { - let binding_replacement = snippet_with_applicability(cx, pat_span, "<binding_repl>", &mut app); let suggestion_span = match *pat_binding { PatBindingInfo { span, @@ -170,14 +247,11 @@ fn emit_redundant_guards<'tcx>( Guard::IfLet(l) => ("if let", l.span), }; - format!( - " {prefix} {}", - snippet_with_applicability(cx, span, "<guard>", &mut app), - ) + format!(" {prefix} {}", snippet(cx, span, "<guard>")) }), ), ], - app, + Applicability::MaybeIncorrect, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 1517223ab9a..c22f76484d0 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index c5dbb6ad98b..e1b934d36ea 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] use super::ITER_KV_MAP; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; @@ -21,7 +22,11 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v + msrv: &Msrv, ) { + if map_type == "into_iter" && !msrv.meets(msrvs::INTO_KEYS) { + return; + } if !expr.span.from_expansion() && let ExprKind::Closure(c) = m_arg.kind && let Body { diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs new file mode 100644 index 00000000000..02f28779cf6 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::expr_or_init; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use rustc_span::Span; + +use super::JOIN_ABSOLUTE_PATHS; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if (is_type_diagnostic_item(cx, ty, sym::Path) || is_type_diagnostic_item(cx, ty, sym::PathBuf)) + && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind + && let LitKind::Str(symbol, _) = spanned.node + && let sym_str = symbol.as_str() + && sym_str.starts_with(['/', '\\']) + { + span_lint_and_then( + cx, + JOIN_ABSOLUTE_PATHS, + join_arg.span, + "argument to `Path::join` starts with a path separator", + |diag| { + let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string()); + + let no_separator = if sym_str.starts_with('/') { + arg_str.replacen('/', "", 1) + } else { + arg_str.replacen('\\', "", 1) + }; + + diag.note("joining a path starting with separator will replace the path instead") + .span_suggestion( + spanned.span, + "if this is unintentional, try removing the starting separator", + no_separator, + Applicability::Unspecified, + ) + .span_suggestion( + expr_span, + "if this is intentional, try using `Path::new` instead", + format!("PathBuf::from({arg_str})"), + Applicability::Unspecified, + ); + }, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index 51145afda7f..f93edded729 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -1,14 +1,14 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_from_proc_macro, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::MANUAL_TRY_FOLD; @@ -22,6 +22,7 @@ pub(super) fn check<'tcx>( ) { if !in_external_macro(cx.sess(), fold_span) && msrv.meets(msrvs::ITERATOR_TRY_FOLD) + && is_trait_method(cx, expr, sym::Iterator) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() && implements_trait(cx, init_ty, try_trait, &[]) diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index cb81b3919bf..52ea584a2c8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs @@ -44,11 +44,9 @@ pub(super) fn check<'tcx>( // lint message let msg = if is_option { - "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling \ - `map_or_else(<g>, <f>)` instead" + "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value" } else { - "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" + "called `map(<f>).unwrap_or_else(<g>)` on a `Result` value" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_arg.span, ".."); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 31d44bc1b3f..25c681bb9d9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -49,6 +49,7 @@ mod iter_skip_next; mod iter_skip_zero; mod iter_with_drain; mod iterator_step_by_zero; +mod join_absolute_paths; mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; @@ -69,6 +70,7 @@ mod obfuscated_if_else; mod ok_expect; mod open_options; mod option_as_ref_deref; +mod option_map_or_err_ok; mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; @@ -80,6 +82,7 @@ mod read_line_without_trim; mod readonly_write_lock; mod redundant_as_str; mod repeat_once; +mod result_map_or_else_none; mod search_is_some; mod seek_from_current; mod seek_to_start_instead_of_rewind; @@ -130,7 +133,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -3609,7 +3612,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself. + /// Checks for usage of `as_str()` on a `String` chained with a method available on the `String` itself. /// /// ### Why is this bad? /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. @@ -3618,14 +3621,16 @@ declare_clippy_lint! { /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_str().as_bytes(); + /// owned_string.as_str().as_bytes() + /// # ; /// ``` /// /// Use instead: /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_bytes(); + /// owned_string.as_bytes() + /// # ; /// ``` #[clippy::version = "1.74.0"] pub REDUNDANT_AS_STR, @@ -3682,6 +3687,71 @@ declare_clippy_lint! { "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `Path::join` that start with a path separator (`\\` or `/`). + /// + /// ### Why is this bad? + /// If the argument to `Path::join` starts with a separator, it will overwrite + /// the original path. If this is intentional, prefer using `Path::new` instead. + /// + /// Note the behavior is platform dependent. A leading `\\` will be accepted + /// on unix systems as part of the file name + /// + /// See [`Path::join`](https://doc.rust-lang.org/std/path/struct.Path.html#method.join) + /// + /// ### Example + /// ```rust + /// # use std::path::{Path, PathBuf}; + /// let path = Path::new("/bin"); + /// let joined_path = path.join("/sh"); + /// assert_eq!(joined_path, PathBuf::from("/sh")); + /// ``` + /// + /// Use instead; + /// ```rust + /// # use std::path::{Path, PathBuf}; + /// let path = Path::new("/bin"); + /// + /// // If this was unintentional, remove the leading separator + /// let joined_path = path.join("sh"); + /// assert_eq!(joined_path, PathBuf::from("/bin/sh")); + /// + /// // If this was intentional, create a new path instead + /// let new = Path::new("/sh"); + /// assert_eq!(new, PathBuf::from("/sh")); + /// ``` + #[clippy::version = "1.76.0"] + pub JOIN_ABSOLUTE_PATHS, + suspicious, + "calls to `Path::join` which will overwrite the original path" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `_.map_or(Err(_), Ok)`. + /// + /// ### Why is this bad? + /// Readability, this can be written more concisely as + /// `_.ok_or(_)`. + /// + /// ### Example + /// ```no_run + /// # let opt = Some(1); + /// opt.map_or(Err("error"), Ok); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let opt = Some(1); + /// opt.ok_or("error"); + /// ``` + #[clippy::version = "1.76.0"] + pub OPTION_MAP_OR_ERR_OK, + style, + "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3831,6 +3901,8 @@ impl_lint_pass!(Methods => [ REDUNDANT_AS_STR, WAKER_CLONE_WAKE, UNNECESSARY_FALLIBLE_CONVERSIONS, + JOIN_ABSOLUTE_PATHS, + OPTION_MAP_OR_ERR_OK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4233,6 +4305,8 @@ impl Methods { ("join", [join_arg]) => { if let Some(("collect", _, _, span, _)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); + } else { + join_absolute_paths::check(cx, recv, join_arg, expr.span); } }, ("last", []) => { @@ -4255,7 +4329,7 @@ impl Methods { map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { - iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv); }, Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, @@ -4288,6 +4362,10 @@ impl Methods { ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); + option_map_or_err_ok::check(cx, expr, recv, def, map); + }, + ("map_or_else", [def, map]) => { + result_map_or_else_none::check(cx, expr, recv, def, map); }, ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 79ed5515ea2..293b4981c55 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -225,7 +225,10 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let sig = cx.tcx.fn_sig(id).instantiate_identity() && sig.skip_binder().output().is_bool() && let [_, search_ty] = *sig.skip_binder().inputs() - && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.instantiate_bound_regions_with_erased(sig.rebind(search_ty)).kind() + && let ty::Ref(_, search_ty, Mutability::Not) = *cx + .tcx + .instantiate_bound_regions_with_erased(sig.rebind(search_ty)) + .kind() && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind( cx.tcx, diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 15111006133..756dbe62d84 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -99,10 +99,7 @@ pub(super) fn check( let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); let suggestion = format!("try using {method_hint} instead"); - let msg = format!( - "called `{current_method}` on an Option value. This can be done more directly \ - by calling `{hint}` instead" - ); + let msg = format!("called `{current_method}` on an `Option` value"); span_lint_and_sugg( cx, OPTION_AS_REF_DEREF, diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs new file mode 100644 index 00000000000..91e39d5a1cd --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res}; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::OPTION_MAP_OR_ERR_OK; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'_>, + or_expr: &'tcx Expr<'_>, + map_expr: &'tcx Expr<'_>, +) { + // We check that it's called on an `Option` type. + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) + // We check that first we pass an `Err`. + && let ExprKind::Call(call, &[arg]) = or_expr.kind + && is_res_lang_ctor(cx, path_res(cx, call), ResultErr) + // And finally we check that it is mapped as `Ok`. + && is_res_lang_ctor(cx, path_res(cx, map_expr), ResultOk) + { + let msg = "called `map_or(Err(_), Ok)` on an `Option` value"; + let self_snippet = snippet(cx, recv.span, ".."); + let err_snippet = snippet(cx, arg.span, ".."); + span_lint_and_sugg( + cx, + OPTION_MAP_OR_ERR_OK, + expr.span, + msg, + "try using `ok_or` instead", + format!("{self_snippet}.ok_or({err_snippet})"), + Applicability::MachineApplicable, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs index 418e6a7d6a0..ff4d8cc9e3e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs @@ -66,8 +66,7 @@ pub(super) fn check<'tcx>( && Some(id) == cx.tcx.lang_items().option_some_variant() { let func_snippet = snippet(cx, arg_char.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `map(..)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value"; return span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, @@ -80,8 +79,7 @@ pub(super) fn check<'tcx>( } let func_snippet = snippet(cx, map_arg.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `and_then(..)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value"; span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, @@ -92,8 +90,7 @@ pub(super) fn check<'tcx>( Applicability::MachineApplicable, ); } else if f_arg_is_some { - let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ - `ok()` instead"; + let msg = "called `map_or(None, Some)` on a `Result` value"; let self_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index c78f8b71c78..575c2d8f157 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -97,10 +97,7 @@ pub(super) fn check<'tcx>( } else { "map_or(<a>, <f>)" }; - let msg = &format!( - "called `map(<f>).unwrap_or({arg})` on an `Option` value. \ - This can be done more directly by calling `{suggest}` instead" - ); + let msg = &format!("called `map(<f>).unwrap_or({arg})` on an `Option` value"); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_arg.span; diff --git a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs new file mode 100644 index 00000000000..bc16a112816 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs @@ -0,0 +1,42 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::RESULT_MAP_OR_INTO_OPTION; + +/// lint use of `_.map_or_else(|_| None, Some)` for `Result`s +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + def_arg: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, +) { + // lint if the caller of `map_or_else()` is a `Result` + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) + // We check that it is mapped as `Some`. + && is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome) + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind + && let body = cx.tcx.hir().body(body) + // And finally we check that we return a `None` in the "else case". + && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone) + { + let msg = "called `map_or_else(|_| None, Some)` on a `Result` value"; + let self_snippet = snippet(cx, recv.span, ".."); + span_lint_and_sugg( + cx, + RESULT_MAP_OR_INTO_OPTION, + expr.span, + msg, + "try using `ok` instead", + format!("{self_snippet}.ok()"), + Applicability::MachineApplicable, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index 4ad12e899fe..f5b749c7f80 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_item, Visitor}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index e0904f17b8d..fca626fa5c3 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_trait_method; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::cmp::Ordering; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 814fc3303b0..b9784a58596 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index df0dd9e4e39..abe5b00e888 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -16,7 +16,7 @@ use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs index c74d0d623df..0739b49fe19 100644 --- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs +++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{GenericArg, Item, ItemKind, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::GenericParamDefKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs index 4e00215c5cb..04df7b7a7e5 100644 --- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs +++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs @@ -3,7 +3,7 @@ use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_cal use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index ff2792faf57..8f2a5390781 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -9,9 +9,9 @@ use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::{Applicability, Diagnostic}; -use rustc_hir::{BinOp, Block, Expr, ExprKind, UnOp}; +use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::{sym, Span}; @@ -390,10 +390,10 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>> } impl LateLintPass<'_> for MissingAssertsForIndexing { - fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { + fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { let mut map = UnhashMap::default(); - for_each_expr(block, |expr| { + for_each_expr(body.value, |expr| { check_index(cx, expr, &mut map); check_assert(cx, expr, &mut map); ControlFlow::<!, ()>::Continue(()) diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 496bae583f1..5f736898159 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index b5a884f7c8b..bf4af7946f4 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs index f7e42815104..c1f6c71a63e 100644 --- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs +++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Item, ItemKind, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Symbol; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 95f9df4e42a..8be45b8c2f3 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -12,7 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index b815da79b69..07bcbfc4ff4 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index ad5f45a3280..6bbf18d52d1 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefIdMap; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocItem; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index e5ebdc14510..cd180754113 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs index cd45467407e..0226b31dd19 100644 --- a/src/tools/clippy/clippy_lints/src/module_style.rs +++ b/src/tools/clippy/clippy_lints/src/module_style.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{FileName, SourceFile, Span, SyntaxContext}; use std::ffi::OsStr; diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs index b42dce7a13a..9a6b1dfc52b 100644 --- a/src/tools/clippy/clippy_lints/src/multi_assignments.rs +++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index d4f8008aece..049f44f3246 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 454fc6f5642..04d2ced6abf 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; use rustc_middle::ty::{Adt, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; @@ -143,7 +143,11 @@ impl MutableKeyType { for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { self.check_ty_(cx, hir_ty.span, *ty); } - self.check_ty_(cx, decl.output.span(), cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output())); + self.check_ty_( + cx, + decl.output.span(), + cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output()), + ); } // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 6989504a4a9..72a2cca1e40 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -5,7 +5,7 @@ use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 4f8e244222d..f905a4e5b64 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::iter; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index dea432fdbd5..96cd81ecdf3 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -5,7 +5,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 9d8c06cd077..a23e12f7a18 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -7,7 +7,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 1712262ff3e..2ab83f733cb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 02c177c9227..218ca5e80f3 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -13,7 +13,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs index fdb91f0dc0d..4710a69443b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f25475aaa8e..85166b0dd95 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::{ self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamTy, ProjectionPredicate, Ty, }; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 6803034f475..4b9ab50e4fd 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -37,7 +37,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs index d881c13f84a..b6aad69d166 100644 --- a/src/tools/clippy/clippy_lints/src/needless_else.rs +++ b/src/tools/clippy/clippy_lints/src/needless_else.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, trim_span}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 70571d18e78..84a07df1bb0 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -2,7 +2,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; use clippy_utils::diagnostics::span_lint_and_then; diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 1ed7ea6b325..41d05d72284 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 0a95678d31a..3e63c0a1d36 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -10,7 +10,7 @@ use rustc_hir::{ StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs index 490c3f9c1ab..8a62106377c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index f4ccd26631f..13b736cd9ad 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -17,7 +17,7 @@ use rustc_middle::hir::map::associated_body; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 5442463bbf5..27da44812eb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -17,7 +17,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 7ec0879ba38..a4d3aaf0de9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index f8888d36878..6a2893cefbd 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 30aed8cc04a..f7621822b66 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index a6adb7c8a5f..f84d9fadb85 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -6,7 +6,7 @@ use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 2f6aebae4f5..9de6ad42137 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index de8bb123e9b..6e65dd628a4 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::ops::Deref; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index 04d75014892..8d5a523fd8f 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi; diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 9689f63a013..63050080ac6 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use rustc_span::symbol::kw; diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 3059eb25d29..4f8922aea17 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::query::Key; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::VariantIdx; diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 649a23565a9..70b7ef1a5ea 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -5,7 +5,7 @@ use rustc_ast::ast::{ use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, Span}; use std::cmp::Ordering; diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index 6cfcc81025d..49e9e2c00cc 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -4,7 +4,7 @@ use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index d07a9da55a2..352540d70b5 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -8,7 +8,7 @@ use rustc_hir::{FieldDef, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index 1c6a8e16ae2..1c6069e9c65 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 0faf4ce3d3e..8822dfeeddd 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -4,7 +4,7 @@ use rustc_ast::token::{Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use std::fmt::Write; diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index ef7b367649f..d621051ef16 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -8,7 +8,7 @@ use rustc_hir::hir_id::HirIdMap; use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use std::iter; diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs index fd3502ad878..01dd418c38b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs @@ -36,7 +36,7 @@ pub(crate) fn check<'tcx>( left: &'tcx Expr<'_>, right: &'tcx Expr<'_>, ) { - if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { + if is_useless_with_eq_exprs(op) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { span_lint_and_then( cx, EQ_OP, diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs index 5eabb349ec1..fecc5a8578e 100644 --- a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -46,7 +46,7 @@ fn lint_misrefactored_assign_op( if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); - let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r)); + let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r)); diag.span_suggestion( expr.span, format!( diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index ee79ea27689..4c09c4eea58 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -25,7 +25,7 @@ pub(crate) mod arithmetic_side_effects; use rustc_hir::{Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs index 7792efe6acd..4bfb26209d2 100644 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_direct_expn_of; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index 6e4e0c98d29..89e4e3c740d 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::SyntaxContext; declare_clippy_lint! { @@ -239,21 +239,24 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> if_then, if_else: Some(if_else), }) = higher::IfLet::hir(cx, expr) + && !cx.typeck_results().expr_ty(expr).is_unit() + && !is_else_clause(cx.tcx, expr) { - if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else); - } + try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else) + } else { + None } - None } fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurrence> { - if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { - if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else); - } + if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind + && !cx.typeck_results().expr_ty(expr).is_unit() + && let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) + { + try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else) + } else { + None } - None } fn try_convert_match<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs index e661bfbb96c..de789879331 100644 --- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs +++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::SpanlessEq; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index f4dc80d744a..f821a4efee7 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -7,7 +7,7 @@ use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index f4f1f6ddb3f..ef51a9a9a1c 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs index 99ba55b6b31..ffa403e27ca 100644 --- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs +++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Item, ItemKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index 1b06762415d..18e6aad9c9a 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs index 11e9a2bc394..6d4216970cc 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_oper use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 98d284d0340..57d37067e8f 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index dcd1e7af0c2..60ced9c1208 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -3,7 +3,7 @@ use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Muta use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs index b98005d5922..704acdc103e 100644 --- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs +++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index 52cec437378..ff83725da69 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 621a32d79bf..2587b3881bb 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -20,7 +20,7 @@ use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; @@ -28,6 +28,8 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; +use crate::vec::is_allowed_vec_method; + declare_clippy_lint! { /// ### What it does /// This lint checks for function arguments of type `&String`, `&Vec`, @@ -660,7 +662,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: }, // If the types match check for methods which exist on both types. e.g. `Vec::len` and // `slice::len` - ty::Adt(def, _) if def.did() == args.ty_did => { + ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => { set_skip_flag(); }, _ => (), @@ -712,23 +714,25 @@ fn matches_preds<'tcx>( preds: &'tcx [ty::PolyExistentialPredicate<'tcx>], ) -> bool { let infcx = cx.tcx.infer_ctxt().build(); - preds.iter().all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) { - ExistentialPredicate::Trait(p) => infcx - .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env) - .must_apply_modulo_regions(), - ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new( - cx.tcx, - ObligationCause::dummy(), - cx.param_env, - cx.tcx - .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection( - p.with_self_ty(cx.tcx, ty), - )))), - )), - ExistentialPredicate::AutoTrait(p) => infcx - .type_implements_trait(p, [ty], cx.param_env) - .must_apply_modulo_regions(), - }) + preds + .iter() + .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) { + ExistentialPredicate::Trait(p) => infcx + .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env) + .must_apply_modulo_regions(), + ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new( + cx.tcx, + ObligationCause::dummy(), + cx.param_env, + cx.tcx + .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection( + p.with_self_ty(cx.tcx, ty), + )))), + )), + ExistentialPredicate::AutoTrait(p) => infcx + .type_implements_trait(p, [ty], cx.param_env) + .must_apply_modulo_regions(), + }) } fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index 66d869bc45a..ff8ec2ad57c 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::fmt; diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs index 316a72988aa..c0e999e76ef 100644 --- a/src/tools/clippy/clippy_lints/src/pub_use.rs +++ b/src/tools/clippy/clippy_lints/src/pub_use.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Item, ItemKind, VisibilityKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 5c395143b9a..fc5835408a9 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -18,7 +18,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs index d0de33e3c4f..ddfc53083c4 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::span_is_local; use rustc_hir::{Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index fd9de76bacf..6b54258dd61 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; use std::cmp::Ordering; diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs index 98f5a07da0d..ac29d27303c 100644 --- a/src/tools/clippy/clippy_lints/src/raw_strings.rs +++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs @@ -8,7 +8,7 @@ use rustc_ast::token::LitKind; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs index b99af44655d..d0b45b59526 100644 --- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index b27d4cc6e4f..62f3c09aa7e 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -7,7 +7,7 @@ use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 90297ca8bb6..19d9d64b31e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -9,7 +9,7 @@ use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSo use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 698af9fb192..c62c351e716 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -9,7 +9,7 @@ use rustc_hir::{def_id, Body, FnDecl, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, BytePos, Span}; diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index f2a006ebdfc..8bac2e40e01 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -4,13 +4,13 @@ use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; +use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -60,11 +60,14 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor { } } -/// Checks if the body is owned by an async closure -fn is_async_closure(body: &hir::Body<'_>) -> bool { - if let hir::ExprKind::Closure(closure) = body.value.kind - && let [resume_ty] = closure.fn_decl.inputs - && let hir::TyKind::Path(hir::QPath::LangItem(hir::LangItem::ResumeTy, ..)) = resume_ty.kind +/// Checks if the body is owned by an async closure. +/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression +/// }`. +fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { + if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind + && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body) + // checks whether it is `async || whatever_expression` + && let Some(CoroutineKind::Async(CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind { true } else { @@ -100,7 +103,7 @@ fn find_innermost_closure<'tcx>( data = Some(( body.value, closure.fn_decl, - if is_async_closure(body) { + if is_async_closure(cx, body) { ty::Asyncness::Yes } else { ty::Asyncness::No @@ -173,12 +176,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { hint = hint.asyncify(); } - diag.span_suggestion( - full_expr.span, - "try doing something like", - hint.maybe_par(), - applicability, - ); + let is_in_fn_call_arg = + clippy_utils::get_parent_node(cx.tcx, expr.hir_id).is_some_and(|x| match x { + Node::Expr(expr) => matches!(expr.kind, hir::ExprKind::Call(_, _)), + _ => false, + }); + + // avoid clippy::double_parens + if !is_in_fn_call_arg { + hint = hint.maybe_par(); + }; + + diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability); } }, ); diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 221aa317e5d..1168e79bb0d 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -3,7 +3,7 @@ use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{walk_expr, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index b8e606df737..fb000cd7184 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index 15b784039b6..8c374d7d6db 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -6,7 +6,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index 32e0c3749ab..0e43e4a7ee5 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::hygiene::MacroKind; diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index c9fc65653c2..c99b657c23a 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -8,7 +8,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{GenericArg, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index a70b831a80c..07b604f2326 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs index f6af9cac3de..07fcb69afbc 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs index 0ba898e75a1..19ce08bde10 100644 --- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs +++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs index 8b3dabde9be..a4be78b310b 100644 --- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 69818db7c82..16086ba6637 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::BytePos; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index ae8be006781..687bad35a36 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -8,7 +8,7 @@ use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index b4842e7d48a..ca7a0c7c87b 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index 1a23757f7d6..5962e8be959 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 14c103e7047..2293b53b42b 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -7,12 +7,14 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind, + Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, + StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; @@ -158,6 +160,22 @@ impl<'tcx> ToString for RetReplacement<'tcx> { declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]); +/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed. This +/// is the case when the enclosing block expression is coerced to some other type, which only works +/// because of the never-ness of `return` expressions +fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool { + cx.tcx + .hir() + .parent_iter(stmt_hir_id) + .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None }) + .is_some_and(|e| { + cx.typeck_results() + .expr_adjustments(e) + .iter() + .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny)) + }) +} + impl<'tcx> LateLintPass<'tcx> for Return { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.sess(), stmt.span) @@ -173,6 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { && let [.., final_stmt] = block.stmts && final_stmt.hir_id != stmt.hir_id && !is_from_proc_macro(cx, expr) + && !stmt_needs_never_type(cx, stmt.hir_id) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 4f53cceeecf..74193e0199f 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; use std::collections::{BTreeMap, BTreeSet}; diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs index 36cb2edf723..935dd4a3630 100644 --- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs +++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs @@ -3,7 +3,7 @@ use clippy_utils::return_ty; use clippy_utils::ty::contains_adt_constructor; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index b0601bba4af..0b3adfb7a4b 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 3aabcadaa1f..2cd3e57f885 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index fc1c2af9257..90834d784a5 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::{get_trait_def_id, paths}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 41c10b34a42..c74364d89d6 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index 57bcee1a871..6c99ccda7ea 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{self as hir}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, DUMMY_SP}; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index ae81e1198af..396d2717a13 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -7,7 +7,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs index 74ee8ce2de7..42f1564db35 100644 --- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs +++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{GenericParam, GenericParamKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 9c21d70c82c..18fbbdb4079 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_expr, Visitor}; use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::symbol::kw; use rustc_span::{Span, Symbol}; diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 099743d229d..95b4a11a783 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -8,7 +8,7 @@ use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::fmt::{self, Display, Formatter}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index 0385f1a98e5..756e47cbdf0 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TypeAndMut}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs index 7de029b7b94..14ca7a3f004 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::path_def_id; use clippy_utils::ty::peel_mid_ty_refs; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 733da790441..c4a5e48e855 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index d07a44770cc..38fd54a0f1e 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index baa9750cc01..13ae1ff52dd 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -11,7 +11,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs index 644664b104d..8cf4715eeb8 100644 --- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs +++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_parent_node, match_libc_symbol}; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index b332309a552..8b9d9bade91 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs index 3244933a124..268c0c1b2df 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs @@ -4,7 +4,7 @@ use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TR use core::ops::ControlFlow; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs index 4340c23f830..1cc27670fa8 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 285f2f4f6f9..daa6fe8715c 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, SyntaxContext}; diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs index 6a6c94425d1..20e9608a15d 100644 --- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs index dcf1fac023a..af9e13dba36 100644 --- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index c717ccc35a6..8151dd8f2cf 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_adjusted; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs index 9481c78a505..da557582647 100644 --- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index 1dca523a966..dafe9e38818 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 7eef02b3c65..cbdf31c9336 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -3,7 +3,7 @@ use clippy_utils::has_repr_attr; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Const; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index e624bbe5ff1..e4054393d0a 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -13,7 +13,7 @@ use rustc_hir::{ TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; use std::collections::hash_map::Entry; diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index a3a50acb609..95a92afea66 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -21,7 +21,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index 642e39e8270..e1cd82e18d5 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use std::iter::once; use std::ops::ControlFlow; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 4037808d34f..8e890b4df88 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -16,7 +16,7 @@ use rustc_hir::{ TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; 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 41c4d3359f4..7a6549a7c54 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; 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_session::impl_lint_pass; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index b824deac2c8..3d319b9fe76 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use unicode_normalization::UnicodeNormalization; diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index a7119434517..fc8519d5628 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -6,7 +6,7 @@ use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKi use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index bfd30cec3dd..729972de6e6 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -4,7 +4,7 @@ use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { @@ -44,7 +44,9 @@ fn get_trait_predicates_for_trait_id<'tcx>( let mut preds = Vec::new(); for (pred, _) in generics.predicates { if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder() - && let trait_pred = cx.tcx.instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred)) + && let trait_pred = cx + .tcx + .instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred)) && let Some(trait_def_id) = trait_id && trait_def_id == trait_pred.trait_ref.def_id { @@ -61,7 +63,9 @@ fn get_projection_pred<'tcx>( ) -> Option<ProjectionPredicate<'tcx>> { generics.predicates.iter().find_map(|(proj_pred, _)| { if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() { - let projection_pred = cx.tcx.instantiate_bound_regions_with_erased(proj_pred.kind().rebind(pred)); + let projection_pred = cx + .tcx + .instantiate_bound_regions_with_erased(proj_pred.kind().rebind(pred)); if projection_pred.projection_ty.args == trait_pred.trait_ref.args { return Some(projection_pred); } diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs index 884c6ca4d31..0abd48e6423 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs @@ -5,7 +5,7 @@ mod utils; use rustc_hir::{Expr, Local}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs index 2223cbcb060..41e13e13e56 100644 --- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs +++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index 9bd7167db25..f5af540fa14 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Symbol; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs index 25a9db36d5c..9979e02297e 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -4,24 +4,27 @@ use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Suggest removing the use of a may (or map_err) method when an Option or Result is being constructed. + /// Suggests removing the use of a `map()` (or `map_err()`) method when an `Option` or `Result` + /// is being constructed. /// /// ### Why is this bad? - /// It introduces unnecessary complexity. In this case the function can be used directly and - /// construct the Option or Result from the output. + /// It introduces unnecessary complexity. Instead, the function can be called before + /// constructing the `Option` or `Result` from its return value. /// /// ### Example /// ```no_run - /// Some(4).map(i32::swap_bytes); + /// Some(4).map(i32::swap_bytes) + /// # ; /// ``` /// Use instead: /// ```no_run - /// Some(i32::swap_bytes(4)); + /// Some(i32::swap_bytes(4)) + /// # ; /// ``` #[clippy::version = "1.74.0"] pub UNNECESSARY_MAP_ON_CONSTRUCTOR, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs index 14694bb3a28..6b5e6c6ab20 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs index 1e2b20469ef..ddee06b59ca 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs index c35a2afab48..ed4d87ef8f8 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 0d551639ea9..446160f8e0f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 952c0dc72b1..65600009c1d 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -11,7 +11,7 @@ use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; use std::cell::Cell; use std::mem; diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index a7b2d2148e9..3f2f765f751 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 780ece3677d..9c8c44c0a16 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -5,7 +5,7 @@ use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 0fcb62017c6..1de9adfcb96 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index 0473ecaabeb..ba72b3450b9 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs index fbb36bea068..d5ca844b9e2 100644 --- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs +++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 532207310bc..a67f53f00ae 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -3,7 +3,7 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::visitors::is_local_used; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use std::ops::ControlFlow; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 9627f4c7454..0a73da202ec 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -4,7 +4,7 @@ use rustc_ast::visit::FnKind; use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 6e1d0e09fe2..ae2ac38cffe 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -12,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index df4b42133f8..a615ef11691 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -6,7 +6,7 @@ use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index de6a75b79fc..d2a1d42f279 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind}; +use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; declare_clippy_lint! { @@ -77,7 +77,7 @@ fn correct_ident(ident: &str) -> String { ident } -fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { +fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive: bool) { let span = ident.span; let ident = ident.as_str(); let corrected = correct_ident(ident); @@ -89,14 +89,20 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { // upper-case-acronyms-aggressive config option enabled || (be_aggressive && ident != corrected) { - span_lint_and_sugg( + span_lint_hir_and_then( cx, UPPER_CASE_ACRONYMS, + hir_id, span, &format!("name `{ident}` contains a capitalized acronym"), - "consider making the acronym lowercase, except the initial letter", - corrected, - Applicability::MaybeIncorrect, + |diag| { + diag.span_suggestion( + span, + "consider making the acronym lowercase, except the initial letter", + corrected, + Applicability::MaybeIncorrect, + ); + }, ); } } @@ -111,16 +117,15 @@ impl LateLintPass<'_> for UpperCaseAcronyms { } match it.kind { ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => { - check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); + check_ident(cx, &it.ident, it.hir_id(), self.upper_case_acronyms_aggressive); }, ItemKind::Enum(ref enumdef, _) => { - check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); + check_ident(cx, &it.ident, it.hir_id(), self.upper_case_acronyms_aggressive); // check enum variants separately because again we only want to lint on private enums and // the fn check_variant does not know about the vis of the enum of its variants - enumdef - .variants - .iter() - .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive)); + enumdef.variants.iter().for_each(|variant| { + check_ident(cx, &variant.ident, variant.hir_id, self.upper_case_acronyms_aggressive); + }); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index ac1d9acc70b..fa033838ef3 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 7aed1d6e30b..2ab24f70ae0 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -11,7 +11,7 @@ use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index d78f67c05f0..5ddedb24b15 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -4,7 +4,7 @@ use regex::Regex; use rustc_ast as ast; use rustc_hir::{Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index f514f166cff..7c70d3f45db 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::borrow::{Borrow, Cow}; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index 5aa1417cfb4..5059712d69c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_lint_allowed, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 16d0636b834..07879e81fc2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -11,7 +11,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::ConstValue; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 66d32087fcd..4fb615e1d57 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -7,7 +7,7 @@ use rustc_hir::Item; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::FloatTy; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 486e8220484..370ed430bcf 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -11,7 +11,7 @@ use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 8ecdba47f89..373b076f92c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -20,9 +20,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath}; -use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; +use rustc_lint::{unerased_lint_store, CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; use rustc_middle::hir::nested_filter; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Loc, Span, Symbol}; use serde::ser::SerializeStruct; @@ -714,7 +714,7 @@ fn get_lint_group_and_level_or_lint( lint_name: &str, item: &Item<'_>, ) -> Option<(String, &'static str)> { - let result = cx.lint_store.check_lint_name( + let result = unerased_lint_store(cx.tcx.sess).check_lint_name( lint_name, Some(sym::clippy), &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), @@ -746,7 +746,7 @@ fn get_lint_group_and_level_or_lint( } fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> { - for (group_name, lints, _) in cx.lint_store.get_lint_groups() { + for (group_name, lints, _) in unerased_lint_store(cx.tcx.sess).get_lint_groups() { if IGNORED_LINT_GROUPS.contains(&group_name) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 86b1a0ae624..6d5240db832 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs index 77b95e51f62..326e1721461 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_lint_allowed, method_calls, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs index 5899b94e16b..9169e2968eb 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::NodeId; use rustc_ast::visit::FnKind; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 9aa23b6efe3..70ca1b206b4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs index fd51bca9e5b..a5c4bf474f7 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index f58641289f8..ba958c5b392 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -12,7 +12,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; #[expect(clippy::module_name_repetitions)] @@ -57,7 +57,7 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// Checks if the given expression is a method call to a `Vec` method /// that also exists on slices. If this returns true, it means that /// this expression does not actually require a `Vec` and could just work with an array. -fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { +pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"]; if let ExprKind::MethodCall(path, ..) = e.kind { diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index c8b9402f1ae..ac3b2bdaf65 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -11,7 +11,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 8abcc964b89..83369c66367 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 5c1bea74486..9b0dac6af25 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, BytePos}; diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index b6f942a90d3..be16d2e5cc3 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -10,7 +10,7 @@ use rustc_ast::{ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 1d6217d186c..d3623d6fda4 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 41c1757fde8..fba3808261a 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -5,7 +5,7 @@ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{Adt, Ty, TypeVisitableExt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index dcfce45fc9a..35a8a7920a9 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -10,7 +10,7 @@ use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{alloc_range, Scalar}; -use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; @@ -51,6 +51,63 @@ pub enum Constant<'tcx> { Err, } +trait IntTypeBounds: Sized { + type Output: PartialOrd; + + fn min_max(self) -> Option<(Self::Output, Self::Output)>; + fn bits(self) -> Self::Output; + fn ensure_fits(self, val: Self::Output) -> Option<Self::Output> { + let (min, max) = self.min_max()?; + (min <= val && val <= max).then_some(val) + } +} +impl IntTypeBounds for UintTy { + type Output = u128; + fn min_max(self) -> Option<(Self::Output, Self::Output)> { + Some(match self { + UintTy::U8 => (u8::MIN.into(), u8::MAX.into()), + UintTy::U16 => (u16::MIN.into(), u16::MAX.into()), + UintTy::U32 => (u32::MIN.into(), u32::MAX.into()), + UintTy::U64 => (u64::MIN.into(), u64::MAX.into()), + UintTy::U128 => (u128::MIN, u128::MAX), + UintTy::Usize => (usize::MIN.try_into().ok()?, usize::MAX.try_into().ok()?), + }) + } + fn bits(self) -> Self::Output { + match self { + UintTy::U8 => 8, + UintTy::U16 => 16, + UintTy::U32 => 32, + UintTy::U64 => 64, + UintTy::U128 => 128, + UintTy::Usize => usize::BITS.into(), + } + } +} +impl IntTypeBounds for IntTy { + type Output = i128; + fn min_max(self) -> Option<(Self::Output, Self::Output)> { + Some(match self { + IntTy::I8 => (i8::MIN.into(), i8::MAX.into()), + IntTy::I16 => (i16::MIN.into(), i16::MAX.into()), + IntTy::I32 => (i32::MIN.into(), i32::MAX.into()), + IntTy::I64 => (i64::MIN.into(), i64::MAX.into()), + IntTy::I128 => (i128::MIN, i128::MAX), + IntTy::Isize => (isize::MIN.try_into().ok()?, isize::MAX.try_into().ok()?), + }) + } + fn bits(self) -> Self::Output { + match self { + IntTy::I8 => 8, + IntTy::I16 => 16, + IntTy::I32 => 32, + IntTy::I64 => 64, + IntTy::I128 => 128, + IntTy::Isize => isize::BITS.into(), + } + } +} + impl<'tcx> PartialEq for Constant<'tcx> { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -433,8 +490,15 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match *o { Int(value) => { let ty::Int(ity) = *ty.kind() else { return None }; + let (min, _) = ity.min_max()?; // sign extend let value = sext(self.lcx.tcx, value, ity); + + // Applying unary - to the most negative value of any signed integer type panics. + if value == min { + return None; + } + let value = value.checked_neg()?; // clear unused bits Some(Int(unsext(self.lcx.tcx, value, ity))) @@ -570,17 +634,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match (l, r) { (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() { ty::Int(ity) => { + let (ty_min_value, _) = ity.min_max()?; + let bits = ity.bits(); let l = sext(self.lcx.tcx, l, ity); let r = sext(self.lcx.tcx, r, ity); + + // Using / or %, where the left-hand argument is the smallest integer of a signed integer type and + // the right-hand argument is -1 always panics, even with overflow-checks disabled + if let BinOpKind::Div | BinOpKind::Rem = op.node + && l == ty_min_value + && r == -1 + { + return None; + } + let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity)); match op.node { - BinOpKind::Add => l.checked_add(r).map(zext), - BinOpKind::Sub => l.checked_sub(r).map(zext), - BinOpKind::Mul => l.checked_mul(r).map(zext), + // When +, * or binary - create a value greater than the maximum value, or less than + // the minimum value that can be stored, it panics. + BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(zext), + BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(zext), + BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(zext), BinOpKind::Div if r != 0 => l.checked_div(r).map(zext), BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext), - BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(zext), - BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(zext), + // Using << or >> where the right-hand argument is greater than or equal to the number of bits + // in the type of the left-hand argument, or is negative panics. + BinOpKind::Shr if r < bits && !r.is_negative() => l.checked_shr(r.try_into().ok()?).map(zext), + BinOpKind::Shl if r < bits && !r.is_negative() => l.checked_shl(r.try_into().ok()?).map(zext), BinOpKind::BitXor => Some(zext(l ^ r)), BinOpKind::BitOr => Some(zext(l | r)), BinOpKind::BitAnd => Some(zext(l & r)), @@ -593,24 +673,28 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { _ => None, } }, - ty::Uint(_) => match op.node { - BinOpKind::Add => l.checked_add(r).map(Constant::Int), - BinOpKind::Sub => l.checked_sub(r).map(Constant::Int), - BinOpKind::Mul => l.checked_mul(r).map(Constant::Int), - BinOpKind::Div => l.checked_div(r).map(Constant::Int), - BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), - BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(Constant::Int), - BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(Constant::Int), - BinOpKind::BitXor => Some(Constant::Int(l ^ r)), - BinOpKind::BitOr => Some(Constant::Int(l | r)), - BinOpKind::BitAnd => Some(Constant::Int(l & r)), - BinOpKind::Eq => Some(Constant::Bool(l == r)), - BinOpKind::Ne => Some(Constant::Bool(l != r)), - BinOpKind::Lt => Some(Constant::Bool(l < r)), - BinOpKind::Le => Some(Constant::Bool(l <= r)), - BinOpKind::Ge => Some(Constant::Bool(l >= r)), - BinOpKind::Gt => Some(Constant::Bool(l > r)), - _ => None, + ty::Uint(ity) => { + let bits = ity.bits(); + + match op.node { + BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int), + BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int), + BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int), + BinOpKind::Div => l.checked_div(r).map(Constant::Int), + BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), + BinOpKind::Shr if r < bits => l.checked_shr(r.try_into().ok()?).map(Constant::Int), + BinOpKind::Shl if r < bits => l.checked_shl(r.try_into().ok()?).map(Constant::Int), + BinOpKind::BitXor => Some(Constant::Int(l ^ r)), + BinOpKind::BitOr => Some(Constant::Int(l | r)), + BinOpKind::BitAnd => Some(Constant::Int(l & r)), + BinOpKind::Eq => Some(Constant::Bool(l == r)), + BinOpKind::Ne => Some(Constant::Bool(l != r)), + BinOpKind::Lt => Some(Constant::Bool(l < r)), + BinOpKind::Le => Some(Constant::Bool(l <= r)), + BinOpKind::Ge => Some(Constant::Bool(l >= r)), + BinOpKind::Gt => Some(Constant::Bool(l > r)), + _ => None, + } }, _ => None, }, diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 0bcefba75a7..4e71c6483e6 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -9,12 +9,13 @@ //! - or-fun-call //! - option-if-let-else +use crate::consts::{constant, FullInt}; use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, QPath, UnOp}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; @@ -193,6 +194,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.eagerness = Lazy; } }, + + // `-i32::MIN` panics with overflow checks + ExprKind::Unary(UnOp::Neg, right) if constant(self.cx, self.cx.typeck_results(), right).is_none() => { + self.eagerness |= NoChange; + }, + // Custom `Deref` impl might have side effects ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => @@ -207,6 +214,49 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.cx.typeck_results().expr_ty(e).kind(), ty::Bool | ty::Int(_) | ty::Uint(_), ) => {}, + + // `>>` and `<<` panic when the right-hand side is greater than or equal to the number of bits in the + // type of the left-hand side, or is negative. + // We intentionally only check if the right-hand isn't a constant, because even if the suggestion would + // overflow with constants, the compiler emits an error for it and the programmer will have to fix it. + // Thus, we would realistically only delay the lint. + ExprKind::Binary(op, _, right) + if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr) + && constant(self.cx, self.cx.typeck_results(), right).is_none() => + { + self.eagerness |= NoChange; + }, + + ExprKind::Binary(op, left, right) + if matches!(op.node, BinOpKind::Div | BinOpKind::Rem) + && let right_ty = self.cx.typeck_results().expr_ty(right) + && let left = constant(self.cx, self.cx.typeck_results(), left) + && let right = constant(self.cx, self.cx.typeck_results(), right) + .and_then(|c| c.int_value(self.cx, right_ty)) + && matches!( + (left, right), + // `1 / x`: x might be zero + (_, None) + // `x / -1`: x might be T::MIN + | (None, Some(FullInt::S(-1))) + ) => + { + self.eagerness |= NoChange; + }, + + // Similar to `>>` and `<<`, we only want to avoid linting entirely if either side is unknown and the + // compiler can't emit an error for an overflowing expression. + // Suggesting eagerness for `true.then(|| i32::MAX + 1)` is okay because the compiler will emit an + // error and it's good to have the eagerness warning up front when the user fixes the logic error. + ExprKind::Binary(op, left, right) + if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul) + && !self.cx.typeck_results().expr_ty(e).is_floating_point() + && (constant(self.cx, self.cx.typeck_results(), left).is_none() + || constant(self.cx, self.cx.typeck_results(), right).is_none()) => + { + self.eagerness |= NoChange; + }, + ExprKind::Binary(_, lhs, rhs) if self.cx.typeck_results().expr_ty(lhs).is_primitive() && self.cx.typeck_results().expr_ty(rhs).is_primitive() => {}, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 34ec83709ff..e610ed93050 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1017,8 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, - PatKind::Never => {}, - PatKind::Wild => {}, + PatKind::Never | PatKind::Wild => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index fd37713fc60..f3b63f1cdcf 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1706,8 +1706,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { } match pat.kind { - PatKind::Wild => false, - PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. + PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Lit(..) | PatKind::Range(..) => true, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index f143163152e..9b2bc8df1f3 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -159,7 +159,7 @@ impl<'a> Sugg<'a> { Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span)) }, hir::ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp( - AssocOp::from_ast_binop(op.node.into()), + AssocOp::from_ast_binop(op.node), get_snippet(lhs.span), get_snippet(rhs.span), ), @@ -380,10 +380,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::NotEqual | AssocOp::Greater | AssocOp::GreaterEqual => { - format!( - "{lhs} {} {rhs}", - op.to_ast_binop().expect("Those are AST ops").as_str() - ) + format!("{lhs} {} {rhs}", op.to_ast_binop().expect("Those are AST ops").as_str()) }, AssocOp::Assign => format!("{lhs} = {rhs}"), AssocOp::AssignOp(op) => { diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index c325e4eae21..da71fc3aaa8 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -170,19 +170,18 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type) }, - QPath::LangItem(lang_item, ..) => { - cx.tcx - .lang_items() - .get(*lang_item) - .map_or(Certainty::Uncertain, |def_id| { - let generics = cx.tcx.generics_of(def_id); - if generics.parent_count == 0 && generics.params.is_empty() { - Certainty::Certain(if resolves_to_type { Some(def_id) } else { None }) - } else { - Certainty::Uncertain - } - }) - }, + QPath::LangItem(lang_item, ..) => cx + .tcx + .lang_items() + .get(*lang_item) + .map_or(Certainty::Uncertain, |def_id| { + let generics = cx.tcx.generics_of(def_id); + if generics.parent_count == 0 && generics.params.is_empty() { + Certainty::Certain(if resolves_to_type { Some(def_id) } else { None }) + } else { + Certainty::Uncertain + } + }), }; debug_assert!(resolves_to_type || certainty.to_def_id().is_none()); certainty diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs index dc3037f6669..25b2fc9395c 100644 --- a/src/tools/clippy/declare_clippy_lint/src/lib.rs +++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs @@ -148,7 +148,7 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let category_variant = format_ident!("{category}"); let output = quote! { - declare_tool_lint! { + rustc_session::declare_tool_lint! { #(#attrs)* pub clippy::#name, #level, diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index 58cb42316fd..841b605f5fb 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -309,7 +309,7 @@ impl Crate { target_dir_index: &AtomicUsize, total_crates_to_lint: usize, config: &LintcheckConfig, - lint_filter: &Vec<String>, + lint_filter: &[String], server: &Option<LintcheckServer>, ) -> Vec<ClippyWarning> { // advance the atomic index by one @@ -728,7 +728,7 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> { } /// print how lint counts changed between runs -fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &Vec<String>) { +fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { let same_in_both_hashmaps = old_stats .iter() .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index d40e176b4b0..684cf4574b9 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-11-16" +channel = "nightly-2023-12-01" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 1ae8ac81695..49f0cad08e0 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -183,7 +183,7 @@ pub fn main() { // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't // accept a generic closure. let version_info = rustc_tools_util::get_version_info!(); - handler.note_without_error(format!("Clippy version: {version_info}")); + handler.note(format!("Clippy version: {version_info}")); }); exit(rustc_driver::catch_with_exit_code(move || { diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs index 031982edbe9..267f095f9c2 100644 --- a/src/tools/clippy/tests/integration.rs +++ b/src/tools/clippy/tests/integration.rs @@ -69,15 +69,15 @@ fn integration_test() { // debug: eprintln!("{stderr}"); - // this is an internal test to make sure we would correctly panic on a delay_span_bug + // this is an internal test to make sure we would correctly panic on a span_delayed_bug if repo_name == "matthiaskrgr/clippy_ci_panic_test" { // we need to kind of switch around our logic here: // if we find a panic, everything is fine, if we don't panic, SOMETHING is broken about our testing - // the repo basically just contains a delay_span_bug that forces rustc/clippy to panic: + // the repo basically just contains a span_delayed_bug that forces rustc/clippy to panic: /* #![feature(rustc_attrs)] - #[rustc_error(delay_span_bug_from_inside_query)] + #[rustc_error(span_delayed_bug_from_inside_query)] fn main() {} */ @@ -86,7 +86,7 @@ fn integration_test() { return; } - panic!("panic caused by delay_span_bug was NOT detected! Something is broken!"); + panic!("panic caused by span_delayed_bug was NOT detected! Something is broken!"); } if let Some(backtrace_start) = stderr.find("error: internal compiler error") { diff --git a/src/tools/clippy/tests/ui-toml/private-doc-errors/clippy.toml b/src/tools/clippy/tests/ui-toml/private-doc-errors/clippy.toml new file mode 100644 index 00000000000..8483b87c650 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/private-doc-errors/clippy.toml @@ -0,0 +1 @@ +check-private-items = true diff --git a/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs new file mode 100644 index 00000000000..ae4c3f84c29 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs @@ -0,0 +1,54 @@ +#![deny( + clippy::unnecessary_safety_doc, + clippy::missing_errors_doc, + clippy::missing_panics_doc +)] + +/// This is a private function, skip to match behavior with `missing_safety_doc`. +/// +/// # Safety +/// +/// Boo! +fn you_dont_see_me() { + //~^ ERROR: safe function's docs have unnecessary `# Safety` section + unimplemented!(); +} + +mod private_mod { + /// This is public but unexported function. + /// + /// # Safety + /// + /// Very safe! + pub fn only_crate_wide_accessible() -> Result<(), ()> { + //~^ ERROR: safe function's docs have unnecessary `# Safety` section + //~| ERROR: docs for function returning `Result` missing `# Errors` section + unimplemented!(); + } +} + +pub struct S; + +impl S { + /// Private, fine again to stay consistent with `missing_safety_doc`. + /// + /// # Safety + /// + /// Unnecessary! + fn private(&self) { + //~^ ERROR: safe function's docs have unnecessary `# Safety` section + //~| ERROR: docs for function which may panic missing `# Panics` section + panic!(); + } +} + +#[doc(hidden)] +pub mod __macro { + pub struct T; + impl T { + pub unsafe fn f() {} + //~^ ERROR: unsafe function's docs miss `# Safety` section + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr new file mode 100644 index 00000000000..85336748049 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr @@ -0,0 +1,64 @@ +error: safe function's docs have unnecessary `# Safety` section + --> $DIR/doc_lints.rs:12:1 + | +LL | fn you_dont_see_me() { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/doc_lints.rs:2:5 + | +LL | clippy::unnecessary_safety_doc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: safe function's docs have unnecessary `# Safety` section + --> $DIR/doc_lints.rs:23:5 + | +LL | pub fn only_crate_wide_accessible() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/doc_lints.rs:23:5 + | +LL | pub fn only_crate_wide_accessible() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/doc_lints.rs:3:5 + | +LL | clippy::missing_errors_doc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: safe function's docs have unnecessary `# Safety` section + --> $DIR/doc_lints.rs:38:5 + | +LL | fn private(&self) { + | ^^^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_lints.rs:38:5 + | +LL | fn private(&self) { + | ^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/doc_lints.rs:41:9 + | +LL | panic!(); + | ^^^^^^^^ +note: the lint level is defined here + --> $DIR/doc_lints.rs:4:5 + | +LL | clippy::missing_panics_doc + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unsafe function's docs miss `# Safety` section + --> $DIR/doc_lints.rs:49:9 + | +LL | pub unsafe fn f() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::missing-safety-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 2f9eaa5178c..12828cf9dec 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -21,6 +21,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-macros @@ -95,6 +96,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-macros diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs index 05ee48d17b1..da96eabede1 100644 --- a/src/tools/clippy/tests/ui/attrs.rs +++ b/src/tools/clippy/tests/ui/attrs.rs @@ -36,6 +36,9 @@ pub const ANOTHER_CONST: u8 = 23; #[deprecated(since = "0.1.1")] pub const YET_ANOTHER_CONST: u8 = 0; +#[deprecated(since = "TBD")] +pub const GONNA_DEPRECATE_THIS_LATER: u8 = 0; + fn main() { test_attr_lint(); if false { diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index 69cabcb32d3..48408e19125 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -90,3 +90,17 @@ fn issue_10381() { assert!(maybe_get_bar(2).is_some()); } + +#[allow(unused)] +fn issue_11868() { + fn foo(_: &mut Vec<usize>) {} + + macro_rules! bar { + ($baz:expr) => { + Box::leak(Box::new($baz)) + }; + } + + foo(bar!(vec![])); + foo(bar!(vec![1])); +} diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index 48fa8bc33bc..58b91270747 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -90,3 +90,17 @@ fn issue_10381() { assert!(maybe_get_bar(2).is_some()); } + +#[allow(unused)] +fn issue_11868() { + fn foo(_: &mut Vec<usize>) {} + + macro_rules! bar { + ($baz:expr) => { + Box::leak(Box::new($baz)) + }; + } + + foo(bar!(vec![])); + foo(bar!(vec![1])); +} diff --git a/src/tools/clippy/tests/ui/cfg_features.fixed b/src/tools/clippy/tests/ui/cfg_features.fixed index 3d52f2382ea..0fe38f169f9 100644 --- a/src/tools/clippy/tests/ui/cfg_features.fixed +++ b/src/tools/clippy/tests/ui/cfg_features.fixed @@ -2,16 +2,28 @@ fn main() { #[cfg(feature = "not-really-a-feature")] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` let _ = 1 + 2; #[cfg(all(feature = "right", feature = "wrong"))] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; #[cfg(all(feature = "wrong1", any(feature = "right", feature = "wrong2", feature, features)))] - //~^ ERROR: feature may misspelled as features - //~| ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' + //~| ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; + + #[cfg(test)] + //~^ ERROR: 'test' may be misspelled as 'tests' + let _ = 2; + #[cfg(test)] + //~^ ERROR: 'test' may be misspelled as 'Test' + let _ = 2; + + #[cfg(all(test, test))] + //~^ ERROR: 'test' may be misspelled as 'tests' + //~| ERROR: 'test' may be misspelled as 'Test' + let _ = 2; } diff --git a/src/tools/clippy/tests/ui/cfg_features.rs b/src/tools/clippy/tests/ui/cfg_features.rs index a0344a00447..9c0db035eac 100644 --- a/src/tools/clippy/tests/ui/cfg_features.rs +++ b/src/tools/clippy/tests/ui/cfg_features.rs @@ -2,16 +2,28 @@ fn main() { #[cfg(features = "not-really-a-feature")] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` let _ = 1 + 2; #[cfg(all(feature = "right", features = "wrong"))] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - //~^ ERROR: feature may misspelled as features - //~| ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' + //~| ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; + + #[cfg(tests)] + //~^ ERROR: 'test' may be misspelled as 'tests' + let _ = 2; + #[cfg(Test)] + //~^ ERROR: 'test' may be misspelled as 'Test' + let _ = 2; + + #[cfg(all(tests, Test))] + //~^ ERROR: 'test' may be misspelled as 'tests' + //~| ERROR: 'test' may be misspelled as 'Test' + let _ = 2; } diff --git a/src/tools/clippy/tests/ui/cfg_features.stderr b/src/tools/clippy/tests/ui/cfg_features.stderr index 401c3e92ed9..e1593e2071b 100644 --- a/src/tools/clippy/tests/ui/cfg_features.stderr +++ b/src/tools/clippy/tests/ui/cfg_features.stderr @@ -1,29 +1,53 @@ -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:4:11 | LL | #[cfg(features = "not-really-a-feature")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `feature = "not-really-a-feature"` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `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 +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:9:34 | LL | #[cfg(all(feature = "right", features = "wrong"))] - | ^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong"` + | ^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong"` -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:13:15 | LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong1"` + | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong1"` -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:13:59 | LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong2"` + | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong2"` -error: aborting due to 4 previous errors +error: 'test' may be misspelled as 'tests' + --> $DIR/cfg_features.rs:18:11 + | +LL | #[cfg(tests)] + | ^^^^^ help: did you mean: `test` + +error: 'test' may be misspelled as 'Test' + --> $DIR/cfg_features.rs:21:11 + | +LL | #[cfg(Test)] + | ^^^^ help: did you mean: `test` + +error: 'test' may be misspelled as 'tests' + --> $DIR/cfg_features.rs:25:15 + | +LL | #[cfg(all(tests, Test))] + | ^^^^^ help: did you mean: `test` + +error: 'test' may be misspelled as 'Test' + --> $DIR/cfg_features.rs:25:22 + | +LL | #[cfg(all(tests, Test))] + | ^^^^ help: did you mean: `test` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs index 37d0d135957..48e1b1819c6 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs @@ -11,6 +11,12 @@ pub fn foo() { bar() } +/// Calls ["bar"] uselessly +//~^ ERROR: possible intra-doc link using quotes instead of backticks +pub fn foo2() { + bar() +} + /// # Examples /// This demonstrates issue \#8961 /// ``` 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 e1883f349b0..cd4f87c56b4 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr @@ -7,5 +7,11 @@ 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 1 previous error +error: possible intra-doc link using quotes instead of backticks + --> $DIR/doc_link_with_quotes.rs:14:12 + | +LL | /// Calls ["bar"] uselessly + | ^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed index a4d6d49e57c..3ce2edf2c71 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -39,3 +39,21 @@ fn main() { // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); } + +fn _issue11831() { + struct NotAFloat; + + impl std::ops::Add<f64> for NotAFloat { + type Output = Self; + + fn add(self, _: f64) -> Self { + NotAFloat + } + } + + let a = NotAFloat; + let b = 1.0_f64; + let c = 1.0; + + let _ = a + b * c; +} diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs index 262a20f0f55..b5e4a8db4db 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -39,3 +39,21 @@ fn main() { // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); } + +fn _issue11831() { + struct NotAFloat; + + impl std::ops::Add<f64> for NotAFloat { + type Output = Self; + + fn add(self, _: f64) -> Self { + NotAFloat + } + } + + let a = NotAFloat; + let b = 1.0_f64; + let c = 1.0; + + let _ = a + b * c; +} diff --git a/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.rs b/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.rs new file mode 100644 index 00000000000..f6ce6153e01 --- /dev/null +++ b/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.rs @@ -0,0 +1,136 @@ +#![warn(clippy::impl_hash_borrow_with_str_and_bytes)] + +use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; + +struct ExampleType { + data: String, +} + +impl Hash for ExampleType { + //~^ ERROR: can't + fn hash<H: Hasher>(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl Borrow<str> for ExampleType { + fn borrow(&self) -> &str { + &self.data + } +} + +impl Borrow<[u8]> for ExampleType { + fn borrow(&self) -> &[u8] { + self.data.as_bytes() + } +} + +struct ShouldNotRaiseForHash {} +impl Hash for ShouldNotRaiseForHash { + fn hash<H: Hasher>(&self, state: &mut H) { + todo!(); + } +} + +struct ShouldNotRaiseForBorrow {} +impl Borrow<str> for ShouldNotRaiseForBorrow { + fn borrow(&self) -> &str { + todo!(); + } +} +impl Borrow<[u8]> for ShouldNotRaiseForBorrow { + fn borrow(&self) -> &[u8] { + todo!(); + } +} + +struct ShouldNotRaiseForHashBorrowStr {} +impl Hash for ShouldNotRaiseForHashBorrowStr { + fn hash<H: Hasher>(&self, state: &mut H) { + todo!(); + } +} +impl Borrow<str> for ShouldNotRaiseForHashBorrowStr { + fn borrow(&self) -> &str { + todo!(); + } +} + +struct ShouldNotRaiseForHashBorrowSlice {} +impl Hash for ShouldNotRaiseForHashBorrowSlice { + fn hash<H: Hasher>(&self, state: &mut H) { + todo!(); + } +} + +impl Borrow<[u8]> for ShouldNotRaiseForHashBorrowSlice { + fn borrow(&self) -> &[u8] { + todo!(); + } +} + +#[derive(Hash)] +//~^ ERROR: can't +struct Derived { + data: String, +} + +impl Borrow<str> for Derived { + fn borrow(&self) -> &str { + self.data.as_str() + } +} + +impl Borrow<[u8]> for Derived { + fn borrow(&self) -> &[u8] { + self.data.as_bytes() + } +} + +struct GenericExampleType<T> { + data: T, +} + +impl<T: Hash> Hash for GenericExampleType<T> { + fn hash<H: Hasher>(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl Borrow<str> for GenericExampleType<String> { + fn borrow(&self) -> &str { + &self.data + } +} + +impl Borrow<[u8]> for GenericExampleType<&'static [u8]> { + fn borrow(&self) -> &[u8] { + self.data + } +} + +struct GenericExampleType2<T> { + data: T, +} + +impl Hash for GenericExampleType2<String> { + //~^ ERROR: can't + // this is correctly throwing an error for generic with concrete impl + // for all 3 types + fn hash<H: Hasher>(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl Borrow<str> for GenericExampleType2<String> { + fn borrow(&self) -> &str { + &self.data + } +} + +impl Borrow<[u8]> for GenericExampleType2<String> { + fn borrow(&self) -> &[u8] { + self.data.as_bytes() + } +} diff --git a/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr b/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr new file mode 100644 index 00000000000..afc35ef9845 --- /dev/null +++ b/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr @@ -0,0 +1,41 @@ +error: the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented + --> $DIR/impl_hash_with_borrow_str_and_bytes.rs:10:6 + | +LL | impl Hash for ExampleType { + | ^^^^ + | + = note: the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T> + = note: however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ... + = note: ... as (`hash("abc") != hash("abc".as_bytes())` + = help: consider either removing one of the `Borrow` implementations (`Borrow<str>` or `Borrow<[u8]>`) ... + = help: ... or not implementing `Hash` for this type + = note: `-D clippy::impl-hash-borrow-with-str-and-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::impl_hash_borrow_with_str_and_bytes)]` + +error: the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented + --> $DIR/impl_hash_with_borrow_str_and_bytes.rs:73:10 + | +LL | #[derive(Hash)] + | ^^^^ + | + = note: the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T> + = note: however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ... + = note: ... as (`hash("abc") != hash("abc".as_bytes())` + = help: consider either removing one of the `Borrow` implementations (`Borrow<str>` or `Borrow<[u8]>`) ... + = help: ... or not implementing `Hash` for this type + = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented + --> $DIR/impl_hash_with_borrow_str_and_bytes.rs:117:6 + | +LL | impl Hash for GenericExampleType2<String> { + | ^^^^ + | + = note: the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T> + = note: however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ... + = note: ... as (`hash("abc") != hash("abc".as_bytes())` + = help: consider either removing one of the `Borrow` implementations (`Borrow<str>` or `Borrow<[u8]>`) ... + = help: ... or not implementing `Hash` for this type + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed index 566a5b690d8..2cbf972fca5 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.fixed +++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed @@ -89,3 +89,46 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_values().count(); } + +#[clippy::msrv = "1.53"] +fn msrv_1_53() { + let map: HashMap<u32, u32> = HashMap::new(); + + // Don't lint because into_iter is not supported + let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); + + // Lint + let _ = map.keys().collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + let _ = map.values().collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + let _ = map.values().map(|v| v + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values +} + +#[clippy::msrv = "1.54"] +fn msrv_1_54() { + // Lint all + let map: HashMap<u32, u32> = HashMap::new(); + + let _ = map.clone().into_keys().collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + let _ = map.clone().into_keys().map(|key| key + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + + let _ = map.clone().into_values().collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + let _ = map.clone().into_values().map(|val| val + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + + let _ = map.keys().collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + let _ = map.values().collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + let _ = map.values().map(|v| v + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values +} diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs index d85e501da48..6a9a4267a76 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.rs +++ b/src/tools/clippy/tests/ui/iter_kv_map.rs @@ -93,3 +93,46 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); } + +#[clippy::msrv = "1.53"] +fn msrv_1_53() { + let map: HashMap<u32, u32> = HashMap::new(); + + // Don't lint because into_iter is not supported + let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); + + // Lint + let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values +} + +#[clippy::msrv = "1.54"] +fn msrv_1_54() { + // Lint all + let map: HashMap<u32, u32> = HashMap::new(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + + let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's keys + let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values + let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); + //~^ ERROR: iterating on a map's values +} diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr index 62155b7f838..471615978e1 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.stderr +++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr @@ -201,5 +201,65 @@ error: iterating on a map's values LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` -error: aborting due to 28 previous errors +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:109:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:111:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:113:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:122:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:124:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:127:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:129:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:132:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:134:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:136:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: aborting due to 38 previous errors diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.rs b/src/tools/clippy/tests/ui/join_absolute_paths.rs new file mode 100644 index 00000000000..efa77a0492e --- /dev/null +++ b/src/tools/clippy/tests/ui/join_absolute_paths.rs @@ -0,0 +1,30 @@ +//@no-rustfix + +#![allow(clippy::needless_raw_string_hashes)] +#![warn(clippy::join_absolute_paths)] + +use std::path::{Path, PathBuf}; + +fn main() { + let path = Path::new("/bin"); + path.join("/sh"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = Path::new("C:\\Users"); + path.join("\\user"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = PathBuf::from("/bin"); + path.join("/sh"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = PathBuf::from("/bin"); + path.join(r#"/sh"#); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path: &[&str] = &["/bin"]; + path.join("/sh"); + + let path = Path::new("/bin"); + path.join("sh"); +} diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.stderr b/src/tools/clippy/tests/ui/join_absolute_paths.stderr new file mode 100644 index 00000000000..0c2f89d9978 --- /dev/null +++ b/src/tools/clippy/tests/ui/join_absolute_paths.stderr @@ -0,0 +1,68 @@ +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:10:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead + = note: `-D clippy::join-absolute-paths` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::join_absolute_paths)]` +help: if this is unintentional, try removing the starting separator + | +LL | path.join("sh"); + | ~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("/sh"); + | ~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:14:15 + | +LL | path.join("\\user"); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join("\user"); + | ~~~~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("\\user"); + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:18:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join("sh"); + | ~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("/sh"); + | ~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:22:15 + | +LL | path.join(r#"/sh"#); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join(r#"sh"#); + | ~~~~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from(r#"/sh"#); + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed b/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed index 74ef6f72957..621115cc132 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed @@ -10,11 +10,17 @@ fn main() -> io::Result<()> { // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + // Lint + io::stdin().lines().map_while(Result::ok).for_each(|_| ()); // Do not lint (not a `Lines` iterator) io::stdin() .lines() diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.rs b/src/tools/clippy/tests/ui/lines_filter_map_ok.rs index 345f4dc5f30..a86efbd6686 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.rs +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.rs @@ -10,11 +10,17 @@ fn main() -> io::Result<()> { // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().flatten().for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; // Lint io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); // Lint io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + // Lint + io::stdin().lines().flatten().for_each(|_| ()); // Do not lint (not a `Lines` iterator) io::stdin() .lines() 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 fa2ba0a9a46..9833ab16473 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr @@ -24,29 +24,53 @@ note: this expression returning a `std::io::Lines` may produce an infinite numbe LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: `flatten()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:15:31 + | +LL | BufReader::new(f).lines().flatten().for_each(|_| ()); + | ^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:15:5 + | +LL | BufReader::new(f).lines().flatten().for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` - --> $DIR/lines_filter_map_ok.rs:15:25 + --> $DIR/lines_filter_map_ok.rs:19:25 | LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> $DIR/lines_filter_map_ok.rs:15:5 + --> $DIR/lines_filter_map_ok.rs:19:5 | LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` - --> $DIR/lines_filter_map_ok.rs:17:25 + --> $DIR/lines_filter_map_ok.rs:21:25 | LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> $DIR/lines_filter_map_ok.rs:17:5 + --> $DIR/lines_filter_map_ok.rs:21:5 | LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: `flatten()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:23:25 + | +LL | io::stdin().lines().flatten().for_each(|_| ()); + | ^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:23:5 + | +LL | io::stdin().lines().flatten().for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index bafe8cfddb4..5524e7e5642 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -1,17 +1,17 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:23:5 + --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` | = 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:21:5 + --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:25:5 @@ -20,10 +20,10 @@ LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:19:5 + --> $DIR/macro_use_imports.rs:21:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs index e32ba863176..eb387532031 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs @@ -26,7 +26,7 @@ enum NoDocHidden { _C, } -// name of variant with doc hidden does not start with underscore, should be ignored +// name of variant with doc hidden does not start with underscore enum NoUnderscore { A, B, 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 d2922af99bf..c4b13a577a9 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr @@ -22,5 +22,26 @@ LL | _C, = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` -error: aborting due to 1 previous error +error: this seems like a manual implementation of the non-exhaustive pattern + --> $DIR/manual_non_exhaustive_enum.rs:30:1 + | +LL | enum NoUnderscore { + | ^---------------- + | | + | _help: add the attribute: `#[non_exhaustive] enum NoUnderscore` + | | +LL | | A, +LL | | B, +LL | | #[doc(hidden)] +LL | | C, +LL | | } + | |_^ + | +help: remove this variant + --> $DIR/manual_non_exhaustive_enum.rs:34:5 + | +LL | C, + | ^ + +error: aborting due to 2 previous errors 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 028b8ff7639..0b88b19691e 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr @@ -39,6 +39,26 @@ LL | _c: (), | ^^^^^^ error: this seems like a manual implementation of the non-exhaustive pattern + --> $DIR/manual_non_exhaustive_struct.rs:29:5 + | +LL | struct NoUnderscore { + | ^------------------ + | | + | _____help: add the attribute: `#[non_exhaustive] struct NoUnderscore` + | | +LL | | pub a: i32, +LL | | pub b: i32, +LL | | c: (), +LL | | } + | |_____^ + | +help: remove this field + --> $DIR/manual_non_exhaustive_struct.rs:32:9 + | +LL | c: (), + | ^^^^^ + +error: this seems like a manual implementation of the non-exhaustive pattern --> $DIR/manual_non_exhaustive_struct.rs:56:5 | LL | struct T(pub i32, pub i32, ()); @@ -64,5 +84,5 @@ help: remove this field LL | struct Tp(pub i32, pub i32, ()); | ^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/manual_ok_or.stderr b/src/tools/clippy/tests/ui/manual_ok_or.stderr index ddb2cf261e4..b277d22e59b 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.stderr +++ b/src/tools/clippy/tests/ui/manual_ok_or.stderr @@ -13,6 +13,15 @@ error: this pattern reimplements `Option::ok_or` LL | foo.map_or(Err("error"), Ok); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` +error: called `map_or(Err(_), Ok)` on an `Option` value + --> $DIR/manual_ok_or.rs:14:5 + | +LL | foo.map_or(Err("error"), Ok); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `foo.ok_or("error")` + | + = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` + error: this pattern reimplements `Option::ok_or` --> $DIR/manual_ok_or.rs:17:5 | @@ -38,5 +47,5 @@ LL + "{}{}{}{}{}{}{}", LL ~ "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")); | -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/manual_try_fold.rs b/src/tools/clippy/tests/ui/manual_try_fold.rs index bddf03ac3f1..7299d7cf986 100644 --- a/src/tools/clippy/tests/ui/manual_try_fold.rs +++ b/src/tools/clippy/tests/ui/manual_try_fold.rs @@ -96,3 +96,33 @@ fn msrv_juust_right() { .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) .unwrap(); } + +mod issue11876 { + struct Foo; + + impl Bar for Foo { + type Output = u32; + } + + trait Bar: Sized { + type Output; + fn fold<A, F>(self, init: A, func: F) -> Fold<Self, A, F> + where + A: Clone, + F: Fn(A, Self::Output) -> A, + { + Fold { this: self, init, func } + } + } + + #[allow(dead_code)] + struct Fold<S, A, F> { + this: S, + init: A, + func: F, + } + + fn main() { + Foo.fold(Some(0), |acc, entry| Some(acc? + entry)); + } +} diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr index 7b7eeb322a5..54ddd1402e3 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr @@ -1,4 +1,4 @@ -error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead +error: called `map(<f>).unwrap_or(<a>)` on an `Option` value --> $DIR/map_unwrap_or.rs:17:13 | LL | let _ = opt.map(|x| x + 1) @@ -15,7 +15,7 @@ LL - let _ = opt.map(|x| x + 1) LL + let _ = opt.map_or(0, |x| x + 1); | -error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead +error: called `map(<f>).unwrap_or(<a>)` on an `Option` value --> $DIR/map_unwrap_or.rs:21:13 | LL | let _ = opt.map(|x| { @@ -33,7 +33,7 @@ LL | } LL ~ ); | -error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead +error: called `map(<f>).unwrap_or(<a>)` on an `Option` value --> $DIR/map_unwrap_or.rs:25:13 | LL | let _ = opt.map(|x| x + 1) @@ -50,7 +50,7 @@ LL + 0 LL ~ }, |x| x + 1); | -error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead +error: called `map(<f>).unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:30:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); @@ -62,7 +62,7 @@ LL - let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); LL + let _ = opt.and_then(|x| Some(x + 1)); | -error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead +error: called `map(<f>).unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:32:13 | LL | let _ = opt.map(|x| { @@ -80,7 +80,7 @@ LL | } LL ~ ); | -error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead +error: called `map(<f>).unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:36:13 | LL | let _ = opt @@ -95,7 +95,7 @@ LL - .map(|x| Some(x + 1)) LL + .and_then(|x| Some(x + 1)); | -error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead +error: called `map(<f>).unwrap_or(<a>)` on an `Option` value --> $DIR/map_unwrap_or.rs:47:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); @@ -107,7 +107,7 @@ LL - let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); LL + let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | -error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead +error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value --> $DIR/map_unwrap_or.rs:51:13 | LL | let _ = opt.map(|x| { @@ -117,7 +117,7 @@ LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ -error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead +error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value --> $DIR/map_unwrap_or.rs:55:13 | LL | let _ = opt.map(|x| x + 1) @@ -127,7 +127,7 @@ LL | | 0 LL | | ); | |_________^ -error: called `map(<f>).unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and(<f>)` instead +error: called `map(<f>).unwrap_or(false)` on an `Option` value --> $DIR/map_unwrap_or.rs:61:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); @@ -139,7 +139,7 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.is_some_and(|x| x > 5); | -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 +error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value --> $DIR/map_unwrap_or.rs:71:13 | LL | let _ = res.map(|x| { @@ -149,7 +149,7 @@ LL | | } LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ -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 +error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value --> $DIR/map_unwrap_or.rs:75:13 | LL | let _ = res.map(|x| x + 1) @@ -159,13 +159,13 @@ LL | | 0 LL | | }); | |__________^ -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 +error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value --> $DIR/map_unwrap_or.rs:99:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` -error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead +error: called `map(<f>).unwrap_or(<a>)` on an `Option` value --> $DIR/map_unwrap_or.rs:106:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); @@ -177,7 +177,7 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.map_or(false, |x| x > 5); | -error: called `map(<f>).unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and(<f>)` instead +error: called `map(<f>).unwrap_or(false)` on an `Option` value --> $DIR/map_unwrap_or.rs:113:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); 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 ca611ac9d7f..d1a9fdd6ecf 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead +error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value --> $DIR/map_unwrap_or_fixable.rs:16:13 | LL | let _ = opt.map(|x| x + 1) @@ -10,7 +10,7 @@ LL | | .unwrap_or_else(|| 0); = 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 +error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value --> $DIR/map_unwrap_or_fixable.rs:46:13 | LL | let _ = res.map(|x| x + 1) diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs index 4346ed892f2..de53079a476 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -46,4 +46,26 @@ fn index_struct_different_fields(f: &Foo<'_>) { let _ = f.v[0] + f.v2[1]; } +fn shadowing() { + let x: &[i32] = &[1]; + assert!(x.len() > 1); + + let x: &[i32] = &[1]; + let _ = x[0] + x[1]; + //~^ ERROR: indexing into a slice multiple times without an `assert` +} + +pub fn issue11856(values: &[i32]) -> usize { + let mut ascending = Vec::new(); + for w in values.windows(2) { + assert!(w.len() > 1); + if w[0] < w[1] { + ascending.push((w[0], w[1])); + } else { + ascending.push((w[1], w[0])); + } + } + ascending.len() +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr index 12c9eed5d66..12e05422798 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -160,5 +160,24 @@ LL | let _ = f.v[0] + f.v[1]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks -error: aborting due to 7 previous errors +error: indexing into a slice multiple times without an `assert` + --> $DIR/missing_asserts_for_indexing_unfixable.rs:54:13 + | +LL | let _ = x[0] + x[1]; + | ^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(x.len() > 1);` +note: slice indexed here + --> $DIR/missing_asserts_for_indexing_unfixable.rs:54:13 + | +LL | let _ = x[0] + x[1]; + | ^^^^ +note: slice indexed here + --> $DIR/missing_asserts_for_indexing_unfixable.rs:54:20 + | +LL | let _ = x[0] + x[1]; + | ^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index ea5e74c4c00..25a02bdd2f2 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -1,4 +1,9 @@ -#![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)] +#![allow( + clippy::if_same_then_else, + clippy::no_effect, + clippy::redundant_closure_call, + clippy::ptr_arg +)] #![warn(clippy::needless_pass_by_ref_mut)] #![feature(lint_reasons)] //@no-rustfix 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 aa937c3f6af..92b753276ac 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 @@ -1,5 +1,5 @@ error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:7:11 + --> $DIR/needless_pass_by_ref_mut.rs:12:11 | LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>` @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) { = 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:32:12 + --> $DIR/needless_pass_by_ref_mut.rs:37:12 | LL | fn foo6(s: &mut Vec<u32>) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:45:29 + --> $DIR/needless_pass_by_ref_mut.rs:50:29 | LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:50:31 + --> $DIR/needless_pass_by_ref_mut.rs:55:31 | LL | fn badger(&mut self, vec: &mut Vec<i32>) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:127:16 + --> $DIR/needless_pass_by_ref_mut.rs:132:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:131:16 + --> $DIR/needless_pass_by_ref_mut.rs:136:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:135:16 + --> $DIR/needless_pass_by_ref_mut.rs:140:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:139:16 + --> $DIR/needless_pass_by_ref_mut.rs:144:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:143:24 + --> $DIR/needless_pass_by_ref_mut.rs:148:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:147:24 + --> $DIR/needless_pass_by_ref_mut.rs:152:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:151:32 + --> $DIR/needless_pass_by_ref_mut.rs:156:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:155:24 + --> $DIR/needless_pass_by_ref_mut.rs:160:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:155:45 + --> $DIR/needless_pass_by_ref_mut.rs:160:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:189:16 + --> $DIR/needless_pass_by_ref_mut.rs:194:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:195:20 + --> $DIR/needless_pass_by_ref_mut.rs:200:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:209:39 + --> $DIR/needless_pass_by_ref_mut.rs:214:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:217:26 + --> $DIR/needless_pass_by_ref_mut.rs:222:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:236:34 + --> $DIR/needless_pass_by_ref_mut.rs:241:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:248:25 + --> $DIR/needless_pass_by_ref_mut.rs:253:25 | LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -124,7 +124,7 @@ LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:255:20 + --> $DIR/needless_pass_by_ref_mut.rs:260:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,7 +132,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:266:26 + --> $DIR/needless_pass_by_ref_mut.rs:271:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` diff --git a/src/tools/clippy/tests/ui/needless_raw_string.fixed b/src/tools/clippy/tests/ui/needless_raw_string.fixed index 4ea711fd67a..1a9c601c462 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.fixed +++ b/src/tools/clippy/tests/ui/needless_raw_string.fixed @@ -1,6 +1,5 @@ #![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)] #![warn(clippy::needless_raw_strings)] -#![feature(c_str_literals)] fn main() { "aaa"; diff --git a/src/tools/clippy/tests/ui/needless_raw_string.rs b/src/tools/clippy/tests/ui/needless_raw_string.rs index b6239f9b1f0..1126ea5aa30 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.rs +++ b/src/tools/clippy/tests/ui/needless_raw_string.rs @@ -1,6 +1,5 @@ #![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)] #![warn(clippy::needless_raw_strings)] -#![feature(c_str_literals)] fn main() { r#"aaa"#; diff --git a/src/tools/clippy/tests/ui/needless_raw_string.stderr b/src/tools/clippy/tests/ui/needless_raw_string.stderr index 276bc84c6c3..b2188698564 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string.stderr @@ -1,5 +1,5 @@ error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:6:5 + --> $DIR/needless_raw_string.rs:5:5 | LL | r#"aaa"#; | ^^^^^^^^ @@ -13,7 +13,7 @@ LL + "aaa"; | error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:9:5 + --> $DIR/needless_raw_string.rs:8:5 | LL | br#"aaa"#; | ^^^^^^^^^ @@ -25,7 +25,7 @@ LL + b"aaa"; | error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:12:5 + --> $DIR/needless_raw_string.rs:11:5 | LL | cr#"aaa"#; | ^^^^^^^^^ @@ -37,7 +37,7 @@ LL + c"aaa"; | error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:16:5 + --> $DIR/needless_raw_string.rs:15:5 | LL | / r#" LL | | a @@ -56,7 +56,7 @@ LL ~ "; | error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:22:5 + --> $DIR/needless_raw_string.rs:21:5 | LL | r"no hashes"; | ^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + "no hashes"; | error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:23:5 + --> $DIR/needless_raw_string.rs:22:5 | LL | br"no hashes"; | ^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL + b"no hashes"; | error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:24:5 + --> $DIR/needless_raw_string.rs:23:5 | LL | cr"no hashes"; | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed index c99c2f46532..b2ad657d6b2 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed @@ -1,6 +1,5 @@ #![allow(clippy::no_effect, unused)] #![warn(clippy::needless_raw_string_hashes)] -#![feature(c_str_literals)] fn main() { r"\aaa"; diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs index dcc2af69f4e..54d8ed76d47 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs @@ -1,6 +1,5 @@ #![allow(clippy::no_effect, unused)] #![warn(clippy::needless_raw_string_hashes)] -#![feature(c_str_literals)] fn main() { r#"\aaa"#; 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 017160b1a42..c74eff8161e 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr @@ -1,5 +1,5 @@ error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:6:5 + --> $DIR/needless_raw_string_hashes.rs:5:5 | LL | r#"\aaa"#; | ^^^^^^^^^ @@ -13,7 +13,7 @@ LL + r"\aaa"; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:7:5 + --> $DIR/needless_raw_string_hashes.rs:6:5 | LL | r##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + r#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:8:5 + --> $DIR/needless_raw_string_hashes.rs:7:5 | LL | r######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + r####" "### "## "# "####; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:9:5 + --> $DIR/needless_raw_string_hashes.rs:8:5 | LL | r######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + r###" "aa" "# "## "###; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:10:5 + --> $DIR/needless_raw_string_hashes.rs:9:5 | LL | br#"\aaa"#; | ^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + br"\aaa"; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:11:5 + --> $DIR/needless_raw_string_hashes.rs:10:5 | LL | br##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + br#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:12:5 + --> $DIR/needless_raw_string_hashes.rs:11:5 | LL | br######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + br####" "### "## "# "####; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:13:5 + --> $DIR/needless_raw_string_hashes.rs:12:5 | LL | br######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + br###" "aa" "# "## "###; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:14:5 + --> $DIR/needless_raw_string_hashes.rs:13:5 | LL | cr#"\aaa"#; | ^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + cr"\aaa"; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:15:5 + --> $DIR/needless_raw_string_hashes.rs:14:5 | LL | cr##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + cr#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:16:5 + --> $DIR/needless_raw_string_hashes.rs:15:5 | LL | cr######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + cr####" "### "## "# "####; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:17:5 + --> $DIR/needless_raw_string_hashes.rs:16:5 | LL | cr######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + cr###" "aa" "# "## "###; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:19:5 + --> $DIR/needless_raw_string_hashes.rs:18:5 | LL | / r#" LL | | \a @@ -164,7 +164,7 @@ LL ~ "; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:25:5 + --> $DIR/needless_raw_string_hashes.rs:24:5 | LL | r###"rust"###; | ^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL + r"rust"; | error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:26:5 + --> $DIR/needless_raw_string_hashes.rs:25:5 | LL | r#"hello world"#; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed index d5932ebcf12..0147c73a94b 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed @@ -5,6 +5,7 @@ clippy::unit_arg, clippy::useless_conversion, clippy::diverging_sub_expression, + clippy::let_unit_value, unused )] @@ -59,3 +60,20 @@ fn main() -> Result<(), ()> { Err(()) } + +fn issue11616() -> Result<(), ()> { + let _x: String = { + return Err(())?; + }; + let _x: () = { + Err(())?; + //~^ ERROR: unneeded `return` statement with `?` operator + }; + let _x = match 1 { + 1 => vec![1, 2], + _ => { + return Err(())?; + }, + }; + Ok(()) +} diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs index 2485e25f05c..66e1f438f8c 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs @@ -5,6 +5,7 @@ clippy::unit_arg, clippy::useless_conversion, clippy::diverging_sub_expression, + clippy::let_unit_value, unused )] @@ -59,3 +60,20 @@ fn main() -> Result<(), ()> { Err(()) } + +fn issue11616() -> Result<(), ()> { + let _x: String = { + return Err(())?; + }; + let _x: () = { + return Err(())?; + //~^ ERROR: unneeded `return` statement with `?` operator + }; + let _x = match 1 { + 1 => vec![1, 2], + _ => { + return Err(())?; + }, + }; + Ok(()) +} 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 707f1c25327..17aa212ae8d 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 @@ -1,5 +1,5 @@ error: unneeded `return` statement with `?` operator - --> $DIR/needless_return_with_question_mark.rs:28:5 + --> $DIR/needless_return_with_question_mark.rs:29:5 | LL | return Err(())?; | ^^^^^^^ help: remove it @@ -7,5 +7,11 @@ LL | return Err(())?; = 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 1 previous error +error: unneeded `return` statement with `?` operator + --> $DIR/needless_return_with_question_mark.rs:69:9 + | +LL | return Err(())?; + | ^^^^^^^ help: remove it + +error: aborting due to 2 previous errors 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 eb0661c523a..9d173e409ab 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr @@ -1,4 +1,4 @@ -error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead +error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:11:13 | LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); @@ -7,7 +7,7 @@ LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); = 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 +error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:14:13 | LL | let _ = opt.clone() @@ -17,97 +17,97 @@ LL | | Deref::deref LL | | ) | |_________^ help: try using as_deref instead: `opt.clone().as_deref()` -error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(DerefMut::deref_mut)` on an `Option` value --> $DIR/option_as_ref_deref.rs:20:13 | LL | let _ = opt.as_mut().map(DerefMut::deref_mut); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:22:13 | LL | let _ = opt.as_ref().map(String::as_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| x.as_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:23:13 | LL | let _ = opt.as_ref().map(|x| x.as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(String::as_mut_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:24:13 | LL | let _ = opt.as_mut().map(String::as_mut_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(|x| x.as_mut_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:25:13 | LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead +error: called `.as_ref().map(CString::as_c_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:26:13 | LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()` -error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead +error: called `.as_ref().map(OsString::as_os_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:27:13 | LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()` -error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead +error: called `.as_ref().map(PathBuf::as_path)` on an `Option` value --> $DIR/option_as_ref_deref.rs:28:13 | LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()` -error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead +error: called `.as_ref().map(Vec::as_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:29:13 | LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()` -error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead +error: called `.as_mut().map(Vec::as_mut_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:30:13 | LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()` -error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| x.deref())` on an `Option` value --> $DIR/option_as_ref_deref.rs:32:13 | LL | let _ = opt.as_ref().map(|x| x.deref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead +error: called `.as_mut().map(|x| x.deref_mut())` on an `Option` value --> $DIR/option_as_ref_deref.rs:33:13 | LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()` -error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| &**x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:40:13 | LL | let _ = opt.as_ref().map(|x| &**x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(|x| &mut **x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:41:13 | LL | let _ = opt.as_mut().map(|x| &mut **x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(std::ops::Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:44:13 | LL | let _ = opt.as_ref().map(std::ops::Deref::deref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:56:13 | LL | let _ = opt.as_ref().map(String::as_str); diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed index f0113ca696e..363520112ef 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -92,11 +92,13 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { } // #10335 -fn test_result_impure_else(variable: Result<u32, &str>) { +fn test_result_impure_else(variable: Result<u32, &str>) -> bool { variable.map_or_else(|_| { println!("Err"); + false }, |binding| { println!("Ok {binding}"); + true }) } @@ -213,15 +215,19 @@ mod issue10729 { pub fn reproduce(initial: &Option<String>) { // 👇 needs `.as_ref()` because initial is an `&Option<_>` - initial.as_ref().map_or({}, |value| do_something(value)) + let _ = initial.as_ref().map_or(42, |value| do_something(value)); } pub fn reproduce2(initial: &mut Option<String>) { - initial.as_mut().map_or({}, |value| do_something2(value)) + let _ = initial.as_mut().map_or(42, |value| do_something2(value)); } - fn do_something(_value: &str) {} - fn do_something2(_value: &mut str) {} + fn do_something(_value: &str) -> u32 { + todo!() + } + fn do_something2(_value: &mut str) -> u32 { + todo!() + } } fn issue11429() { @@ -237,3 +243,13 @@ fn issue11429() { let mut _hm = opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone()); } + +fn issue11893() { + use std::io::Write; + let mut output = std::io::stdout().lock(); + if let Some(name) = Some("stuff") { + writeln!(output, "{name:?}").unwrap(); + } else { + panic!("Haven't thought about this condition."); + } +} diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs index 18b7af44392..aaa87a0db54 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -115,11 +115,13 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { } // #10335 -fn test_result_impure_else(variable: Result<u32, &str>) { +fn test_result_impure_else(variable: Result<u32, &str>) -> bool { if let Ok(binding) = variable { println!("Ok {binding}"); + true } else { println!("Err"); + false } } @@ -254,21 +256,25 @@ mod issue10729 { pub fn reproduce(initial: &Option<String>) { // 👇 needs `.as_ref()` because initial is an `&Option<_>` - match initial { + let _ = match initial { Some(value) => do_something(value), - None => {}, - } + None => 42, + }; } pub fn reproduce2(initial: &mut Option<String>) { - match initial { + let _ = match initial { Some(value) => do_something2(value), - None => {}, - } + None => 42, + }; } - fn do_something(_value: &str) {} - fn do_something2(_value: &mut str) {} + fn do_something(_value: &str) -> u32 { + todo!() + } + fn do_something2(_value: &mut str) -> u32 { + todo!() + } } fn issue11429() { @@ -288,3 +294,13 @@ fn issue11429() { let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; } + +fn issue11893() { + use std::io::Write; + let mut output = std::io::stdout().lock(); + if let Some(name) = Some("stuff") { + writeln!(output, "{name:?}").unwrap(); + } else { + panic!("Haven't thought about this condition."); + } +} 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 e36357bcb38..55a8360ffd0 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -158,8 +158,10 @@ error: use Option::map_or_else instead of an if let/else | LL | / if let Ok(binding) = variable { LL | | println!("Ok {binding}"); +LL | | true LL | | } else { LL | | println!("Err"); +LL | | false LL | | } | |_____^ | @@ -167,19 +169,21 @@ help: try | LL ~ variable.map_or_else(|_| { LL + println!("Err"); +LL + false LL + }, |binding| { LL + println!("Ok {binding}"); +LL + true LL + }) | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:141:13 + --> $DIR/option_if_let_else.rs:143:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:151:13 + --> $DIR/option_if_let_else.rs:153:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -201,13 +205,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:179:13 + --> $DIR/option_if_let_else.rs:181:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:183:13 + --> $DIR/option_if_let_else.rs:185:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -227,7 +231,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:222:13 + --> $DIR/option_if_let_else.rs:224:13 | LL | let _ = match s { | _____________^ @@ -237,7 +241,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:226:13 + --> $DIR/option_if_let_else.rs:228:13 | LL | let _ = match Some(10) { | _____________^ @@ -247,7 +251,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:232:13 + --> $DIR/option_if_let_else.rs:234:13 | LL | let _ = match res { | _____________^ @@ -257,7 +261,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:236:13 + --> $DIR/option_if_let_else.rs:238:13 | LL | let _ = match res { | _____________^ @@ -267,31 +271,33 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:240:13 + --> $DIR/option_if_let_else.rs:242:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:257:9 + --> $DIR/option_if_let_else.rs:259:17 | -LL | / match initial { +LL | let _ = match initial { + | _________________^ LL | | Some(value) => do_something(value), -LL | | None => {}, -LL | | } - | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))` +LL | | None => 42, +LL | | }; + | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:264:9 + --> $DIR/option_if_let_else.rs:266:17 | -LL | / match initial { +LL | let _ = match initial { + | _________________^ LL | | Some(value) => do_something2(value), -LL | | None => {}, -LL | | } - | |_________^ help: try: `initial.as_mut().map_or({}, |value| do_something2(value))` +LL | | None => 42, +LL | | }; + | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:283:24 + --> $DIR/option_if_let_else.rs:289:24 | LL | let mut _hashmap = if let Some(hm) = &opt { | ________________________^ @@ -302,7 +308,7 @@ LL | | }; | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:289:19 + --> $DIR/option_if_let_else.rs:295:19 | LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.fixed b/src/tools/clippy/tests/ui/option_map_or_err_ok.fixed new file mode 100644 index 00000000000..131f4b2093e --- /dev/null +++ b/src/tools/clippy/tests/ui/option_map_or_err_ok.fixed @@ -0,0 +1,7 @@ +#![warn(clippy::option_map_or_err_ok)] + +fn main() { + let x = Some("a"); + let _ = x.ok_or("a"); + //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value +} diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.rs b/src/tools/clippy/tests/ui/option_map_or_err_ok.rs new file mode 100644 index 00000000000..0f07a592ae5 --- /dev/null +++ b/src/tools/clippy/tests/ui/option_map_or_err_ok.rs @@ -0,0 +1,7 @@ +#![warn(clippy::option_map_or_err_ok)] + +fn main() { + let x = Some("a"); + let _ = x.map_or(Err("a"), Ok); + //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value +} diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr b/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr new file mode 100644 index 00000000000..a193e3c4c49 --- /dev/null +++ b/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr @@ -0,0 +1,11 @@ +error: called `map_or(Err(_), Ok)` on an `Option` value + --> $DIR/option_map_or_err_ok.rs:5:13 + | +LL | let _ = x.map_or(Err("a"), Ok); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `x.ok_or("a")` + | + = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` + +error: aborting due to 1 previous error + 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 fa150718f89..f2cfc3f9a28 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:10:26 | LL | let _: Option<i32> = opt.map_or(None, |x| Some(x + 1)); @@ -7,7 +7,7 @@ LL | let _: Option<i32> = opt.map_or(None, |x| Some(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 +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:13:26 | LL | let _: Option<i32> = opt.map_or(None, |x| { @@ -16,13 +16,13 @@ LL | | Some(x + 1) LL | | }); | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:17:26 | LL | let _: Option<i32> = opt.map_or(None, bar); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:18:26 | LL | let _: Option<i32> = opt.map_or(None, |x| { @@ -42,7 +42,7 @@ LL + Some(offset + height) LL ~ }); | -error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead +error: called `map_or(None, Some)` on a `Result` value --> $DIR/option_map_or_none.rs:25:26 | LL | let _: Option<i32> = r.map_or(None, Some); diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 91e2e7fd642..fcd716f4144 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -22,6 +22,12 @@ fn do_vec_mut(x: &mut Vec<i64>) { //Nothing here } +fn do_vec_mut2(x: &mut Vec<i64>) { + //~^ ERROR: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice w + x.len(); + x.is_empty(); +} + fn do_str(x: &String) { //~^ ERROR: writing `&String` instead of `&str` involves a new object where a slice will d //Nothing here either diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index cccf2d62d63..35bd8509205 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -13,38 +13,44 @@ error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a sl LL | fn do_vec_mut(x: &mut Vec<i64>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` +error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:25:19 + | +LL | fn do_vec_mut2(x: &mut Vec<i64>) { + | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` + error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:25:14 + --> $DIR/ptr_arg.rs:31:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:30:18 + --> $DIR/ptr_arg.rs:36:18 | LL | fn do_str_mut(x: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:35:15 + --> $DIR/ptr_arg.rs:41:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:40:19 + --> $DIR/ptr_arg.rs:46:19 | LL | fn do_path_mut(x: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:49:18 + --> $DIR/ptr_arg.rs:55:18 | LL | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:63:14 + --> $DIR/ptr_arg.rs:69:14 | LL | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ @@ -62,7 +68,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:73:18 + --> $DIR/ptr_arg.rs:79:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -79,7 +85,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:82:19 + --> $DIR/ptr_arg.rs:88:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -96,7 +102,7 @@ LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:91:44 + --> $DIR/ptr_arg.rs:97:44 | LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ @@ -111,19 +117,19 @@ LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:106:25 + --> $DIR/ptr_arg.rs:112:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:136:66 + --> $DIR/ptr_arg.rs:142:66 | LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {} | ^^^^^^^ help: change this to: `&str` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:166:21 + --> $DIR/ptr_arg.rs:172:21 | LL | fn foo_vec(vec: &Vec<u8>) { | ^^^^^^^^ @@ -137,7 +143,7 @@ LL ~ let _ = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:172:23 + --> $DIR/ptr_arg.rs:178:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -151,7 +157,7 @@ LL ~ let _ = path.to_path_buf().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:178:21 + --> $DIR/ptr_arg.rs:184:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -165,46 +171,46 @@ LL ~ let _ = str.to_path_buf().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:185:29 + --> $DIR/ptr_arg.rs:191:29 | LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:248:17 + --> $DIR/ptr_arg.rs:254:17 | LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:248:35 + --> $DIR/ptr_arg.rs:254:35 | LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:248:51 + --> $DIR/ptr_arg.rs:254:51 | LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:274:39 + --> $DIR/ptr_arg.rs:280:39 | LL | fn cow_elided_lifetime<'a>(input: &'a Cow<str>) -> &'a str { | ^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:280:36 + --> $DIR/ptr_arg.rs:286:36 | LL | fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:284:40 + --> $DIR/ptr_arg.rs:290:40 | LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` -error: aborting due to 23 previous errors +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed index bf268d0b583..f272d8359a3 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed @@ -84,3 +84,21 @@ fn issue9956() { bar()(42, 5); foo(42, 5); } + +async fn issue11357() { + async {}.await; +} + +mod issue11707 { + use core::future::Future; + + fn spawn_on(fut: impl Future<Output = ()>) {} + + fn demo() { + spawn_on(async move {}); + } +} + +fn avoid_double_parens() { + std::convert::identity(13_i32 + 36_i32).leading_zeros(); +} diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs index c8a91049d19..f45db8c9cff 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs @@ -84,3 +84,21 @@ fn issue9956() { bar()((|| || 42)()(), 5); foo((|| || 42)()(), 5); } + +async fn issue11357() { + (|| async {})().await; +} + +mod issue11707 { + use core::future::Future; + + fn spawn_on(fut: impl Future<Output = ()>) {} + + fn demo() { + spawn_on((|| async move {})()); + } +} + +fn avoid_double_parens() { + std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); +} 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 a7cdb43693f..028d383ad35 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr @@ -123,5 +123,23 @@ error: try not to call a closure in the expression where it is declared LL | foo((|| || 42)()(), 5); | ^^^^^^^^^^^^^^ help: try doing something like: `42` -error: aborting due to 14 previous errors +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:89:5 + | +LL | (|| async {})().await; + | ^^^^^^^^^^^^^^^ help: try doing something like: `async {}` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:98:18 + | +LL | spawn_on((|| async move {})()); + | ^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move {}` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:103:28 + | +LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed index f8af9092725..aef26ef225c 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.fixed +++ b/src/tools/clippy/tests/ui/redundant_guards.fixed @@ -193,3 +193,60 @@ mod issue11465 { } } } + +fn issue11807() { + #![allow(clippy::single_match)] + + match Some(Some("")) { + Some(Some("")) => {}, + _ => {}, + } + + match Some(Some(String::new())) { + // Do not lint: String deref-coerces to &str + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([])) => {}, + _ => {}, + } + + match Some(Some([] as [i32; 0])) { + Some(Some([])) => {}, + _ => {}, + } + + match Some(Some(Vec::<()>::new())) { + // Do not lint: Vec deref-coerces to &[T] + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([..])) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([1, ..])) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([1, 2, ..])) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([.., 1, 2])) => {}, + _ => {}, + } + + match Some(Some(Vec::<i32>::new())) { + // Do not lint: deref coercion + Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + _ => {}, + } +} diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs index b46f8a6207e..5d476f5b040 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.rs +++ b/src/tools/clippy/tests/ui/redundant_guards.rs @@ -193,3 +193,60 @@ mod issue11465 { } } } + +fn issue11807() { + #![allow(clippy::single_match)] + + match Some(Some("")) { + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(String::new())) { + // Do not lint: String deref-coerces to &str + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some([] as [i32; 0])) { + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(Vec::<()>::new())) { + // Do not lint: Vec deref-coerces to &[T] + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.starts_with(&[]) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.starts_with(&[1]) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.ends_with(&[1, 2]) => {}, + _ => {}, + } + + match Some(Some(Vec::<i32>::new())) { + // Do not lint: deref coercion + Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + _ => {}, + } +} diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr index b8d7834e358..f78d2a814f9 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.stderr +++ b/src/tools/clippy/tests/ui/redundant_guards.stderr @@ -203,5 +203,89 @@ LL - B { ref c, .. } if matches!(c, &1) => {}, LL + B { c: 1, .. } => {}, | -error: aborting due to 17 previous errors +error: redundant guard + --> $DIR/redundant_guards.rs:201:26 + | +LL | Some(Some(x)) if x.is_empty() => {}, + | ^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.is_empty() => {}, +LL + Some(Some("")) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:212:26 + | +LL | Some(Some(x)) if x.is_empty() => {}, + | ^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.is_empty() => {}, +LL + Some(Some([])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:217:26 + | +LL | Some(Some(x)) if x.is_empty() => {}, + | ^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.is_empty() => {}, +LL + Some(Some([])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:228:26 + | +LL | Some(Some(x)) if x.starts_with(&[]) => {}, + | ^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.starts_with(&[]) => {}, +LL + Some(Some([..])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:233:26 + | +LL | Some(Some(x)) if x.starts_with(&[1]) => {}, + | ^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.starts_with(&[1]) => {}, +LL + Some(Some([1, ..])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:238:26 + | +LL | Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.starts_with(&[1, 2]) => {}, +LL + Some(Some([1, 2, ..])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:243:26 + | +LL | Some(Some(x)) if x.ends_with(&[1, 2]) => {}, + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.ends_with(&[1, 2]) => {}, +LL + Some(Some([.., 1, 2])) => {}, + | + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed index fb2db6cf5ec..cf42b24b2dd 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed @@ -3,6 +3,12 @@ fn main() { let opt: Result<u32, &str> = Ok(1); let _ = opt.ok(); + //~^ ERROR: called `map_or(None, Some)` on a `Result` value + let _ = opt.ok(); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + #[rustfmt::skip] + let _ = opt.ok(); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value let rewrap = |s: u32| -> Option<u32> { Some(s) }; @@ -14,4 +20,5 @@ fn main() { // return should not emit the lint let opt: Result<u32, &str> = Ok(1); _ = opt.map_or(None, |_x| Some(1)); + let _ = opt.map_or_else(|a| a.parse::<u32>().ok(), Some); } diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.rs b/src/tools/clippy/tests/ui/result_map_or_into_option.rs index 06779a69925..cdb45d6b82a 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.rs +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.rs @@ -3,6 +3,12 @@ fn main() { let opt: Result<u32, &str> = Ok(1); let _ = opt.map_or(None, Some); + //~^ ERROR: called `map_or(None, Some)` on a `Result` value + let _ = opt.map_or_else(|_| None, Some); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + #[rustfmt::skip] + let _ = opt.map_or_else(|_| { None }, Some); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value let rewrap = |s: u32| -> Option<u32> { Some(s) }; @@ -14,4 +20,5 @@ fn main() { // return should not emit the lint let opt: Result<u32, &str> = Ok(1); _ = opt.map_or(None, |_x| Some(1)); + let _ = opt.map_or_else(|a| a.parse::<u32>().ok(), Some); } 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 12de3b46088..3d6bfef48ec 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 @@ -1,4 +1,4 @@ -error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead +error: called `map_or(None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:5:13 | LL | let _ = opt.map_or(None, Some); @@ -7,5 +7,17 @@ LL | let _ = opt.map_or(None, Some); = 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 1 previous error +error: called `map_or_else(|_| None, Some)` on a `Result` value + --> $DIR/result_map_or_into_option.rs:7:13 + | +LL | let _ = opt.map_or_else(|_| None, Some); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + +error: called `map_or_else(|_| None, Some)` on a `Result` value + --> $DIR/result_map_or_into_option.rs:10:13 + | +LL | let _ = opt.map_or_else(|_| { None }, Some); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/single_element_loop.fixed b/src/tools/clippy/tests/ui/single_element_loop.fixed index a82eb6afcf5..4e59c763198 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.fixed +++ b/src/tools/clippy/tests/ui/single_element_loop.fixed @@ -15,23 +15,19 @@ fn main() { dbg!(item); } - { - let item = &(0..5); + for item in 0..5 { dbg!(item); } - { - let item = &mut (0..5); + for item in 0..5 { dbg!(item); } - { - let item = 0..5; + for item in 0..5 { dbg!(item); } - { - let item = 0..5; + for item in 0..5 { dbg!(item); } diff --git a/src/tools/clippy/tests/ui/single_element_loop.stderr b/src/tools/clippy/tests/ui/single_element_loop.stderr index 603dd7406e4..952d704143a 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.stderr +++ b/src/tools/clippy/tests/ui/single_element_loop.stderr @@ -32,69 +32,29 @@ LL + dbg!(item); LL + } | -error: for loop over a single element - --> $DIR/single_element_loop.rs:16:5 - | -LL | / for item in &[0..5] { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = &(0..5); -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:16:17 | +LL | for item in &[0..5] { + | ^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` -error: for loop over a single element - --> $DIR/single_element_loop.rs:20:5 - | -LL | / for item in [0..5].iter_mut() { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = &mut (0..5); -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:20:17 | +LL | for item in [0..5].iter_mut() { + | ^^^^^^^^^^^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` -error: for loop over a single element - --> $DIR/single_element_loop.rs:24:5 - | -LL | / for item in [0..5] { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = 0..5; -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:24:17 | +LL | for item in [0..5] { + | ^^^^^^ help: did you mean to iterate over the range instead?: `0..5` -error: for loop over a single element - --> $DIR/single_element_loop.rs:28:5 - | -LL | / for item in [0..5].into_iter() { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = 0..5; -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:28:17 | +LL | for item in [0..5].into_iter() { + | ^^^^^^^^^^^^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` error: for loop over a single element --> $DIR/single_element_loop.rs:47:5 diff --git a/src/tools/clippy/tests/ui/test_attr_in_doctest.rs b/src/tools/clippy/tests/ui/test_attr_in_doctest.rs new file mode 100644 index 00000000000..4c904f7a09a --- /dev/null +++ b/src/tools/clippy/tests/ui/test_attr_in_doctest.rs @@ -0,0 +1,51 @@ +/// This is a test for `#[test]` in doctests +/// +/// # Examples +/// +/// ``` +/// #[test] +/// fn should_be_linted() { +/// assert_eq!(1, 1); +/// } +/// ``` +/// +/// Make sure we catch multiple tests in one example, +/// and show that we really parse the attr: +/// +/// ``` +/// #[test] +/// fn should_also_be_linted() { +/// #[cfg(test)] +/// assert!(true); +/// } +/// +/// #[test] +/// fn should_be_linted_too() { +/// assert_eq!("#[test]", " +/// #[test] +/// "); +/// } +/// ``` +/// +/// We don't catch examples that aren't run: +/// +/// ```ignore +/// #[test] +/// fn ignored() { todo!() } +/// ``` +/// +/// ```no_run +/// #[test] +/// fn ignored() { todo!() } +/// ``` +/// +/// ```compile_fail +/// #[test] +/// fn ignored() { Err(()) } +/// ``` +/// +/// ```txt +/// #[test] +/// fn not_even_rust() { panic!("Ouch") } +/// ``` +fn test_attr_in_doctests() {} diff --git a/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr b/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr new file mode 100644 index 00000000000..605259f3bfb --- /dev/null +++ b/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr @@ -0,0 +1,29 @@ +error: unit tests in doctest are not executed + --> $DIR/test_attr_in_doctest.rs:6:5 + | +LL | /// #[test] + | _____^ +LL | | /// fn should_be_linted() { + | |_______________________^ + | + = note: `-D clippy::test-attr-in-doctest` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::test_attr_in_doctest)]` + +error: unit tests in doctest are not executed + --> $DIR/test_attr_in_doctest.rs:16:5 + | +LL | /// #[test] + | _____^ +LL | | /// fn should_also_be_linted() { + | |____________________________^ + +error: unit tests in doctest are not executed + --> $DIR/test_attr_in_doctest.rs:22:5 + | +LL | /// #[test] + | _____^ +LL | | /// fn should_be_linted_too() { + | |___________________________^ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed index 19abced98bb..4e145693c55 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed @@ -43,6 +43,9 @@ fn transmute_ptr_to_ptr() { //~^ ERROR: transmute from a reference to a reference let _: &GenericParam<f32> = &*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>); //~^ ERROR: transmute from a reference to a reference + let u8_ref: &u8 = &0u8; + let u64_ref: &u64 = unsafe { &*(u8_ref as *const u8 as *const u64) }; + //~^ ERROR: transmute from a reference to a reference } // these are recommendations for solving the above; if these lint we need to update diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs index abba2b8e524..086aadc3647 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs @@ -43,6 +43,9 @@ fn transmute_ptr_to_ptr() { //~^ ERROR: transmute from a reference to a reference let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); //~^ ERROR: transmute from a reference to a reference + let u8_ref: &u8 = &0u8; + let u64_ref: &u64 = unsafe { std::mem::transmute(u8_ref) }; + //~^ ERROR: transmute from a reference to a reference } // these are recommendations for solving the above; if these lint we need to update 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 564339c067e..9f8599921ec 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr @@ -37,5 +37,11 @@ error: transmute from a reference to a reference LL | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)` -error: aborting due to 6 previous errors +error: transmute from a reference to a reference + --> $DIR/transmute_ptr_to_ptr.rs:47:38 + | +LL | let u64_ref: &u64 = unsafe { std::mem::transmute(u8_ref) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(u8_ref as *const u8 as *const u64)` + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs new file mode 100644 index 00000000000..e7f35c57436 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -0,0 +1,18 @@ +//@no-rustfix + +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code)] + +fn main() { + unsafe { + let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; + let bools: &[bool] = unsafe { std::mem::transmute(single_u64) }; + //~^ ERROR: transmute from a reference to a reference + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { std::mem::transmute(a) }; + //~^ ERROR: transmute from a reference to a reference + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; + let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + //~^ ERROR: transmute from a reference to a reference + } +} diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr new file mode 100644 index 00000000000..cc6b156b188 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr @@ -0,0 +1,26 @@ +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref.rs:9:39 + | +LL | let bools: &[bool] = unsafe { std::mem::transmute(single_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` + | +note: the lint level is defined here + --> $DIR/transmute_ref_to_ref.rs:3:9 + | +LL | #![deny(clippy::transmute_ptr_to_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref.rs:12:33 + | +LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref.rs:15:42 + | +LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed index 4778eaefdbd..66598f89208 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed @@ -6,6 +6,8 @@ #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] #![allow(clippy::unit_arg)] +#![allow(arithmetic_overflow)] +#![allow(unconditional_panic)] use std::ops::Deref; @@ -190,3 +192,79 @@ fn issue9485() { // should not lint, is in proc macro with_span!(span Some(42).unwrap_or_else(|| 2);); } + +fn issue9422(x: usize) -> Option<usize> { + (x >= 5).then(|| x - 5) + // (x >= 5).then_some(x - 5) // clippy suggestion panics +} + +fn panicky_arithmetic_ops(x: usize, y: isize) { + #![allow(clippy::identity_op, clippy::eq_op)] + + // See comments in `eager_or_lazy.rs` for the rules that this is meant to follow + + let _x = false.then_some(i32::MAX + 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MAX * 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MAX - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MIN - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255u8 << 7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255u8 << 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255u8 >> 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 >> x); + let _x = false.then_some(i32::MAX + -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(-i32::MAX); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(-i32::MIN); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -y); + let _x = false.then_some(255 >> -7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255 << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(1 / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(x << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(x << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x + x); + let _x = false.then(|| x * x); + let _x = false.then(|| x - x); + let _x = false.then(|| x / x); + let _x = false.then(|| x % x); + let _x = false.then(|| x + 1); + let _x = false.then(|| 1 + x); + + let _x = false.then_some(x / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(x % 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| y / -1); + let _x = false.then_some(1 / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MIN / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN / x as i32); + let _x = false.then_some(i32::MIN / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(4 / 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 1 / x); + + // const eval doesn't read variables, but floating point math never panics, so we can still emit a + // warning + let f1 = 1.0; + let f2 = 2.0; + let _x = false.then_some(f1 + f2); + //~^ ERROR: unnecessary closure used with `bool::then` +} diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs index d4b7fd31b1b..5045fcd790e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs @@ -6,6 +6,8 @@ #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] #![allow(clippy::unit_arg)] +#![allow(arithmetic_overflow)] +#![allow(unconditional_panic)] use std::ops::Deref; @@ -190,3 +192,79 @@ fn issue9485() { // should not lint, is in proc macro with_span!(span Some(42).unwrap_or_else(|| 2);); } + +fn issue9422(x: usize) -> Option<usize> { + (x >= 5).then(|| x - 5) + // (x >= 5).then_some(x - 5) // clippy suggestion panics +} + +fn panicky_arithmetic_ops(x: usize, y: isize) { + #![allow(clippy::identity_op, clippy::eq_op)] + + // See comments in `eager_or_lazy.rs` for the rules that this is meant to follow + + let _x = false.then(|| i32::MAX + 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MAX * 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MAX - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 << 7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 << 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 >> 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 >> x); + let _x = false.then(|| i32::MAX + -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -i32::MAX); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -i32::MIN); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -y); + let _x = false.then(|| 255 >> -7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255 << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 1 / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x + x); + let _x = false.then(|| x * x); + let _x = false.then(|| x - x); + let _x = false.then(|| x / x); + let _x = false.then(|| x % x); + let _x = false.then(|| x + 1); + let _x = false.then(|| 1 + x); + + let _x = false.then(|| x / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x % 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| y / -1); + let _x = false.then(|| 1 / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN / x as i32); + let _x = false.then(|| i32::MIN / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 4 / 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 1 / x); + + // const eval doesn't read variables, but floating point math never panics, so we can still emit a + // warning + let f1 = 1.0; + let f2 = 2.0; + let _x = false.then(|| f1 + f2); + //~^ ERROR: unnecessary closure used with `bool::then` +} diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr index 1b0db4759bb..466664aee6c 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -10,7 +10,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = 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:70:13 + --> $DIR/unnecessary_lazy_eval.rs:72:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -18,7 +18,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:71:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -26,7 +26,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:73:13 + --> $DIR/unnecessary_lazy_eval.rs:75:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -34,7 +34,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:74:13 + --> $DIR/unnecessary_lazy_eval.rs:76:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -42,7 +42,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:75:13 + --> $DIR/unnecessary_lazy_eval.rs:77:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -50,7 +50,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:76:13 + --> $DIR/unnecessary_lazy_eval.rs:78:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -58,7 +58,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:77:13 + --> $DIR/unnecessary_lazy_eval.rs:79:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -66,7 +66,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:78:13 + --> $DIR/unnecessary_lazy_eval.rs:80:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -74,7 +74,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:79:13 + --> $DIR/unnecessary_lazy_eval.rs:81:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- @@ -82,7 +82,7 @@ LL | let _ = cond.then(|| astronomers_pi); | help: use `then_some(..)` instead: `then_some(astronomers_pi)` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:80:13 + --> $DIR/unnecessary_lazy_eval.rs:82:13 | LL | let _ = true.then(|| -> _ {}); | ^^^^^---------------- @@ -90,7 +90,7 @@ LL | let _ = true.then(|| -> _ {}); | help: use `then_some(..)` instead: `then_some({})` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:81:13 + --> $DIR/unnecessary_lazy_eval.rs:83:13 | LL | let _ = true.then(|| {}); | ^^^^^----------- @@ -98,7 +98,7 @@ LL | let _ = true.then(|| {}); | help: use `then_some(..)` instead: `then_some({})` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:85:13 + --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); | ^^^^^^^^--------------------- @@ -106,7 +106,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *r); | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:87:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); | ^^^^^^^^--------------------- @@ -114,7 +114,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *b); | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:89:13 + --> $DIR/unnecessary_lazy_eval.rs:91:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | ^^^^^^^^^^^^^^^^^--------------------- @@ -122,7 +122,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:90:13 + --> $DIR/unnecessary_lazy_eval.rs:92:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | ^^^^^^^^^^^^^^^^^--------------------- @@ -130,7 +130,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:93:13 + --> $DIR/unnecessary_lazy_eval.rs:95:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -138,7 +138,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:94:13 + --> $DIR/unnecessary_lazy_eval.rs:96:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -146,7 +146,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:95:28 + --> $DIR/unnecessary_lazy_eval.rs:97:28 | LL | let _: Option<usize> = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -154,7 +154,7 @@ LL | let _: Option<usize> = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:96:13 + --> $DIR/unnecessary_lazy_eval.rs:98:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -162,7 +162,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:97:35 + --> $DIR/unnecessary_lazy_eval.rs:99:35 | LL | let _: Result<usize, usize> = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -170,7 +170,7 @@ LL | let _: Result<usize, usize> = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:98:28 + --> $DIR/unnecessary_lazy_eval.rs:100:28 | LL | let _: Option<usize> = None.or_else(|| None); | ^^^^^---------------- @@ -178,7 +178,7 @@ LL | let _: Option<usize> = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:101:13 + --> $DIR/unnecessary_lazy_eval.rs:103:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -186,7 +186,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:102:13 + --> $DIR/unnecessary_lazy_eval.rs:104:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -194,7 +194,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:103:13 + --> $DIR/unnecessary_lazy_eval.rs:105:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -202,7 +202,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:104:13 + --> $DIR/unnecessary_lazy_eval.rs:106:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -210,7 +210,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:105:13 + --> $DIR/unnecessary_lazy_eval.rs:107:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -218,7 +218,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:135:28 + --> $DIR/unnecessary_lazy_eval.rs:137:28 | LL | let _: Option<usize> = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -226,7 +226,7 @@ LL | let _: Option<usize> = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:136:13 + --> $DIR/unnecessary_lazy_eval.rs:138:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -234,7 +234,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:137:13 + --> $DIR/unnecessary_lazy_eval.rs:139:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -242,7 +242,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:143:13 + --> $DIR/unnecessary_lazy_eval.rs:145:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -250,7 +250,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:144:13 + --> $DIR/unnecessary_lazy_eval.rs:146:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -258,7 +258,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:145:13 + --> $DIR/unnecessary_lazy_eval.rs:147:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -266,7 +266,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:167:35 + --> $DIR/unnecessary_lazy_eval.rs:169:35 | LL | let _: Result<usize, usize> = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -274,7 +274,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:168:35 + --> $DIR/unnecessary_lazy_eval.rs:170:35 | LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -282,7 +282,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:169:35 + --> $DIR/unnecessary_lazy_eval.rs:171:35 | LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -290,7 +290,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:171:35 + --> $DIR/unnecessary_lazy_eval.rs:173:35 | LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -298,7 +298,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:172:35 + --> $DIR/unnecessary_lazy_eval.rs:174:35 | LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -306,7 +306,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:173:35 + --> $DIR/unnecessary_lazy_eval.rs:175:35 | LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -314,7 +314,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:174:35 + --> $DIR/unnecessary_lazy_eval.rs:176:35 | LL | let _: Result<usize, usize> = res. | ___________________________________^ @@ -328,5 +328,189 @@ LL | | or_else(|_| Ok(ext_str.some_field)); | | | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 40 previous errors +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:206:14 + | +LL | let _x = false.then(|| i32::MAX + 1); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX + 1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:208:14 + | +LL | let _x = false.then(|| i32::MAX * 2); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX * 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:210:14 + | +LL | let _x = false.then(|| i32::MAX - 1); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX - 1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:212:14 + | +LL | let _x = false.then(|| i32::MIN - 1); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MIN - 1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:214:14 + | +LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); + | ^^^^^^------------------------------------- + | | + | help: use `then_some(..)` instead: `then_some((1 + 2 * 3 - 2 / 3 + 9) << 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:216:14 + | +LL | let _x = false.then(|| 255u8 << 7); + | ^^^^^^------------------- + | | + | help: use `then_some(..)` instead: `then_some(255u8 << 7)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:218:14 + | +LL | let _x = false.then(|| 255u8 << 8); + | ^^^^^^------------------- + | | + | help: use `then_some(..)` instead: `then_some(255u8 << 8)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:220:14 + | +LL | let _x = false.then(|| 255u8 >> 8); + | ^^^^^^------------------- + | | + | help: use `then_some(..)` instead: `then_some(255u8 >> 8)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:223:14 + | +LL | let _x = false.then(|| i32::MAX + -1); + | ^^^^^^---------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX + -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:225:14 + | +LL | let _x = false.then(|| -i32::MAX); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(-i32::MAX)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:227:14 + | +LL | let _x = false.then(|| -i32::MIN); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(-i32::MIN)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:230:14 + | +LL | let _x = false.then(|| 255 >> -7); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(255 >> -7)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:232:14 + | +LL | let _x = false.then(|| 255 << -1); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(255 << -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:234:14 + | +LL | let _x = false.then(|| 1 / 0); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(1 / 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:236:14 + | +LL | let _x = false.then(|| x << -1); + | ^^^^^^---------------- + | | + | help: use `then_some(..)` instead: `then_some(x << -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:238:14 + | +LL | let _x = false.then(|| x << 2); + | ^^^^^^--------------- + | | + | help: use `then_some(..)` instead: `then_some(x << 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:248:14 + | +LL | let _x = false.then(|| x / 0); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(x / 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:250:14 + | +LL | let _x = false.then(|| x % 0); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(x % 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:253:14 + | +LL | let _x = false.then(|| 1 / -1); + | ^^^^^^--------------- + | | + | help: use `then_some(..)` instead: `then_some(1 / -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:255:14 + | +LL | let _x = false.then(|| i32::MIN / -1); + | ^^^^^^---------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MIN / -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:258:14 + | +LL | let _x = false.then(|| i32::MIN / 0); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MIN / 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:260:14 + | +LL | let _x = false.then(|| 4 / 2); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(4 / 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:268:14 + | +LL | let _x = false.then(|| f1 + f2); + | ^^^^^^---------------- + | | + | help: use `then_some(..)` instead: `then_some(f1 + f2)` + +error: aborting due to 63 previous errors diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.fixed b/src/tools/clippy/tests/ui/upper_case_acronyms.fixed index 460567b097e..a8023ed00d2 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.fixed +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.fixed @@ -59,4 +59,12 @@ enum Yaml { Str(String), } +// test for issue #7708 +enum AllowOnField { + Disallow, + //~^ ERROR: name `DISALLOW` contains a capitalized acronym + #[allow(clippy::upper_case_acronyms)] + ALLOW, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.rs b/src/tools/clippy/tests/ui/upper_case_acronyms.rs index 6a20aee62dc..c4711b87ec3 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.rs +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.rs @@ -59,4 +59,12 @@ enum YAML { Str(String), } +// test for issue #7708 +enum AllowOnField { + DISALLOW, + //~^ ERROR: name `DISALLOW` contains a capitalized acronym + #[allow(clippy::upper_case_acronyms)] + ALLOW, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr index c57b325e91a..009c53c725b 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr @@ -67,5 +67,11 @@ error: name `YAML` contains a capitalized acronym LL | enum YAML { | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Yaml` -error: aborting due to 11 previous errors +error: name `DISALLOW` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:64:5 + | +LL | DISALLOW, + | ^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `Disallow` + +error: aborting due to 12 previous errors diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index c2ef7710011..fb90559f3d1 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -384,7 +384,7 @@ pub fn report_error<'tcx, 'mir>( // Include a note like `std` does when we omit frames from a backtrace if was_pruned { - ecx.tcx.sess.diagnostic().note_without_error( + ecx.tcx.sess.diagnostic().note( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); } @@ -431,7 +431,7 @@ pub fn report_leaks<'mir, 'tcx>( ); } if any_pruned { - ecx.tcx.sess.diagnostic().note_without_error( + ecx.tcx.sess.diagnostic().note( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); } @@ -456,7 +456,7 @@ pub fn report_msg<'tcx>( let mut err = match diag_level { DiagLevel::Error => sess.struct_span_err(span, title).forget_guarantee(), DiagLevel::Warning => sess.struct_span_warn(span, title), - DiagLevel::Note => sess.diagnostic().span_note_diag(span, title), + DiagLevel::Note => sess.diagnostic().struct_span_note(span, title), }; // Show main message. diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 1345b22a34a..875a78974fa 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -464,7 +464,7 @@ pub fn eval_entry<'tcx>( // Check for thread leaks. if !ecx.have_all_terminated() { tcx.sess.err("the main thread terminated without waiting for all remaining threads"); - tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); + tcx.sess.note("pass `-Zmiri-ignore-leaks` to disable this check"); return None; } // Check for memory leaks. @@ -475,7 +475,7 @@ pub fn eval_entry<'tcx>( let leak_message = "the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check"; if ecx.machine.collect_leak_backtraces { // If we are collecting leak backtraces, each leak is a distinct error diagnostic. - tcx.sess.note_without_error(leak_message); + tcx.sess.note(leak_message); } else { // If we do not have backtraces, we just report an error without any span. tcx.sess.err(leak_message); diff --git a/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.rs b/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.rs index 10939c0f1c3..0dfa8bdd274 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-float-to-int.rs @@ -1,5 +1,5 @@ #![feature(portable_simd)] -use std::simd::*; +use std::simd::prelude::*; fn main() { unsafe { diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/portable-simd-ptrs.rs index 843bb0284cf..a73b1d03cfa 100644 --- a/src/tools/miri/tests/pass/portable-simd-ptrs.rs +++ b/src/tools/miri/tests/pass/portable-simd-ptrs.rs @@ -2,7 +2,7 @@ //@compile-flags: -Zmiri-permissive-provenance #![feature(portable_simd, platform_intrinsics)] use std::ptr; -use std::simd::*; +use std::simd::prelude::*; fn main() { // Pointer casts diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs index 969162e2c1e..2179bcf1c38 100644 --- a/src/tools/miri/tests/pass/portable-simd.rs +++ b/src/tools/miri/tests/pass/portable-simd.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zmiri-strict-provenance #![feature(portable_simd, platform_intrinsics, adt_const_params, inline_const)] -#![allow(incomplete_features)] -use std::simd::*; +#![allow(incomplete_features, internal_features)] +use std::simd::{prelude::*, StdFloat}; extern "platform-intrinsic" { pub(crate) fn simd_bitmask<T, U>(x: T) -> U; @@ -328,14 +328,12 @@ fn simd_cast() { } fn simd_swizzle() { - use Which::*; - let a = f32x4::splat(10.0); let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); assert_eq!(simd_swizzle!(b, [3, 0, 0, 2]), f32x4::from_array([-4.0, 1.0, 1.0, 3.0])); assert_eq!(simd_swizzle!(b, [1, 2]), f32x2::from_array([2.0, 3.0])); - assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0])); + assert_eq!(simd_swizzle!(b, a, [3, 4]), f32x2::from_array([-4.0, 10.0])); } fn simd_gather_scatter() { @@ -417,13 +415,13 @@ fn simd_intrinsics() { i32x4::from_array([10, 2, 10, 10]) ); assert_eq!(simd_shuffle_generic::<_, i32x4, { &[3, 1, 0, 2] }>(a, b), a,); - assert_eq!(simd_shuffle::<_, _, i32x4>(a, b, const { [3, 1, 0, 2] }), a,); + assert_eq!(simd_shuffle::<_, _, i32x4>(a, b, const { [3u32, 1, 0, 2] }), a,); assert_eq!( simd_shuffle_generic::<_, i32x4, { &[7, 5, 4, 6] }>(a, b), i32x4::from_array([4, 2, 1, 10]), ); assert_eq!( - simd_shuffle::<_, _, i32x4>(a, b, const { [7, 5, 4, 6] }), + simd_shuffle::<_, _, i32x4>(a, b, const { [7u32, 5, 4, 6] }), i32x4::from_array([4, 2, 1, 10]), ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs index 2ae3cd2a939..15dceeb8af2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs @@ -629,7 +629,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!( TEST, rustc_error, Normal, - template!(Word, List: "delay_span_bug_from_inside_query"), WarnFollowingWordOnly + template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly ), rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index b2591f016d4..27c79499868 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -110,7 +110,7 @@ struct LayoutCx<'a> { impl<'a> LayoutCalculator for LayoutCx<'a> { type TargetDataLayoutRef = &'a TargetDataLayout; - fn delay_bug(&self, txt: String) { + fn delayed_bug(&self, txt: String) { never!("{}", txt); } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index dfa386b49de..40149f8f1c3 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1852; -const ROOT_ENTRY_LIMIT: usize = 867; +const ROOT_ENTRY_LIMIT: usize = 866; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/assembly/x86_64-function-return.rs b/tests/assembly/x86_64-function-return.rs new file mode 100644 index 00000000000..0fcaca2d491 --- /dev/null +++ b/tests/assembly/x86_64-function-return.rs @@ -0,0 +1,30 @@ +// Test that the function return is (not) converted into a jump to the thunk +// when the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. + +// revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep +// assembly-output: emit-asm +// compile-flags: -O +// [keep] compile-flags: -Zfunction-return=keep +// [thunk-extern] compile-flags: -Zfunction-return=thunk-extern +// [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern +// [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep +// only-x86_64 +// ignore-x86_64-apple-darwin Symbol is called `___x86_return_thunk` (Darwin's extra underscore) +// ignore-sgx Tests incompatible with LVI mitigations + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +#[no_mangle] +pub unsafe fn foo() { + // unset: ret + // unset-NOT: jmp __x86_return_thunk + // keep: ret + // keep-NOT: jmp __x86_return_thunk + // thunk-extern: jmp __x86_return_thunk + // thunk-extern-NOT: ret + // keep-thunk-extern: jmp __x86_return_thunk + // keep-thunk-extern-NOT: ret + // thunk-extern-keep: ret + // thunk-extern-keep-NOT: jmp __x86_return_thunk +} diff --git a/tests/codegen/function-return.rs b/tests/codegen/function-return.rs new file mode 100644 index 00000000000..d832d19ac39 --- /dev/null +++ b/tests/codegen/function-return.rs @@ -0,0 +1,28 @@ +// Test that the `fn_ret_thunk_extern` function attribute is (not) emitted when +// the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. + +// revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep +// needs-llvm-components: x86 +// compile-flags: --target x86_64-unknown-linux-gnu +// [keep] compile-flags: -Zfunction-return=keep +// [thunk-extern] compile-flags: -Zfunction-return=thunk-extern +// [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern +// [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: fn_ret_thunk_extern + // keep-NOT: fn_ret_thunk_extern + // thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } + // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } + // thunk-extern-keep-NOT: fn_ret_thunk_extern +} diff --git a/tests/codegen/simd/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs index 6e7d3d9316a..109d5381343 100644 --- a/tests/codegen/simd/simd-wide-sum.rs +++ b/tests/codegen/simd/simd-wide-sum.rs @@ -10,7 +10,7 @@ #![crate_type = "lib"] #![feature(portable_simd)] -use std::simd::{Simd, SimdUint}; +use std::simd::prelude::*; const N: usize = 16; #[no_mangle] diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs index 2529e531e30..cc9831fff96 100644 --- a/tests/incremental/delayed_span_bug.rs +++ b/tests/incremental/delayed_span_bug.rs @@ -1,8 +1,8 @@ // revisions: cfail1 cfail2 // should-ice -// error-pattern: delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)] +// error-pattern: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)] #![feature(rustc_attrs)] -#[rustc_error(delay_span_bug_from_inside_query)] +#[rustc_error(span_delayed_bug_from_inside_query)] fn main() {} diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff index 9bfd46231c4..8363783e64e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff index dba50b1428e..19326b6a933 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff index 33fe4628d83..0d1e2430ce3 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff index b2d561911de..35f1e5ba796 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 1751b0de2f1..ddfe2e8c831 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index 858a9d33ddf..861295faa5a 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 51707042075..cbb639edc53 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 9141a6c67be..656846e9f97 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -28,16 +28,16 @@ scope 12 { scope 13 (inlined NonNull::<T>::new_unchecked::runtime::<[bool; 0]>) { debug ptr => _6; - scope 14 (inlined ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut [bool; 0]>::is_null) { debug self => _6; let mut _9: *mut u8; scope 15 { - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _9; - scope 17 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 17 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _9; scope 18 { - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _9; } } diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff index cc96cbef2f5..9b0093c454e 100644 --- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-abort.diff @@ -30,7 +30,7 @@ StorageLive(_4); StorageLive(_5); _5 = _3; - _4 = ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> [return: bb1, unwind unreachable]; + _4 = std::ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> [return: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff index ebeb8619d73..635a214251b 100644 --- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff @@ -30,7 +30,7 @@ StorageLive(_4); StorageLive(_5); _5 = _3; - _4 = ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> [return: bb1, unwind continue]; + _4 = std::ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> [return: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 50189d192ce..eaea5db77c9 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -69,7 +69,7 @@ bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); -+ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): ptr::alignment::AlignmentEnum32) }}; ++ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; StorageDead(_10); StorageDead(_2); StorageLive(_3); @@ -78,7 +78,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 6966762a1b8..f2c2504f802 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -67,7 +67,7 @@ bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); -+ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): ptr::alignment::AlignmentEnum32) }}; ++ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}; StorageDead(_10); StorageDead(_2); StorageLive(_3); @@ -76,7 +76,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue]; } bb5: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index 08a185bad9c..d31a9a5c079 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -69,7 +69,7 @@ bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); -+ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): ptr::alignment::AlignmentEnum64) }}; ++ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); StorageDead(_2); StorageLive(_3); @@ -78,7 +78,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index 6501cb85e8a..62e05a68955 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -67,7 +67,7 @@ bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); -+ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): ptr::alignment::AlignmentEnum64) }}; ++ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}; StorageDead(_10); StorageDead(_2); StorageLive(_3); @@ -76,7 +76,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; } bb5: { diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 49f685cfacd..73a3be7f301 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -30,7 +30,7 @@ fn int_range(_1: usize, _2: usize) -> () { scope 7 { } } - scope 8 (inlined cmp::impls::<impl PartialOrd for usize>::lt) { + scope 8 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) { debug self => _6; debug other => _7; let mut _8: usize; diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir index 630babaa821..713d6cc558a 100644 --- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir @@ -24,16 +24,16 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { debug src => _1; scope 7 (inlined intrinsics::is_aligned_and_not_null::<u32>) { debug ptr => _1; - scope 8 (inlined ptr::const_ptr::<impl *const u32>::is_null) { + scope 8 (inlined std::ptr::const_ptr::<impl *const u32>::is_null) { debug self => _1; let mut _3: *const u8; scope 9 { - scope 10 (inlined ptr::const_ptr::<impl *const T>::is_null::runtime_impl) { + scope 10 (inlined std::ptr::const_ptr::<impl *const T>::is_null::runtime_impl) { debug ptr => _3; - scope 11 (inlined ptr::const_ptr::<impl *const u8>::addr) { + scope 11 (inlined std::ptr::const_ptr::<impl *const u8>::addr) { debug self => _3; scope 12 { - scope 13 (inlined ptr::const_ptr::<impl *const u8>::cast::<()>) { + scope 13 (inlined std::ptr::const_ptr::<impl *const u8>::cast::<()>) { debug self => _3; } } @@ -41,7 +41,7 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { } } } - scope 14 (inlined ptr::const_ptr::<impl *const u32>::is_aligned) { + scope 14 (inlined std::ptr::const_ptr::<impl *const u32>::is_aligned) { debug self => _1; scope 15 (inlined align_of::<u32>) { } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir index 91c3731f492..cd734b10fea 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -33,7 +33,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { scope 7 { } } - scope 8 (inlined cmp::impls::<impl PartialOrd for u32>::lt) { + scope 8 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) { debug self => _7; debug other => _8; let mut _9: u32; diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir index f76de02c9d1..3342da545ae 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -33,7 +33,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { scope 7 { } } - scope 8 (inlined cmp::impls::<impl PartialOrd for u32>::lt) { + scope 8 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) { debug self => _7; debug other => _8; let mut _9: u32; diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir index a7824f36d50..6ed3d73b11d 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir @@ -17,7 +17,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> { scope 4 { } } - scope 5 (inlined cmp::impls::<impl PartialOrd for u32>::lt) { + scope 5 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) { debug self => _2; debug other => _3; let mut _4: u32; diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir index 83c9e6c1af2..a030647deae 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir @@ -17,7 +17,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> { scope 4 { } } - scope 5 (inlined cmp::impls::<impl PartialOrd for u32>::lt) { + scope 5 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) { debug self => _2; debug other => _3; let mut _4: u32; diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 548767dca0d..05f16cdacce 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -30,48 +30,48 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:8:25: 8:39}, _2 debug b => _6; debug c => _8; debug d => _10; - scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { + scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) { debug self => _11; debug other => _13; let mut _14: &usize; let mut _15: &usize; - scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { + scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) { debug self => _14; debug other => _15; let mut _16: usize; let mut _17: usize; } } - scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { + scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) { debug self => _19; debug other => _21; let mut _22: &usize; let mut _23: &usize; - scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { + scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) { debug self => _22; debug other => _23; let mut _24: usize; let mut _25: usize; } } - scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { + scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) { debug self => _27; debug other => _29; let mut _30: &usize; let mut _31: &usize; - scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { + scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) { debug self => _30; debug other => _31; let mut _32: usize; let mut _33: usize; } } - scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { + scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) { debug self => _35; debug other => _37; let mut _38: &usize; let mut _39: &usize; - scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { + scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) { debug self => _38; debug other => _39; let mut _40: usize; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index dfdb1c9f259..e4d9060d4cf 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -22,17 +22,17 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { let mut _6: *mut u32; let mut _9: &[&str]; scope 5 { - scope 10 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { + scope 10 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { debug self => _5; } - scope 11 (inlined ptr::mut_ptr::<impl *mut u32>::add) { + scope 11 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) { debug self => _6; debug count => _2; scope 12 { } } } - scope 6 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { + scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) { debug self => _5; let mut _10: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index dfdb1c9f259..e4d9060d4cf 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -22,17 +22,17 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { let mut _6: *mut u32; let mut _9: &[&str]; scope 5 { - scope 10 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { + scope 10 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { debug self => _5; } - scope 11 (inlined ptr::mut_ptr::<impl *mut u32>::add) { + scope 11 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) { debug self => _6; debug count => _2; scope 12 { } } } - scope 6 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { + scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) { debug self => _5; let mut _10: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { 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 d7da0337dbf..0d95f81c37c 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 @@ -24,10 +24,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> let _6: usize; scope 5 { debug new_len => _6; - scope 10 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { + scope 10 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { debug self => _5; } - scope 11 (inlined ptr::mut_ptr::<impl *mut u32>::add) { + scope 11 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) { debug self => _7; debug count => _3; scope 12 { @@ -37,7 +37,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> debug data => _8; debug len => _6; let mut _9: *mut (); - scope 14 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut u32>::cast::<()>) { debug self => _8; } scope 15 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { @@ -52,7 +52,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> } } } - scope 6 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { + scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) { debug self => _5; let mut _15: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { @@ -88,9 +88,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> StorageLive(_11); StorageLive(_10); _10 = _9 as *const () (PointerCoercion(MutToConstPointer)); - _11 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; + _11 = std::ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; StorageDead(_10); - _12 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; + _12 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; StorageDead(_11); _13 = (_12.1: *mut [u32]); StorageDead(_12); 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 d7da0337dbf..0d95f81c37c 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 @@ -24,10 +24,10 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> let _6: usize; scope 5 { debug new_len => _6; - scope 10 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { + scope 10 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { debug self => _5; } - scope 11 (inlined ptr::mut_ptr::<impl *mut u32>::add) { + scope 11 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) { debug self => _7; debug count => _3; scope 12 { @@ -37,7 +37,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> debug data => _8; debug len => _6; let mut _9: *mut (); - scope 14 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { + scope 14 (inlined std::ptr::mut_ptr::<impl *mut u32>::cast::<()>) { debug self => _8; } scope 15 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { @@ -52,7 +52,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> } } } - scope 6 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { + scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) { debug self => _5; let mut _15: *const [u32]; scope 7 (inlined std::ptr::metadata::<[u32]>) { @@ -88,9 +88,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> StorageLive(_11); StorageLive(_10); _10 = _9 as *const () (PointerCoercion(MutToConstPointer)); - _11 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; + _11 = std::ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; StorageDead(_10); - _12 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; + _12 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; StorageDead(_11); _13 = (_12.1: *mut [u32]); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 89009864c32..c58b630a0c3 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -45,16 +45,16 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { debug ptr => _9; - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) { debug self => _9; let mut _24: *mut u8; scope 17 { - scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _24; - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _24; scope 20 { - scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _24; } } @@ -71,7 +71,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 10 { } } - scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { + scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) { debug self => _4; debug count => _6; scope 12 { diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 3d76bab7ce7..1a805f0fd8d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -45,16 +45,16 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { debug ptr => _9; - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) { debug self => _9; let mut _24: *mut u8; scope 17 { - scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _24; - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _24; scope 20 { - scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _24; } } @@ -71,7 +71,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 10 { } } - scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { + scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) { debug self => _4; debug count => _6; scope 12 { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 146fa57a0b1..09075eed6a9 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -42,16 +42,16 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { debug ptr => _9; - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) { debug self => _9; let mut _22: *mut u8; scope 17 { - scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _22; - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _22; scope 20 { - scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _22; } } @@ -68,7 +68,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 10 { } } - scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { + scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) { debug self => _4; debug count => _6; scope 12 { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index e8586cec981..47b84746468 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -42,16 +42,16 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { debug ptr => _9; - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) { debug self => _9; let mut _22: *mut u8; scope 17 { - scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _22; - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _22; scope 20 { - scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _22; } } @@ -68,7 +68,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 10 { } } - scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { + scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) { debug self => _4; debug count => _6; scope 12 { diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index ac1de7b4c90..db6922968ae 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -39,7 +39,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 8 { } } - scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::lt) { + scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) { debug self => _7; debug other => _8; let mut _9: usize; diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index 3c49ecf95a1..81d1832eebb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -39,7 +39,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 8 { } } - scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::lt) { + scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) { debug self => _7; debug other => _8; let mut _9: usize; diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index f3760463fe0..5ed7ca5e2b8 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -47,16 +47,16 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { debug ptr => _9; - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) { debug self => _9; let mut _24: *mut u8; scope 17 { - scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _24; - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _24; scope 20 { - scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _24; } } @@ -73,7 +73,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 10 { } } - scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { + scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) { debug self => _4; debug count => _6; scope 12 { diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index e63f8b89308..bbb979d23b3 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -47,16 +47,16 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 14 { scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { debug ptr => _9; - scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { + scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) { debug self => _9; let mut _24: *mut u8; scope 17 { - scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { + scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { debug ptr => _24; - scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { + scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) { debug self => _24; scope 20 { - scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { + scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) { debug self => _24; } } @@ -73,7 +73,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 10 { } } - scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { + scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) { debug self => _4; debug count => _6; scope 12 { diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir index 566b6af95ba..9c4d6da296d 100644 --- a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -75,7 +75,7 @@ fn array_casts() -> () { StorageLive(_6); StorageLive(_7); _7 = _2; - _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> [return: bb1, unwind unreachable]; + _6 = std::ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> [return: bb1, unwind unreachable]; } bb1: { @@ -101,7 +101,7 @@ fn array_casts() -> () { StorageLive(_16); StorageLive(_17); _17 = _9; - _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> [return: bb2, unwind unreachable]; + _16 = std::ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> [return: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index d0d3176320b..ca064ab2b8f 100644 --- a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -75,7 +75,7 @@ fn array_casts() -> () { StorageLive(_6); StorageLive(_7); _7 = _2; - _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> [return: bb1, unwind continue]; + _6 = std::ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> [return: bb1, unwind continue]; } bb1: { @@ -101,7 +101,7 @@ fn array_casts() -> () { StorageLive(_16); StorageLive(_17); _17 = _9; - _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> [return: bb2, unwind continue]; + _16 = std::ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> [return: bb2, unwind continue]; } bb2: { diff --git a/tests/run-make/no-builtins-lto/Makefile b/tests/run-make/no-builtins-lto/Makefile index c8f05d9918b..c7be4836466 100644 --- a/tests/run-make/no-builtins-lto/Makefile +++ b/tests/run-make/no-builtins-lto/Makefile @@ -1,9 +1,15 @@ include ../tools.mk +# only-x86_64 + +# We want to check that `no_builtins` is correctly participating in LTO. +# First, verify that the `foo::foo` symbol can be found when linking. +# Next, verify that `memcpy` can be customized using `no_builtins` under LTO. +# Others will use the built-in memcpy. + all: - # Compile a `#![no_builtins]` rlib crate - $(RUSTC) no_builtins.rs - # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't - # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by - # grepping the linker arguments. - $(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib' + $(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 foo.rs + $(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 no_builtins.rs + $(RUSTC) main.rs -C lto -C opt-level=2 -C debuginfo=0 -C save-temps -C metadata=1 -C codegen-units=1 + "$(LLVM_BIN_DIR)"/llvm-dis $(TMPDIR)/main.main.*-cgu.0.rcgu.lto.input.bc -o $(TMPDIR)/lto.ll + cat "$(TMPDIR)"/lto.ll | "$(LLVM_FILECHECK)" filecheck.lto.txt diff --git a/tests/run-make/no-builtins-lto/filecheck.lto.txt b/tests/run-make/no-builtins-lto/filecheck.lto.txt new file mode 100644 index 00000000000..79dc3a51501 --- /dev/null +++ b/tests/run-make/no-builtins-lto/filecheck.lto.txt @@ -0,0 +1,17 @@ +CHECK: define{{.*}} void @bar +CHECK-NEXT: call void @no_builtins +CHECK-NEXT: call void @llvm.memcpy + +CHECK: define{{.*}} i32 @main +CHECK: call void @bar + +CHECK: define{{.*}} void @foo +CHECK-NEXT: call void @llvm.memcpy + +CHECK: define{{.*}} void @no_builtins +CHECK-SAME: #[[ATTR:[0-9]+]] { +CHECK: call void @foo +CHECK-NEXT: call{{.*}} @memcpy + +CHECK: attributes #[[ATTR]] +CHECK-SAME: no-builtins diff --git a/tests/run-make/no-builtins-lto/foo.rs b/tests/run-make/no-builtins-lto/foo.rs new file mode 100644 index 00000000000..f09ac40b152 --- /dev/null +++ b/tests/run-make/no-builtins-lto/foo.rs @@ -0,0 +1,33 @@ +#![feature(lang_items, no_core)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[inline(never)] +#[no_mangle] +pub unsafe fn foo(dest: *mut u8, src: *const u8) { + // should call `@llvm.memcpy`. + memcpy(dest, src, 1024); +} + +#[no_mangle] +#[inline(never)] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, _n: usize) -> *mut u8 { + *dest = 0; + return src as *mut u8; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} +impl Copy for *mut u8 {} +impl Copy for *const u8 {} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} diff --git a/tests/run-make/no-builtins-lto/main.rs b/tests/run-make/no-builtins-lto/main.rs index 890c999c8cc..4421a2afbce 100644 --- a/tests/run-make/no-builtins-lto/main.rs +++ b/tests/run-make/no-builtins-lto/main.rs @@ -1,3 +1,29 @@ +#![feature(no_core, start, lang_items)] +#![no_std] +// We use `no_core` to reduce the LTO products is small enough. +#![no_core] + extern crate no_builtins; +extern crate foo; + +#[cfg_attr(unix, link(name = "c"))] +#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] +extern "C" {} + +#[start] +fn main(_: isize, p: *const *const u8) -> isize { + // Make sure the symbols are retained. + unsafe { bar(*p as *mut u8, *p); } + 0 +} + +#[no_mangle] +#[inline(never)] +pub unsafe extern "C" fn bar(dest: *mut u8, src: *const u8) { + no_builtins::no_builtins(dest, src); + // should call `@llvm.memcpy` + foo::memcpy(dest, src, 1024); +} -fn main() {} +#[lang = "eh_personality"] +fn eh_personality() {} diff --git a/tests/run-make/no-builtins-lto/no_builtins.rs b/tests/run-make/no-builtins-lto/no_builtins.rs index 5d001031a57..33ed68e3aee 100644 --- a/tests/run-make/no-builtins-lto/no_builtins.rs +++ b/tests/run-make/no-builtins-lto/no_builtins.rs @@ -1,2 +1,15 @@ +#![feature(lang_items, no_core)] +#![no_std] +#![no_core] #![crate_type = "lib"] #![no_builtins] + +extern crate foo; + +#[no_mangle] +pub unsafe fn no_builtins(dest: *mut u8, src: *const u8) { + // There should be no "undefined reference to `foo::foo'". + foo::foo(dest, src); + // should call `@memcpy` instead of `@llvm.memcpy`. + foo::memcpy(dest, src, 1024); +} diff --git a/tests/run-make/valid-print-requests/valid-print-requests.stderr b/tests/run-make/valid-print-requests/valid-print-requests.stderr index 4f57550c29a..22bb102f9c9 100644 --- a/tests/run-make/valid-print-requests/valid-print-requests.stderr +++ b/tests/run-make/valid-print-requests/valid-print-requests.stderr @@ -1,2 +1,2 @@ -error: unknown print request `uwu`. Valid print requests are: `crate-name`, `file-names`, `sysroot`, `target-libdir`, `cfg`, `calling-conventions`, `target-list`, `target-cpus`, `target-features`, `relocation-models`, `code-models`, `tls-models`, `native-static-libs`, `stack-protector-strategies`, `target-spec-json`, `all-target-specs-json`, `link-args`, `split-debuginfo`, `deployment-target` +error: unknown print request `uwu`. Valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` diff --git a/tests/run-make/wasm-spurious-import/Makefile b/tests/run-make/wasm-builtins-import/Makefile index ff9dfeac6d0..ff9dfeac6d0 100644 --- a/tests/run-make/wasm-spurious-import/Makefile +++ b/tests/run-make/wasm-builtins-import/Makefile diff --git a/tests/run-make/wasm-spurious-import/main.rs b/tests/run-make/wasm-builtins-import/main.rs index fcbead5e28b..5eb99df6ff7 100644 --- a/tests/run-make/wasm-spurious-import/main.rs +++ b/tests/run-make/wasm-builtins-import/main.rs @@ -8,7 +8,8 @@ fn my_panic(_info: &core::panic::PanicInfo) -> ! { #[no_mangle] pub fn multer(a: i128, b: i128) -> i128 { - // Trigger usage of the __multi3 compiler intrinsic which then leads to an imported - // panic function in case of a bug. We verify that no imports exist in our verifier. + // Trigger usage of the __multi3 compiler intrinsic which then leads to an imported function + // such as panic or __multi3 (externally defined) in case of a bug. We verify that + // no imports exist in our verifier. a * b } diff --git a/tests/run-make/wasm-spurious-import/verify.js b/tests/run-make/wasm-builtins-import/verify.js index d3b2101b662..d3b2101b662 100644 --- a/tests/run-make/wasm-spurious-import/verify.js +++ b/tests/run-make/wasm-builtins-import/verify.js diff --git a/tests/rustdoc-gui/where-whitespace.goml b/tests/rustdoc-gui/where-whitespace.goml index 69e6c3356a4..da104fa4011 100644 --- a/tests/rustdoc-gui/where-whitespace.goml +++ b/tests/rustdoc-gui/where-whitespace.goml @@ -3,15 +3,15 @@ go-to: "file://" + |DOC_PATH| + "/lib2/trait.Whitespace.html" show-text: true // First, we check in the trait definition if the where clause is "on its own" (not on the same // line than "pub trait Whitespace<Idx>"). -compare-elements-position-false: (".item-decl code", ".where.fmt-newline", ("y")) +compare-elements-position-false: (".item-decl code", "div.where", ("y")) // And that the code following it isn't on the same line either. -compare-elements-position-false: (".item-decl .fn", ".where.fmt-newline", ("y")) +compare-elements-position-false: (".item-decl .fn", "div.where", ("y")) go-to: "file://" + |DOC_PATH| + "/lib2/struct.WhereWhitespace.html" // We make the screen a bit wider to ensure that the trait impl is on one line. set-window-size: (915, 915) -compare-elements-position-false: ("#method\.new .fn", "#method\.new .where.fmt-newline", ("y")) +compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ("y")) // We ensure that both the trait name and the struct name are on the same line in // "impl<K, T> Whitespace<&K> for WhereWhitespace<T>". compare-elements-position: ( @@ -22,6 +22,6 @@ compare-elements-position: ( // And we now check that the where condition isn't on the same line. compare-elements-position-false: ( "#trait-implementations-list .impl h3 .trait", - "#trait-implementations-list .impl h3 .where.fmt-newline", + "#trait-implementations-list .impl h3 div.where", ("y"), ) diff --git a/tests/rustdoc-js-std/simd-type-signatures.js b/tests/rustdoc-js-std/simd-type-signatures.js index 5c7cf372bce..c07f15dcbe8 100644 --- a/tests/rustdoc-js-std/simd-type-signatures.js +++ b/tests/rustdoc-js-std/simd-type-signatures.js @@ -13,27 +13,27 @@ const EXPECTED = [ { 'path': 'std::simd::prelude::Simd', 'name': 'simd_max', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_max' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+N%3E/method.simd_max' }, { 'path': 'std::simd::prelude::Simd', 'name': 'simd_min', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_min' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+N%3E/method.simd_min' }, { 'path': 'std::simd::prelude::Simd', 'name': 'simd_clamp', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_clamp' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+N%3E/method.simd_clamp' }, { 'path': 'std::simd::prelude::Simd', 'name': 'saturating_add', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+LANES%3E/method.saturating_add' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+N%3E/method.saturating_add' }, { 'path': 'std::simd::prelude::Simd', 'name': 'saturating_sub', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+LANES%3E/method.saturating_sub' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+N%3E/method.saturating_sub' }, ], }, @@ -43,27 +43,27 @@ const EXPECTED = [ { 'path': 'std::simd::prelude::Simd', 'name': 'simd_max', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_max' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+N%3E/method.simd_max' }, { 'path': 'std::simd::prelude::Simd', 'name': 'simd_min', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_min' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+N%3E/method.simd_min' }, { 'path': 'std::simd::prelude::Simd', 'name': 'simd_clamp', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_clamp' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+N%3E/method.simd_clamp' }, { 'path': 'std::simd::prelude::Simd', 'name': 'saturating_add', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+LANES%3E/method.saturating_add' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+N%3E/method.saturating_add' }, { 'path': 'std::simd::prelude::Simd', 'name': 'saturating_sub', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+LANES%3E/method.saturating_sub' + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+N%3E/method.saturating_sub' }, ], }, diff --git a/tests/rustdoc-ui/error-in-impl-trait/README.md b/tests/rustdoc-ui/error-in-impl-trait/README.md index 1176a4a8c4c..d969ab10ef5 100644 --- a/tests/rustdoc-ui/error-in-impl-trait/README.md +++ b/tests/rustdoc-ui/error-in-impl-trait/README.md @@ -1,5 +1,5 @@ Each of these needs to be in a separate file, -because the `delay_span_bug` ICE in rustdoc won't be triggerred +because the `span_delayed_bug` ICE in rustdoc won't be triggerred if even a single other error was emitted. However, conceptually they are all testing basically the same thing. diff --git a/tests/rustdoc-ui/unescaped_backticks.rs b/tests/rustdoc-ui/unescaped_backticks.rs index e960e9f59e9..e813fba4717 100644 --- a/tests/rustdoc-ui/unescaped_backticks.rs +++ b/tests/rustdoc-ui/unescaped_backticks.rs @@ -190,7 +190,7 @@ pub fn complicated_markdown() {} pub mod mir {} pub mod rustc { - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to + /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg to //~^ ERROR unescaped backtick /// ensure it gets used. pub fn ty_error_with_message() {} diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr index 2b4e491b1fe..bd21dcb6e1a 100644 --- a/tests/rustdoc-ui/unescaped_backticks.stderr +++ b/tests/rustdoc-ui/unescaped_backticks.stderr @@ -64,19 +64,19 @@ LL | /// `cfg=... and not `#[cfg_attr]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:193:91 + --> $DIR/unescaped_backticks.rs:193:93 | -LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to - | ^ +LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg to + | ^ | help: the closing backtick of an inline code may be missing | -LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to - | + +LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg` to + | + help: if you meant to use a literal backtick, escape it | -LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given \`msg to - | + +LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given \`msg to + | + error: unescaped backtick --> $DIR/unescaped_backticks.rs:202:34 diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html index 46be00a0804..7d2a2589133 100644 --- a/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html @@ -1 +1 @@ -<script type="text/json" id="notable-traits-data">{"&'static [SomeStruct]":"<h3>Notable traits for <code>&amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\">SomeTrait</a> for &amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</span>"}</script> \ No newline at end of file +<script type="text/json" id="notable-traits-data">{"&'static [SomeStruct]":"<h3>Notable traits for <code>&amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</code></h3><pre><code><div class=\"where\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\">SomeTrait</a> for &amp;[<a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\">SomeStruct</a>]</div>"}</script> \ No newline at end of file diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html index f592e3b375c..9f71677cf4f 100644 --- a/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html @@ -1 +1 @@ -<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></span>"}</script> \ No newline at end of file +<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre><code><div class=\"where\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></div>"}</script> \ No newline at end of file diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html index e8f4f600045..38689c79f1a 100644 --- a/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html @@ -1 +1 @@ -<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></span>","Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre><code><span class=\"where fmt-newline\">impl&lt;T: <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</span>"}</script> \ No newline at end of file +<script type="text/json" id="notable-traits-data">{"SomeStruct":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></code></h3><pre><code><div class=\"where\">impl <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\">SomeStruct</a></div>","Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre><code><div class=\"where\">impl&lt;T: <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</div>"}</script> \ No newline at end of file diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html index e7909669b15..c137be9e3a5 100644 --- a/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html @@ -1 +1 @@ -<script type="text/json" id="notable-traits-data">{"Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre><code><span class=\"where fmt-newline\">impl&lt;T: <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</span>"}</script> \ No newline at end of file +<script type="text/json" id="notable-traits-data">{"Wrapper<Self>":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</code></h3><pre><code><div class=\"where\">impl&lt;T: <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a>&gt; <a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\">SomeTrait</a> for <a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\">Wrapper</a>&lt;T&gt;</div>"}</script> \ No newline at end of file diff --git a/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html index 5f54b7522ae..cce8739df16 100644 --- a/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html @@ -1 +1 @@ -<script type="text/json" id="notable-traits-data">{"Odd":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></code></h3><pre><code><span class=\"where fmt-newline\">impl <a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\">Iterator</a> for <a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></span><span class=\"where fmt-newline\"> type <a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\">Item</a> = <a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\">usize</a>;</span>"}</script> \ No newline at end of file +<script type="text/json" id="notable-traits-data">{"Odd":"<h3>Notable traits for <code><a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></code></h3><pre><code><div class=\"where\">impl <a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\">Iterator</a> for <a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\">Odd</a></div><div class=\"where\"> type <a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\">Item</a> = <a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\">usize</a>;</div>"}</script> \ No newline at end of file diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/rfc-2632-const-trait-impl.rs index 7f56b2ffeb8..6f264969e54 100644 --- a/tests/rustdoc/rfc-2632-const-trait-impl.rs +++ b/tests/rustdoc/rfc-2632-const-trait-impl.rs @@ -23,7 +23,7 @@ pub trait Tr<T> { // @!has - '//section[@id="method.a"]/h4[@class="code-header"]' '~const' // @has - '//section[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const' - // @has - '//section[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn' + // @has - '//section[@id="method.a"]/h4[@class="code-header"]/div[@class="where"]' ': Fn' fn a<A: /* ~const */ Fn() + ~const Destruct>() where Option<A>: /* ~const */ Fn() + ~const Destruct, @@ -35,7 +35,7 @@ pub trait Tr<T> { // @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]' '~const' // @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where"]' '~const' -// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn' +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header"]/div[@class="where"]' ': Fn' impl<T: /* ~const */ Fn() + ~const Destruct> const Tr<T> for T where Option<T>: /* ~const */ Fn() + ~const Destruct, @@ -49,8 +49,8 @@ where // @!has foo/fn.foo.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '~const' // @has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Fn' -// @!has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' '~const' -// @has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' ': Fn' +// @!has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' '~const' +// @has - '//pre[@class="rust item-decl"]/code/div[@class="where"]' ': Fn' pub const fn foo<F: /* ~const */ Fn() + ~const Destruct>() where Option<F>: /* ~const */ Fn() + ~const Destruct, @@ -62,7 +62,7 @@ impl<T> S<T> { // @!has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const' // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Fn' // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const' - // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Fn' + // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/div[@class="where"]' ': Fn' pub const fn foo<B, C: /* ~const */ Fn() + ~const Destruct>() where B: /* ~const */ Fn() + ~const Destruct, diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs index ff84352d716..bea25c75aa4 100644 --- a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs +++ b/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs @@ -13,14 +13,14 @@ pub struct Pair<A, B> { // @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 -// @count - '//span[@class="where fmt-newline"]' 0 +// @count - '//div[@class="where"]' 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 +// @count - '//div[@class="where"]' 2 pub type ReadWrite<R, W> = Pair<R, W> where R: std::io::Read, @@ -30,5 +30,5 @@ where // @count - '//*[@id="aliased-type"]' 1 // @count - '//*[@id="variants"]' 0 // @count - '//*[@id="fields"]' 1 -// @count - '//span[@class="where fmt-newline"]' 0 +// @count - '//div[@class="where"]' 0 pub type VecPair<U, V> = Pair<Vec<U>, Vec<V>>; diff --git a/tests/rustdoc/where.SWhere_Echo_impl.html b/tests/rustdoc/where.SWhere_Echo_impl.html index 7517eb090f4..726196281a5 100644 --- a/tests/rustdoc/where.SWhere_Echo_impl.html +++ b/tests/rustdoc/where.SWhere_Echo_impl.html @@ -1,2 +1,2 @@ -<h3 class="code-header">impl<D> <a class="struct" href="struct.Delta.html" title="struct foo::Delta">Delta</a><D><span class="where fmt-newline">where - D: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</span></h3> \ No newline at end of file +<h3 class="code-header">impl<D> <a class="struct" href="struct.Delta.html" title="struct foo::Delta">Delta</a><D><div class="where">where + D: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</div></h3> \ No newline at end of file diff --git a/tests/rustdoc/where.bravo_trait_decl.html b/tests/rustdoc/where.bravo_trait_decl.html index 00524201a8a..3f1c994b0b2 100644 --- a/tests/rustdoc/where.bravo_trait_decl.html +++ b/tests/rustdoc/where.bravo_trait_decl.html @@ -1,5 +1,5 @@ -<code>pub trait Bravo<B><span class="where fmt-newline">where - B: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</span>{ +<code>pub trait Bravo<B><div class="where">where + B: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</div>{ // Required method fn <a href="#tymethod.get" class="fn">get</a>(&self, B: B); }</code> \ No newline at end of file diff --git a/tests/rustdoc/where.charlie_fn_decl.html b/tests/rustdoc/where.charlie_fn_decl.html index 8e3bc8b01ec..4dd410435c1 100644 --- a/tests/rustdoc/where.charlie_fn_decl.html +++ b/tests/rustdoc/where.charlie_fn_decl.html @@ -1,2 +1,2 @@ -<code>pub fn charlie<C>()<span class="where fmt-newline">where - C: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</span></code> \ No newline at end of file +<code>pub fn charlie<C>()<div class="where">where + C: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a>,</div></code> \ No newline at end of file diff --git a/tests/rustdoc/where.golf_type_alias_decl.html b/tests/rustdoc/where.golf_type_alias_decl.html index 8da5402f900..ab60bb262da 100644 --- a/tests/rustdoc/where.golf_type_alias_decl.html +++ b/tests/rustdoc/where.golf_type_alias_decl.html @@ -1,2 +1,2 @@ -<code>pub type Golf<T><span class="where fmt-newline">where - T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span> = <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>;</code> \ No newline at end of file +<code>pub type Golf<T><div class="where">where + T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</div> = <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>;</code> \ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.enum.html b/tests/rustdoc/whitespace-after-where-clause.enum.html index ff4971f33cd..25e02145323 100644 --- a/tests/rustdoc/whitespace-after-where-clause.enum.html +++ b/tests/rustdoc/whitespace-after-where-clause.enum.html @@ -1,5 +1,5 @@ -<pre class="rust item-decl"><code>pub enum Cow<'a, B><span class="where fmt-newline">where - B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{ +<pre class="rust item-decl"><code>pub enum Cow<'a, B><div class="where">where + B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</div>{ Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>), Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), }</code></pre> \ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.struct.html b/tests/rustdoc/whitespace-after-where-clause.struct.html index ca685358633..bc62a3a0015 100644 --- a/tests/rustdoc/whitespace-after-where-clause.struct.html +++ b/tests/rustdoc/whitespace-after-where-clause.struct.html @@ -1,5 +1,5 @@ -<pre class="rust item-decl"><code>pub struct Struct<'a, B><span class="where fmt-newline">where - B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{ +<pre class="rust item-decl"><code>pub struct Struct<'a, B><div class="where">where + B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</div>{ pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>, pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, }</code></pre> \ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.trait.html b/tests/rustdoc/whitespace-after-where-clause.trait.html index 0928b48e6b6..0e25ed86a7c 100644 --- a/tests/rustdoc/whitespace-after-where-clause.trait.html +++ b/tests/rustdoc/whitespace-after-where-clause.trait.html @@ -1,5 +1,5 @@ -<pre class="rust item-decl"><code>pub trait ToOwned<T><span class="where fmt-newline">where - T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{ +<pre class="rust item-decl"><code>pub trait ToOwned<T><div class="where">where + T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</div>{ type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>; // Required methods diff --git a/tests/rustdoc/whitespace-after-where-clause.union.html b/tests/rustdoc/whitespace-after-where-clause.union.html index 40b0c671284..7e0d5f8717a 100644 --- a/tests/rustdoc/whitespace-after-where-clause.union.html +++ b/tests/rustdoc/whitespace-after-where-clause.union.html @@ -1,4 +1,4 @@ -<pre class="rust item-decl"><code>pub union Union<'a, B><span class="where fmt-newline">where - B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{ +<pre class="rust item-decl"><code>pub union Union<'a, B><div class="where">where + B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</div>{ /* private fields */ }</code></pre> \ No newline at end of file diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index bbb49596288..d311be5982d 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -18,10 +18,11 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; +use std::assert_matches::assert_matches; use mir::{mono::Instance, TerminatorKind::*}; use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; -use stable_mir::ty::{RigidTy, TyKind}; +use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy}; use stable_mir::*; use std::io::Write; use std::ops::ControlFlow; @@ -39,6 +40,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { assert_eq!(instances.len(), 2); test_fn(instances[0], "from_u32", "std::char::from_u32", "core"); test_fn(instances[1], "Vec::<u8>::new", "std::vec::Vec::<u8>::new", "alloc"); + test_vec_new(instances[1]); ControlFlow::Continue(()) } @@ -56,6 +58,30 @@ fn test_fn(instance: Instance, expected_trimmed: &str, expected_qualified: &str, assert_eq!(&item.krate().name, krate); } +fn extract_elem_ty(ty: Ty) -> Ty { + match ty.kind() { + TyKind::RigidTy(RigidTy::Adt(_, args)) => { + *args.0[0].expect_ty() + } + _ => unreachable!("Expected Vec ADT, but found: {ty:?}") + } +} + +/// Check signature and type of `Vec::<u8>::new` and its generic version. +fn test_vec_new(instance: mir::mono::Instance) { + let sig = instance.fn_sig(); + assert_matches!(sig.inputs(), &[]); + let elem_ty = extract_elem_ty(sig.output()); + assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8))); + + // Get the signature for Vec::<T>::new. + let item = CrateItem::try_from(instance).unwrap(); + let ty = item.ty(); + let gen_sig = ty.kind().fn_sig().unwrap().skip_binder(); + let gen_ty = extract_elem_ty(gen_sig.output()); + assert_matches!(gen_ty.kind(), TyKind::Param(_)); +} + /// Inspect the instance body fn get_instances(body: mir::Body) -> Vec<Instance> { body.blocks.iter().filter_map(|bb| { diff --git a/tests/ui/asm/aarch64/bad-reg.rs b/tests/ui/asm/aarch64/bad-reg.rs index 9ccb8ed6762..f71418161f2 100644 --- a/tests/ui/asm/aarch64/bad-reg.rs +++ b/tests/ui/asm/aarch64/bad-reg.rs @@ -48,14 +48,14 @@ fn main() { // (except in/lateout which don't conflict) asm!("", in("x0") foo, in("w0") bar); - //~^ ERROR register `x0` conflicts with register `x0` + //~^ ERROR register `w0` conflicts with register `x0` asm!("", in("x0") foo, out("x0") bar); //~^ ERROR register `x0` conflicts with register `x0` asm!("", in("w0") foo, lateout("w0") bar); asm!("", in("v0") foo, in("q0") bar); - //~^ ERROR register `v0` conflicts with register `v0` + //~^ ERROR register `q0` conflicts with register `v0` asm!("", in("v0") foo, out("q0") bar); - //~^ ERROR register `v0` conflicts with register `v0` + //~^ ERROR register `q0` conflicts with register `v0` asm!("", in("v0") foo, lateout("q0") bar); } } diff --git a/tests/ui/asm/aarch64/bad-reg.stderr b/tests/ui/asm/aarch64/bad-reg.stderr index 0ba627dac30..717a788caf6 100644 --- a/tests/ui/asm/aarch64/bad-reg.stderr +++ b/tests/ui/asm/aarch64/bad-reg.stderr @@ -98,11 +98,11 @@ error: register class `preg` can only be used as a clobber, not as an input or o LL | asm!("{}", out(preg) _); | ^^^^^^^^^^^ -error: register `x0` conflicts with register `x0` +error: register `w0` conflicts with register `x0` --> $DIR/bad-reg.rs:50:32 | LL | asm!("", in("x0") foo, in("w0") bar); - | ------------ ^^^^^^^^^^^^ register `x0` + | ------------ ^^^^^^^^^^^^ register `w0` | | | register `x0` @@ -120,19 +120,19 @@ help: use `lateout` instead of `out` to avoid conflict LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ -error: register `v0` conflicts with register `v0` +error: register `q0` conflicts with register `v0` --> $DIR/bad-reg.rs:55:32 | LL | asm!("", in("v0") foo, in("q0") bar); - | ------------ ^^^^^^^^^^^^ register `v0` + | ------------ ^^^^^^^^^^^^ register `q0` | | | register `v0` -error: register `v0` conflicts with register `v0` +error: register `q0` conflicts with register `v0` --> $DIR/bad-reg.rs:57:32 | LL | asm!("", in("v0") foo, out("q0") bar); - | ------------ ^^^^^^^^^^^^^ register `v0` + | ------------ ^^^^^^^^^^^^^ register `q0` | | | register `v0` | diff --git a/tests/ui/asm/x86_64/bad-reg.rs b/tests/ui/asm/x86_64/bad-reg.rs index f5728079a6a..e19221bc04e 100644 --- a/tests/ui/asm/x86_64/bad-reg.rs +++ b/tests/ui/asm/x86_64/bad-reg.rs @@ -56,10 +56,10 @@ fn main() { // (except in/lateout which don't conflict) asm!("", in("eax") foo, in("al") bar); - //~^ ERROR register `al` conflicts with register `ax` + //~^ ERROR register `al` conflicts with register `eax` //~| ERROR `i32` cannot be used with this register class asm!("", in("rax") foo, out("rax") bar); - //~^ ERROR register `ax` conflicts with register `ax` + //~^ ERROR register `rax` conflicts with register `rax` asm!("", in("al") foo, lateout("al") bar); //~^ ERROR `i32` cannot be used with this register class //~| ERROR `i32` cannot be used with this register class diff --git a/tests/ui/asm/x86_64/bad-reg.stderr b/tests/ui/asm/x86_64/bad-reg.stderr index 82b7ebd0fb0..8017008e97d 100644 --- a/tests/ui/asm/x86_64/bad-reg.stderr +++ b/tests/ui/asm/x86_64/bad-reg.stderr @@ -106,21 +106,21 @@ error: register class `mmx_reg` can only be used as a clobber, not as an input o LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ -error: register `al` conflicts with register `ax` +error: register `al` conflicts with register `eax` --> $DIR/bad-reg.rs:58:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` | | - | register `ax` + | register `eax` -error: register `ax` conflicts with register `ax` +error: register `rax` conflicts with register `rax` --> $DIR/bad-reg.rs:61:33 | LL | asm!("", in("rax") foo, out("rax") bar); - | ------------- ^^^^^^^^^^^^^^ register `ax` + | ------------- ^^^^^^^^^^^^^^ register `rax` | | - | register `ax` + | register `rax` | help: use `lateout` instead of `out` to avoid conflict --> $DIR/bad-reg.rs:61:18 diff --git a/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr b/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr index 3234945e0df..7f9324035e4 100644 --- a/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr +++ b/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr @@ -5,7 +5,7 @@ LL | let _array: [u32; <A as Foo>::Y]; | ^ cannot perform const operation using `A` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/associated-item/associated-item-duplicate-bounds.stderr b/tests/ui/associated-item/associated-item-duplicate-bounds.stderr index 0c8dc9d7fd6..8898880586c 100644 --- a/tests/ui/associated-item/associated-item-duplicate-bounds.stderr +++ b/tests/ui/associated-item/associated-item-duplicate-bounds.stderr @@ -5,7 +5,7 @@ LL | links: [u32; A::LINKS], // Shouldn't suggest bounds already there. | ^^^^^^^^ cannot perform const operation using `A` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index f1f22e2342d..ce7fce25993 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -5,7 +5,7 @@ LL | let _: [u8; foo::<T>()]; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:16:23 @@ -14,7 +14,7 @@ LL | let _: [u8; bar::<N>()]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:18:23 @@ -23,7 +23,7 @@ LL | let _: [u8; faz::<'a>(&())]; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:20:23 @@ -32,7 +32,7 @@ LL | let _: [u8; baz::<'a>(&())]; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:21:23 @@ -41,7 +41,7 @@ LL | let _: [u8; faz::<'b>(&())]; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:23:23 @@ -50,7 +50,7 @@ LL | let _: [u8; baz::<'b>(&())]; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:26:23 @@ -59,7 +59,7 @@ LL | let _ = [0; bar::<N>()]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:28:23 @@ -68,7 +68,7 @@ LL | let _ = [0; faz::<'a>(&())]; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:30:23 @@ -77,7 +77,7 @@ LL | let _ = [0; baz::<'a>(&())]; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:31:23 @@ -86,7 +86,7 @@ LL | let _ = [0; faz::<'b>(&())]; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:33:23 @@ -95,7 +95,7 @@ LL | let _ = [0; baz::<'b>(&())]; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:34:24 @@ -104,7 +104,7 @@ LL | let _: Foo<{ foo::<T>() }>; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:35:24 @@ -113,7 +113,7 @@ LL | let _: Foo<{ bar::<N>() }>; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:37:24 @@ -122,7 +122,7 @@ LL | let _: Foo<{ faz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:39:24 @@ -131,7 +131,7 @@ LL | let _: Foo<{ baz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:40:24 @@ -140,7 +140,7 @@ LL | let _: Foo<{ faz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:42:24 @@ -149,7 +149,7 @@ LL | let _: Foo<{ baz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:43:27 @@ -158,7 +158,7 @@ LL | let _ = Foo::<{ foo::<T>() }>; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:44:27 @@ -167,7 +167,7 @@ LL | let _ = Foo::<{ bar::<N>() }>; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:46:27 @@ -176,7 +176,7 @@ LL | let _ = Foo::<{ faz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:48:27 @@ -185,7 +185,7 @@ LL | let _ = Foo::<{ baz::<'a>(&()) }>; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:49:27 @@ -194,7 +194,7 @@ LL | let _ = Foo::<{ faz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:51:27 @@ -203,7 +203,7 @@ LL | let _ = Foo::<{ baz::<'b>(&()) }>; | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0747]: unresolved item provided when a constant was expected --> $DIR/const-arg-in-const-arg.rs:16:23 diff --git a/tests/ui/const-generics/const-argument-if-length.min.stderr b/tests/ui/const-generics/const-argument-if-length.min.stderr index 3ba9ffebd4d..b9d9bcc9270 100644 --- a/tests/ui/const-generics/const-argument-if-length.min.stderr +++ b/tests/ui/const-generics/const-argument-if-length.min.stderr @@ -5,7 +5,7 @@ LL | pad: [u8; is_zst::<T>()], | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/const-argument-if-length.rs:15:12 diff --git a/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr b/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr index 52b7f2a37de..a1254672c9d 100644 --- a/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr +++ b/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr @@ -5,7 +5,7 @@ LL | let _: &'a (); | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr index b836cfeaedb..199546c0883 100644 --- a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr +++ b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr @@ -5,7 +5,7 @@ LL | struct Foo<const N: usize, const M: usize = { N + 1 }>; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-generic-default-expr.rs:9:62 @@ -14,7 +14,7 @@ LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/early/macro_rules-braces.stderr b/tests/ui/const-generics/early/macro_rules-braces.stderr index 49382dbf0bd..32695066801 100644 --- a/tests/ui/const-generics/early/macro_rules-braces.stderr +++ b/tests/ui/const-generics/early/macro_rules-braces.stderr @@ -27,7 +27,7 @@ LL | let _: foo!({{ N }}); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:36:19 @@ -36,7 +36,7 @@ LL | let _: bar!({ N }); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:41:20 @@ -45,7 +45,7 @@ LL | let _: baz!({{ N }}); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:46:19 @@ -54,7 +54,7 @@ LL | let _: biz!({ N }); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index c42226b77f5..f2cc17bc517 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations needed for `Mask<_, LANES>` +error[E0283]: type annotations needed for `Mask<_, N>` --> $DIR/issue-91614.rs:6:9 | LL | let y = Mask::<_, _>::splat(false); @@ -11,12 +11,12 @@ LL | let y = Mask::<_, _>::splat(false); i16 i32 i64 -note: required by a bound in `Mask::<T, LANES>::splat` +note: required by a bound in `Mask::<T, N>::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the type for type parameter `T` is specified | -LL | let y: Mask<_, LANES> = Mask::<_, _>::splat(false); - | ++++++++++++++++ +LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr index 64d1e0bcff4..1f4b892e20f 100644 --- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr @@ -5,7 +5,7 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/array-size-in-generic-struct-param.rs:23:15 @@ -14,7 +14,7 @@ LL | arr: [u8; CFG.arr_size], | ^^^ cannot perform const operation using `CFG` | = help: const parameters may only be used as standalone arguments, i.e. `CFG` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: `Config` is forbidden as the type of a const generic parameter --> $DIR/array-size-in-generic-struct-param.rs:21:21 diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr index d674e3acdff..f454ff4e6c0 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr @@ -5,7 +5,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/dependence_lint.rs:21:37 @@ -14,7 +14,7 @@ LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions warning: cannot use constants which depend on generic parameters in types --> $DIR/dependence_lint.rs:10:9 diff --git a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr index 3b456324819..9c4e3d8583c 100644 --- a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr +++ b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr @@ -5,7 +5,7 @@ LL | type Arr<const N: usize> = [u8; N - 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index ea6f5f69276..2454b311921 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -5,7 +5,7 @@ LL | Condition<{ LHS <= RHS }>: True | ^^^ cannot perform const operation using `LHS` | = help: const parameters may only be used as standalone arguments, i.e. `LHS` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:24 @@ -14,7 +14,7 @@ LL | Condition<{ LHS <= RHS }>: True | ^^^ cannot perform const operation using `RHS` | = help: const parameters may only be used as standalone arguments, i.e. `RHS` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:23:25 @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments, i.e. `I` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:23:36 @@ -32,7 +32,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `J` | = help: const parameters may only be used as standalone arguments, i.e. `J` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr index ef9ee6d7cfc..c504464127a 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr @@ -5,7 +5,7 @@ LL | where Assert::<{N < usize::MAX / 2}>: IsTrue, | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr b/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr index f0e0a4b9711..78717028f65 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr @@ -5,7 +5,7 @@ LL | let _: &'a (); | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0308]: mismatched types --> $DIR/issue-74713.rs:3:10 diff --git a/tests/ui/const-generics/ice-118285-fn-ptr-value.rs b/tests/ui/const-generics/ice-118285-fn-ptr-value.rs new file mode 100644 index 00000000000..b68afb0bc83 --- /dev/null +++ b/tests/ui/const-generics/ice-118285-fn-ptr-value.rs @@ -0,0 +1,5 @@ +struct Checked<const F: fn(usize) -> bool>; +//~^ ERROR function pointers as const generic parameters is forbidden +fn not_one(val: usize) -> bool { val != 1 } +const _: Checked<not_one> = Checked::<not_one>; +fn main() {} diff --git a/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr b/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr new file mode 100644 index 00000000000..46a8a975d50 --- /dev/null +++ b/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr @@ -0,0 +1,10 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/ice-118285-fn-ptr-value.rs:1:25 + | +LL | struct Checked<const F: fn(usize) -> bool>; + | ^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index 4c45339b93b..95f75c32186 100644 --- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -5,7 +5,7 @@ LL | T: Trait<{std::intrinsics::type_name::<T>()}> | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22 diff --git a/tests/ui/const-generics/issue-46511.stderr b/tests/ui/const-generics/issue-46511.stderr index 58c93a1fab4..d57295fa2fa 100644 --- a/tests/ui/const-generics/issue-46511.stderr +++ b/tests/ui/const-generics/issue-46511.stderr @@ -5,7 +5,7 @@ LL | _a: [u8; std::mem::size_of::<&'a mut u8>()] | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0392]: parameter `'a` is never used --> $DIR/issue-46511.rs:3:12 diff --git a/tests/ui/const-generics/issues/issue-67375.min.stderr b/tests/ui/const-generics/issues/issue-67375.min.stderr index 5256d96c876..7671e3c4688 100644 --- a/tests/ui/const-generics/issues/issue-67375.min.stderr +++ b/tests/ui/const-generics/issues/issue-67375.min.stderr @@ -5,7 +5,7 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }], | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0392]: parameter `T` is never used --> $DIR/issue-67375.rs:5:12 diff --git a/tests/ui/const-generics/issues/issue-67945-1.min.stderr b/tests/ui/const-generics/issues/issue-67945-1.min.stderr index eee04eb75a2..1d071da903f 100644 --- a/tests/ui/const-generics/issues/issue-67945-1.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-1.min.stderr @@ -5,7 +5,7 @@ LL | let x: S = MaybeUninit::uninit(); | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:13:45 @@ -14,7 +14,7 @@ LL | let b = &*(&x as *const _ as *const S); | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-1.rs:7:12 diff --git a/tests/ui/const-generics/issues/issue-67945-3.min.stderr b/tests/ui/const-generics/issues/issue-67945-3.min.stderr index 8e6b4b20409..e34869c7938 100644 --- a/tests/ui/const-generics/issues/issue-67945-3.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-3.min.stderr @@ -5,7 +5,7 @@ LL | let x: Option<S> = None; | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-3.rs:9:12 diff --git a/tests/ui/const-generics/issues/issue-67945-4.min.stderr b/tests/ui/const-generics/issues/issue-67945-4.min.stderr index f9520872ddd..280c6f4f2cd 100644 --- a/tests/ui/const-generics/issues/issue-67945-4.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-4.min.stderr @@ -5,7 +5,7 @@ LL | let x: Option<Box<S>> = None; | ^ cannot perform const operation using `S` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-4.rs:8:12 diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr index 3740ced90b1..ecf24a356de 100644 --- a/tests/ui/const-generics/issues/issue-68366.min.stderr +++ b/tests/ui/const-generics/issues/issue-68366.min.stderr @@ -5,7 +5,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {} | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-68366.rs:11:7 diff --git a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr index 3b53e18e6f5..da2fbc52a6c 100644 --- a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr +++ b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr @@ -5,7 +5,7 @@ LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] { | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:6:42 @@ -14,7 +14,7 @@ LL | fn const_param<const N: usize>() -> [u8; N + 1] { | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-80062.stderr b/tests/ui/const-generics/issues/issue-80062.stderr index 5f53dca4bed..5da8e45fac8 100644 --- a/tests/ui/const-generics/issues/issue-80062.stderr +++ b/tests/ui/const-generics/issues/issue-80062.stderr @@ -5,7 +5,7 @@ LL | let _: [u8; sof::<T>()]; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-80375.stderr b/tests/ui/const-generics/issues/issue-80375.stderr index 6abbf1c0f75..015196f8605 100644 --- a/tests/ui/const-generics/issues/issue-80375.stderr +++ b/tests/ui/const-generics/issues/issue-80375.stderr @@ -5,7 +5,7 @@ LL | struct MyArray<const COUNT: usize>([u8; COUNT + 1]); | ^^^^^ cannot perform const operation using `COUNT` | = help: const parameters may only be used as standalone arguments, i.e. `COUNT` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 3c78dd6c780..83c71e07253 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -13,7 +13,7 @@ LL | legacy_const_generics::foo(0, N + 1, 2); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/complex-expression.stderr b/tests/ui/const-generics/min_const_generics/complex-expression.stderr index deabd05a6d5..3affdcf9b03 100644 --- a/tests/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/tests/ui/const-generics/min_const_generics/complex-expression.stderr @@ -5,7 +5,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:13:40 @@ -14,7 +14,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]); | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:17:17 @@ -23,7 +23,7 @@ LL | let _: [u8; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:22:17 @@ -32,7 +32,7 @@ LL | let _ = [0; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:26:45 @@ -41,7 +41,7 @@ LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:29:47 @@ -50,7 +50,7 @@ LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:33:32 @@ -59,7 +59,7 @@ LL | let _: [u8; size_of::<*mut T>() + 1]; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions warning: cannot use constants which depend on generic parameters in types --> $DIR/complex-expression.rs:38:17 diff --git a/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr b/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr index 7726016eb83..909b0476999 100644 --- a/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr +++ b/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr @@ -5,7 +5,7 @@ LL | test::<{ let _: &'a (); 3 },>(); | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations --> $DIR/forbid-non-static-lifetimes.rs:21:16 @@ -14,7 +14,7 @@ LL | [(); (|_: &'a u8| (), 0).1]; | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 16a7687c00b..e9216fc12a2 100644 --- a/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -5,7 +5,7 @@ LL | fn t1() -> [u8; std::mem::size_of::<Self>()]; | ^^^^ cannot perform const operation using `Self` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/self-ty-in-const-1.rs:12:41 diff --git a/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr b/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr index 5a947677678..38b25445f61 100644 --- a/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr +++ b/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr @@ -5,7 +5,7 @@ LL | let x: &'a (); | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index a5e70f6b9e6..320c9c1c84d 100644 --- a/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -11,7 +11,7 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0128]: generic parameters with a default cannot use forward declared identifiers --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21 diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 105683940cf..250366da2a6 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -93,7 +93,7 @@ error[E0080]: could not evaluate static initializer | = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) | -note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` +note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -108,7 +108,7 @@ error[E0080]: could not evaluate static initializer | = note: the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | -note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr` +note: inside `std::ptr::const_ptr::<impl *const ()>::sub_ptr` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `from_ptr_range::<'_, ()>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -124,7 +124,7 @@ error[E0080]: could not evaluate static initializer | = note: out-of-bounds pointer arithmetic: ALLOC10 has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | -note: inside `ptr::const_ptr::<impl *const u32>::add` +note: inside `std::ptr::const_ptr::<impl *const u32>::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `R2` --> $DIR/forbidden_slices.rs:52:25 @@ -183,7 +183,7 @@ error[E0080]: could not evaluate static initializer | = note: out-of-bounds pointer arithmetic: ALLOC11 has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | -note: inside `ptr::const_ptr::<impl *const u64>::add` +note: inside `std::ptr::const_ptr::<impl *const u64>::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `R8` --> $DIR/forbidden_slices.rs:76:25 @@ -196,7 +196,7 @@ error[E0080]: could not evaluate static initializer | = note: `ptr_offset_from_unsigned` called on pointers into different allocations | -note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` +note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -211,7 +211,7 @@ error[E0080]: could not evaluate static initializer | = note: `ptr_offset_from_unsigned` called on pointers into different allocations | -note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` +note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index be75f76b26f..7634ba25210 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -18,7 +18,7 @@ error[E0080]: evaluation of constant value failed | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `ptr::const_ptr::<impl *const u32>::read` +note: inside `std::ptr::const_ptr::<impl *const u32>::read` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `_CONST_READ` --> $DIR/out_of_bounds_read.rs:11:39 @@ -33,7 +33,7 @@ error[E0080]: evaluation of constant value failed | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `ptr::mut_ptr::<impl *mut u32>::read` +note: inside `std::ptr::mut_ptr::<impl *mut u32>::read` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL note: inside `_MUT_READ` --> $DIR/out_of_bounds_read.rs:12:37 diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 60fcd461cde..cba06fdc639 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -17,7 +17,7 @@ error[E0080]: evaluation of constant value failed | note: inside `copy_nonoverlapping::<u32>` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL -note: inside `ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping` +note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `MISALIGNED_COPY` --> $DIR/raw-pointer-ub.rs:22:5 diff --git a/tests/ui/consts/const-eval/size-of-t.stderr b/tests/ui/consts/const-eval/size-of-t.stderr index ff09f5aee1c..418ac6f612c 100644 --- a/tests/ui/consts/const-eval/size-of-t.stderr +++ b/tests/ui/consts/const-eval/size-of-t.stderr @@ -5,7 +5,7 @@ LL | let _arr: [u8; size_of::<T>()]; | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index c608bad2a47..ca7b6645d3f 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -155,7 +155,7 @@ error[E0080]: evaluation of constant value failed | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `ptr::const_ptr::<impl *const u32>::read` +note: inside `std::ptr::const_ptr::<impl *const u32>::read` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNALIGNED_READ` --> $DIR/ub-ref-ptr.rs:66:5 diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr index 7ad53800ad7..32beed5dba0 100644 --- a/tests/ui/consts/issue-miri-1910.stderr +++ b/tests/ui/consts/issue-miri-1910.stderr @@ -5,7 +5,7 @@ error[E0080]: evaluation of constant value failed | note: inside `std::ptr::read::<u8>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL -note: inside `ptr::const_ptr::<impl *const u8>::read` +note: inside `std::ptr::const_ptr::<impl *const u8>::read` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `C` --> $DIR/issue-miri-1910.rs:7:5 diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index ef9f6345691..3e3e8e976be 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -7,7 +7,7 @@ note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `mem::swap_simple::<MaybeUninit<MaybeUninit<u8>>>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -note: inside `ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>` +note: inside `std::ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `swap_nonoverlapping::<MaybeUninit<u8>>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 1ef727e5b0f..4fbb2f00100 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -9,7 +9,7 @@ error[E0080]: evaluation of constant value failed | = note: `ptr_offset_from` called on pointers into different allocations | -note: inside `ptr::const_ptr::<impl *const u8>::offset_from` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `NOT_PTR` --> $DIR/offset_from_ub.rs:24:14 @@ -88,7 +88,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) | -note: inside `ptr::const_ptr::<impl *const u8>::offset_from` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR1` --> $DIR/offset_from_ub.rs:115:14 @@ -101,7 +101,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) | -note: inside `ptr::const_ptr::<impl *const u8>::offset_from` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR2` --> $DIR/offset_from_ub.rs:121:14 diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 8bc59d50ee4..b398b20393f 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -3,7 +3,7 @@ error[E0080]: evaluation of constant value failed | = note: overflowing in-bounds pointer arithmetic | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `BEFORE_START` --> $DIR/offset_ub.rs:7:46 @@ -16,7 +16,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: ALLOC0 has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `AFTER_END` --> $DIR/offset_ub.rs:8:43 @@ -29,7 +29,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: ALLOC1 has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `AFTER_ARRAY` --> $DIR/offset_ub.rs:9:45 @@ -42,7 +42,7 @@ error[E0080]: evaluation of constant value failed | = note: overflowing in-bounds pointer arithmetic | -note: inside `ptr::const_ptr::<impl *const u16>::offset` +note: inside `std::ptr::const_ptr::<impl *const u16>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OVERFLOW` --> $DIR/offset_ub.rs:11:43 @@ -55,7 +55,7 @@ error[E0080]: evaluation of constant value failed | = note: overflowing in-bounds pointer arithmetic | -note: inside `ptr::const_ptr::<impl *const u16>::offset` +note: inside `std::ptr::const_ptr::<impl *const u16>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNDERFLOW` --> $DIR/offset_ub.rs:12:44 @@ -68,7 +68,7 @@ error[E0080]: evaluation of constant value failed | = note: overflowing in-bounds pointer arithmetic | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OVERFLOW_ADDRESS_SPACE` --> $DIR/offset_ub.rs:13:56 @@ -81,7 +81,7 @@ error[E0080]: evaluation of constant value failed | = note: overflowing in-bounds pointer arithmetic | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNDERFLOW_ADDRESS_SPACE` --> $DIR/offset_ub.rs:14:57 @@ -94,7 +94,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: ALLOC2 has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `NEGATIVE_OFFSET` --> $DIR/offset_ub.rs:15:49 @@ -107,7 +107,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: ALLOC3 has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `ZERO_SIZED_ALLOC` --> $DIR/offset_ub.rs:17:50 @@ -120,7 +120,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | -note: inside `ptr::mut_ptr::<impl *mut u8>::offset` +note: inside `std::ptr::mut_ptr::<impl *mut u8>::offset` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL note: inside `DANGLING` --> $DIR/offset_ub.rs:18:42 @@ -133,7 +133,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `NULL_OFFSET_ZERO` --> $DIR/offset_ub.rs:21:50 @@ -146,7 +146,7 @@ error[E0080]: evaluation of constant value failed | = note: out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance) | -note: inside `ptr::const_ptr::<impl *const u8>::offset` +note: inside `std::ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNDERFLOW_ABS` --> $DIR/offset_ub.rs:24:47 diff --git a/tests/ui/consts/raw-ptr-const.rs b/tests/ui/consts/raw-ptr-const.rs index fc774be54df..541c5fd1ab1 100644 --- a/tests/ui/consts/raw-ptr-const.rs +++ b/tests/ui/consts/raw-ptr-const.rs @@ -1,4 +1,4 @@ -// This is a regression test for a `delay_span_bug` during interning when a constant +// This is a regression test for a `span_delayed_bug` during interning when a constant // evaluates to a (non-dangling) raw pointer. For now this errors; potentially it // could also be allowed. diff --git a/tests/ui/generic-associated-types/bugs/issue-88382.stderr b/tests/ui/generic-associated-types/bugs/issue-88382.stderr index 624fe2799e0..9b061528e3b 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88382.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-88382.stderr @@ -16,6 +16,10 @@ note: required by a bound in `do_something` | LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something` +help: consider wrapping the function in a closure + | +LL | do_something(SomeImplementation(), |arg0: &mut std::iter::Empty<usize>| test(/* &mut <_ as Iterable>::Iterator<'_> */)); + | ++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/generics/param-in-ct-in-ty-param-default.stderr b/tests/ui/generics/param-in-ct-in-ty-param-default.stderr index 3d2a26e33c3..03dbb3eb9fc 100644 --- a/tests/ui/generics/param-in-ct-in-ty-param-default.stderr +++ b/tests/ui/generics/param-in-ct-in-ty-param-default.stderr @@ -5,7 +5,7 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr index 83791f0d3af..046d35e4e4a 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: no errors encountered even though `delay_span_bug` issued +error: internal compiler error: no errors encountered even though `span_delayed_bug` issued error: internal compiler error: {OpaqueTypeKey { def_id: DefId(rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }) } }} | diff --git a/tests/ui/imports/no-pub-reexports-but-used.rs b/tests/ui/imports/no-pub-reexports-but-used.rs new file mode 100644 index 00000000000..28991bde829 --- /dev/null +++ b/tests/ui/imports/no-pub-reexports-but-used.rs @@ -0,0 +1,15 @@ +// check-pass +// https://github.com/rust-lang/rust/issues/115966 + +mod m { + pub(crate) type A = u8; +} + +#[warn(unused_imports)] //~ NOTE: the lint level is defined here +pub use m::*; +//~^ WARNING: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough +//~| NOTE: the most public imported item is `pub(crate)` + +fn main() { + let _: A; +} diff --git a/tests/ui/imports/no-pub-reexports-but-used.stderr b/tests/ui/imports/no-pub-reexports-but-used.stderr new file mode 100644 index 00000000000..b693dea1935 --- /dev/null +++ b/tests/ui/imports/no-pub-reexports-but-used.stderr @@ -0,0 +1,20 @@ +warning: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough + --> $DIR/no-pub-reexports-but-used.rs:9:9 + | +LL | pub use m::*; + | ^^^^ + | +note: the most public imported item is `pub(crate)` + --> $DIR/no-pub-reexports-but-used.rs:9:9 + | +LL | pub use m::*; + | ^^^^ + = help: reduce the glob import's visibility or increase visibility of imported items +note: the lint level is defined here + --> $DIR/no-pub-reexports-but-used.rs:8:8 + | +LL | #[warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/imports/reexports.rs b/tests/ui/imports/reexports.rs index cb1a3ebe180..2a1a62834ce 100644 --- a/tests/ui/imports/reexports.rs +++ b/tests/ui/imports/reexports.rs @@ -9,7 +9,7 @@ mod a { //~^ ERROR cannot be re-exported //~| WARNING unused import: `super::foo` pub use super::*; - //~^ WARNING glob import doesn't reexport anything because no candidate is public enough + //~^ WARNING glob import doesn't reexport anything with visibility `pub` because no imported item is public enough //~| WARNING unused import: `super::*` } } diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index 401e422af0f..bf4ba474875 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -56,11 +56,18 @@ note: the lint level is defined here LL | #![warn(unused_imports)] | ^^^^^^^^^^^^^^ -warning: glob import doesn't reexport anything because no candidate is public enough +warning: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough --> $DIR/reexports.rs:11:17 | LL | pub use super::*; | ^^^^^^^^ + | +note: the most public imported item is `pub(a)` + --> $DIR/reexports.rs:11:17 + | +LL | pub use super::*; + | ^^^^^^^^ + = help: reduce the glob import's visibility or increase visibility of imported items warning: unused import: `super::*` --> $DIR/reexports.rs:11:17 diff --git a/tests/ui/intrinsics/const-eval-select-bad.stderr b/tests/ui/intrinsics/const-eval-select-bad.stderr index e6ff9d5a0df..bf91dc72cc1 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.stderr +++ b/tests/ui/intrinsics/const-eval-select-bad.stderr @@ -86,6 +86,10 @@ LL | const_eval_select((true,), foo, baz); found function signature `fn(i32) -> _` note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | const_eval_select((true,), |arg0: bool| foo(/* i32 */), baz); + | ++++++++++++ +++++++++++ error: this argument must be a `const fn` --> $DIR/const-eval-select-bad.rs:42:29 diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr new file mode 100644 index 00000000000..a4fe77f5cbb --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs new file mode 100644 index 00000000000..15a88ebdb11 --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs @@ -0,0 +1,20 @@ +// revisions: x86 x86_64 aarch64 + +// compile-flags: -Zfunction-return=thunk-extern + +//[x86] check-pass +//[x86] needs-llvm-components: x86 +//[x86] compile-flags: --target i686-unknown-linux-gnu + +//[x86_64] check-pass +//[x86_64] needs-llvm-components: x86 +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu + +//[aarch64] check-fail +//[aarch64] needs-llvm-components: aarch64 +//[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//[aarch64] error-pattern: `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr new file mode 100644 index 00000000000..683b3213d07 --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr @@ -0,0 +1,4 @@ +error: `-Zfunction-return=thunk-extern` is only supported on non-large code models + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs new file mode 100644 index 00000000000..f925905de36 --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs @@ -0,0 +1,21 @@ +// revisions: small kernel medium large + +// needs-llvm-components: x86 +// compile-flags: --target x86_64-unknown-linux-gnu -Zfunction-return=thunk-extern + +//[small] check-pass +//[small] compile-flags: -Ccode-model=small + +//[kernel] check-pass +//[kernel] compile-flags: -Ccode-model=kernel + +//[medium] check-pass +//[medium] compile-flags: -Ccode-model=medium + +//[large] check-fail +//[large] compile-flags: -Ccode-model=large +//[large] error-pattern: `-Zfunction-return=thunk-extern` is only supported on non-large code models + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr index 02ca10b2eb6..ec4aea62391 100644 --- a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr +++ b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr @@ -5,7 +5,7 @@ LL | beta: [(); foo::<&'a ()>()], | ^^ cannot perform const operation using `'a` | = note: lifetime parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/issue-64173-unused-lifetimes.rs:4:28 diff --git a/tests/ui/mismatched_types/E0631.stderr b/tests/ui/mismatched_types/E0631.stderr index 410ea4b0b34..9ba8f5035c5 100644 --- a/tests/ui/mismatched_types/E0631.stderr +++ b/tests/ui/mismatched_types/E0631.stderr @@ -48,6 +48,10 @@ note: required by a bound in `foo` | LL | fn foo<F: Fn(usize)>(_: F) {} | ^^^^^^^^^ required by this bound in `foo` +help: consider wrapping the function in a closure + | +LL | foo(|arg0: usize| f(/* u64 */)); + | +++++++++++++ +++++++++++ error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:10:9 @@ -67,6 +71,10 @@ note: required by a bound in `bar` | LL | fn bar<F: Fn<(usize,)>>(_: F) {} | ^^^^^^^^^^^^ required by this bound in `bar` +help: consider wrapping the function in a closure + | +LL | bar(|arg0: usize| f(/* u64 */)); + | +++++++++++++ +++++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/mismatched_types/closure-ref-114180.stderr b/tests/ui/mismatched_types/closure-ref-114180.stderr index 798c4e00aa7..27649822e69 100644 --- a/tests/ui/mismatched_types/closure-ref-114180.stderr +++ b/tests/ui/mismatched_types/closure-ref-114180.stderr @@ -12,6 +12,10 @@ LL | v.sort_by(compare); found closure signature `fn((_,), (_,)) -> _` note: required by a bound in `slice::<impl [T]>::sort_by` --> $SRC_DIR/alloc/src/slice.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | v.sort_by(|arg0, arg1| compare(*arg0, *arg1)); + | ++++++++++++ ++++++++++++++ help: consider adjusting the signature so it borrows its arguments | LL | let compare = |&(a,), &(e,)| todo!(); diff --git a/tests/ui/mismatched_types/fn-variance-1.stderr b/tests/ui/mismatched_types/fn-variance-1.stderr index 5794e606eeb..fdb2e6f0097 100644 --- a/tests/ui/mismatched_types/fn-variance-1.stderr +++ b/tests/ui/mismatched_types/fn-variance-1.stderr @@ -16,6 +16,10 @@ note: required by a bound in `apply` | LL | fn apply<T, F>(t: T, f: F) where F: FnOnce(T) { | ^^^^^^^^^ required by this bound in `apply` +help: consider wrapping the function in a closure + | +LL | apply(&3, |x| takes_mut(&mut *x)); + | +++ +++++++++ error[E0631]: type mismatch in function arguments --> $DIR/fn-variance-1.rs:15:19 @@ -35,6 +39,10 @@ note: required by a bound in `apply` | LL | fn apply<T, F>(t: T, f: F) where F: FnOnce(T) { | ^^^^^^^^^ required by this bound in `apply` +help: consider wrapping the function in a closure + | +LL | apply(&mut 3, |x| takes_imm(&*x)); + | +++ +++++ error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr index 3db9803d58f..0ed57466e9c 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr +++ b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr @@ -13,6 +13,10 @@ LL | let _has_inference_vars: Option<i32> = Some(0).map(deref_int); found function signature `for<'a> fn(&'a i32) -> _` note: required by a bound in `Option::<T>::map` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _has_inference_vars: Option<i32> = Some(0).map(|a| deref_int(&a)); + | +++ ++++ help: consider adjusting the signature so it does not borrow its argument | LL - fn deref_int(a: &i32) -> i32 { diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr index 3175a258906..1ac057a5f38 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr @@ -13,6 +13,10 @@ LL | let _ = produces_string().and_then(takes_str_but_too_many_refs); found function signature `for<'a, 'b> fn(&'a &'b str) -> _` note: required by a bound in `Option::<T>::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _ = produces_string().and_then(|arg0: String| takes_str_but_too_many_refs(/* &&str */)); + | ++++++++++++++ +++++++++++++ error[E0277]: expected a `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` --> $DIR/suggest-option-asderef-unfixable.rs:26:40 @@ -68,6 +72,10 @@ LL | let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); found function signature `for<'a, 'b> fn(&'a &'b str) -> _` note: required by a bound in `Option::<T>::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _ = Some(TypeWithoutDeref).and_then(|arg0: TypeWithoutDeref| takes_str_but_too_many_refs(/* &&str */)); + | ++++++++++++++++++++++++ +++++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/mismatched_types/suggest-option-asderef.fixed b/tests/ui/mismatched_types/suggest-option-asderef.fixed deleted file mode 100644 index fc488b790b3..00000000000 --- a/tests/ui/mismatched_types/suggest-option-asderef.fixed +++ /dev/null @@ -1,39 +0,0 @@ -// run-rustfix - -fn produces_string() -> Option<String> { - Some("my cool string".to_owned()) -} - -fn takes_str(_: &str) -> Option<()> { - Some(()) -} - -fn takes_str_mut(_: &mut str) -> Option<()> { - Some(()) -} - -fn generic<T>(_: T) -> Option<()> { - Some(()) -} - -fn generic_ref<T>(_: T) -> Option<()> { - //~^ HELP consider adjusting the signature so it does not borrow its argument - Some(()) -} - -fn main() { - let _: Option<()> = produces_string().as_deref().and_then(takes_str); - //~^ ERROR type mismatch in function arguments - //~| HELP call `Option::as_deref()` first - let _: Option<Option<()>> = produces_string().as_deref().map(takes_str); - //~^ ERROR type mismatch in function arguments - //~| HELP call `Option::as_deref()` first - let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut); - //~^ ERROR type mismatch in function arguments - //~| HELP call `Option::as_deref_mut()` first - let _ = produces_string().and_then(generic); - - let _ = produces_string().as_deref().and_then(generic_ref); - //~^ ERROR type mismatch in function arguments - //~| HELP call `Option::as_deref()` first -} diff --git a/tests/ui/mismatched_types/suggest-option-asderef.rs b/tests/ui/mismatched_types/suggest-option-asderef.rs index 28f46808a39..5f5617e1741 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef.rs +++ b/tests/ui/mismatched_types/suggest-option-asderef.rs @@ -1,4 +1,4 @@ -// run-rustfix +// this isn't auto-fixable now because we produce two similar suggestions fn produces_string() -> Option<String> { Some("my cool string".to_owned()) @@ -25,15 +25,19 @@ fn main() { let _: Option<()> = produces_string().and_then(takes_str); //~^ ERROR type mismatch in function arguments //~| HELP call `Option::as_deref()` first + //~| HELP consider wrapping the function in a closure let _: Option<Option<()>> = produces_string().map(takes_str); //~^ ERROR type mismatch in function arguments //~| HELP call `Option::as_deref()` first + //~| HELP consider wrapping the function in a closure let _: Option<Option<()>> = produces_string().map(takes_str_mut); //~^ ERROR type mismatch in function arguments //~| HELP call `Option::as_deref_mut()` first + //~| HELP consider wrapping the function in a closure let _ = produces_string().and_then(generic); let _ = produces_string().and_then(generic_ref); //~^ ERROR type mismatch in function arguments //~| HELP call `Option::as_deref()` first + //~| HELP consider wrapping the function in a closure } diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr index bfea0867350..1702a7f1dec 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef.stderr +++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr @@ -13,13 +13,17 @@ LL | let _: Option<()> = produces_string().and_then(takes_str); found function signature `for<'a> fn(&'a str) -> _` note: required by a bound in `Option::<T>::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _: Option<()> = produces_string().and_then(|arg0: String| takes_str(/* &str */)); + | ++++++++++++++ ++++++++++++ help: call `Option::as_deref()` first | LL | let _: Option<()> = produces_string().as_deref().and_then(takes_str); | +++++++++++ error[E0631]: type mismatch in function arguments - --> $DIR/suggest-option-asderef.rs:28:55 + --> $DIR/suggest-option-asderef.rs:29:55 | LL | fn takes_str(_: &str) -> Option<()> { | ----------------------------------- found signature defined here @@ -33,13 +37,17 @@ LL | let _: Option<Option<()>> = produces_string().map(takes_str); found function signature `for<'a> fn(&'a str) -> _` note: required by a bound in `Option::<T>::map` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _: Option<Option<()>> = produces_string().map(|arg0: String| takes_str(/* &str */)); + | ++++++++++++++ ++++++++++++ help: call `Option::as_deref()` first | LL | let _: Option<Option<()>> = produces_string().as_deref().map(takes_str); | +++++++++++ error[E0631]: type mismatch in function arguments - --> $DIR/suggest-option-asderef.rs:31:55 + --> $DIR/suggest-option-asderef.rs:33:55 | LL | fn takes_str_mut(_: &mut str) -> Option<()> { | ------------------------------------------- found signature defined here @@ -53,13 +61,17 @@ LL | let _: Option<Option<()>> = produces_string().map(takes_str_mut); found function signature `for<'a> fn(&'a mut str) -> _` note: required by a bound in `Option::<T>::map` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _: Option<Option<()>> = produces_string().map(|arg0: String| takes_str_mut(/* &mut str */)); + | ++++++++++++++ ++++++++++++++++ help: call `Option::as_deref_mut()` first | LL | let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut); | +++++++++++++++ error[E0631]: type mismatch in function arguments - --> $DIR/suggest-option-asderef.rs:36:40 + --> $DIR/suggest-option-asderef.rs:39:40 | LL | fn generic_ref<T>(_: &T) -> Option<()> { | -------------------------------------- found signature defined here @@ -73,6 +85,10 @@ LL | let _ = produces_string().and_then(generic_ref); found function signature `for<'a> fn(&'a _) -> _` note: required by a bound in `Option::<T>::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | let _ = produces_string().and_then(|arg0: String| generic_ref(&arg0)); + | ++++++++++++++ +++++++ help: consider adjusting the signature so it does not borrow its argument | LL - fn generic_ref<T>(_: &T) -> Option<()> { diff --git a/tests/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/tests/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index a900a49c710..d92d5dbd16f 100644 --- a/tests/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/tests/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -16,6 +16,10 @@ note: required by a bound in `call_it` | LL | fn call_it<F: FnMut(isize, isize) -> isize>(y: isize, mut f: F) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` +help: consider wrapping the function in a closure + | +LL | let z = call_it(3, |arg0: isize, arg1: isize| f(/* usize */, arg1)); + | ++++++++++++++++++++++++++ +++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs b/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs new file mode 100644 index 00000000000..5fabf31cecd --- /dev/null +++ b/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs @@ -0,0 +1,46 @@ +// This is a non-regression test about differences in scopes computed by NLLs and `-Zpolonius=next` +// found during the crater run for PR #117593. +// +// Live loans were computed too early compared to some of the liveness data coming from later passes +// than `liveness::trace`, on some specific CFGs shapes: a variable was dead during tracing but its +// regions were marked live later, and live loans were not recomputed at this point. + +// check-pass +// revisions: nll polonius +// [polonius] compile-flags: -Zpolonius=next + +// minimized from wavefc-cli-3.0.0 +fn repro1() { + let a = 0; + let closure = || { + let _b = a; + }; + + let callback = if true { Some(closure) } else { None }; + do_it(callback); +} +fn do_it<F>(_: Option<F>) +where + F: Fn(), +{ +} + +// minimized from simple-server-0.4.0 +fn repro2() { + let mut a = &(); + let s = S(&mut a); + let _ = if true { Some(s) } else { None }; +} +struct S<'a>(&'a mut &'a ()); + +// minimized from https://github.com/SHaaD94/AICup2022 +fn repro3() { + let runner = (); + let writer = debug_interface(&runner); + let _ = if true { Some(writer) } else { None }; +} +fn debug_interface(_: &()) -> &mut dyn std::io::Write { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/packed-struct/packed-struct-generic-transmute.rs b/tests/ui/packed/packed-struct-generic-transmute.rs index c6264b6d2b3..c6264b6d2b3 100644 --- a/tests/ui/packed-struct/packed-struct-generic-transmute.rs +++ b/tests/ui/packed/packed-struct-generic-transmute.rs diff --git a/tests/ui/packed-struct/packed-struct-generic-transmute.stderr b/tests/ui/packed/packed-struct-generic-transmute.stderr index e91f4988429..e91f4988429 100644 --- a/tests/ui/packed-struct/packed-struct-generic-transmute.stderr +++ b/tests/ui/packed/packed-struct-generic-transmute.stderr diff --git a/tests/ui/packed-struct/packed-struct-transmute.rs b/tests/ui/packed/packed-struct-transmute.rs index a7d284025d7..a7d284025d7 100644 --- a/tests/ui/packed-struct/packed-struct-transmute.rs +++ b/tests/ui/packed/packed-struct-transmute.rs diff --git a/tests/ui/packed-struct/packed-struct-transmute.stderr b/tests/ui/packed/packed-struct-transmute.stderr index 4d75820e944..4d75820e944 100644 --- a/tests/ui/packed-struct/packed-struct-transmute.stderr +++ b/tests/ui/packed/packed-struct-transmute.stderr diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs new file mode 100644 index 00000000000..e758e5af4d9 --- /dev/null +++ b/tests/ui/parser/issues/issue-118530-ice.rs @@ -0,0 +1,15 @@ +fn bar() -> String { + #[cfg] + [1, 2, 3].iter() //~ ERROR expected `;`, found `#` + #[feature] + attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn` + //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `->` + //~| ERROR expected `;`, found `bar` + #[attr] + [1, 2, 3].iter().map().collect::<String>() + #[attr] + +}() +} + +fn main() { } diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr new file mode 100644 index 00000000000..ef573fb7ba3 --- /dev/null +++ b/tests/ui/parser/issues/issue-118530-ice.stderr @@ -0,0 +1,43 @@ +error: expected `;`, found `#` + --> $DIR/issue-118530-ice.rs:3:21 + | +LL | #[cfg] + | ------ only `;` terminated statements or tail expressions are allowed after this attribute +LL | [1, 2, 3].iter() + | ^ expected `;` here +LL | #[feature] + | - unexpected token + | +help: add `;` here + | +LL | [1, 2, 3].iter(); + | + +help: alternatively, consider surrounding the expression with a block + | +LL | { [1, 2, 3].iter() } + | + + + +error: expected identifier, found keyword `fn` + --> $DIR/issue-118530-ice.rs:5:11 + | +LL | attr::fn bar() -> String { + | ^^ expected identifier, found keyword + +error: expected `;`, found `bar` + --> $DIR/issue-118530-ice.rs:5:13 + | +LL | #[feature] + | ---------- only `;` terminated statements or tail expressions are allowed after this attribute +LL | attr::fn bar() -> String { + | ^--- unexpected token + | | + | help: add `;` here + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `->` + --> $DIR/issue-118530-ice.rs:5:20 + | +LL | attr::fn bar() -> String { + | ^^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/issues/issue-118531-ice.rs b/tests/ui/parser/issues/issue-118531-ice.rs new file mode 100644 index 00000000000..24794f06052 --- /dev/null +++ b/tests/ui/parser/issues/issue-118531-ice.rs @@ -0,0 +1,10 @@ +fn bar() -> String { + #[cfg(feature = )] + [1, 2, 3].iter().map().collect::<String>() //~ ERROR expected `;`, found `#` + + #[attr] //~ ERROR attributes on expressions are experimental [E0658] + //~^ ERROR cannot find attribute `attr` in this scope + String::new() +} + +fn main() { } diff --git a/tests/ui/parser/issues/issue-118531-ice.stderr b/tests/ui/parser/issues/issue-118531-ice.stderr new file mode 100644 index 00000000000..a32292dcb0d --- /dev/null +++ b/tests/ui/parser/issues/issue-118531-ice.stderr @@ -0,0 +1,38 @@ +error: expected `;`, found `#` + --> $DIR/issue-118531-ice.rs:3:47 + | +LL | #[cfg(feature = )] + | ------------------ only `;` terminated statements or tail expressions are allowed after this attribute +LL | [1, 2, 3].iter().map().collect::<String>() + | ^ expected `;` here +LL | +LL | #[attr] + | - unexpected token + | +help: add `;` here + | +LL | [1, 2, 3].iter().map().collect::<String>(); + | + +help: alternatively, consider surrounding the expression with a block + | +LL | { [1, 2, 3].iter().map().collect::<String>() } + | + + + +error[E0658]: attributes on expressions are experimental + --> $DIR/issue-118531-ice.rs:5:5 + | +LL | #[attr] + | ^^^^^^^ + | + = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error: cannot find attribute `attr` in this scope + --> $DIR/issue-118531-ice.rs:5:7 + | +LL | #[attr] + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr index df5968ba323..93a39edbb82 100644 --- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr +++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr @@ -22,12 +22,18 @@ note: consider marking `Full` as `pub` in the imported module LL | pub use self::Lieutenant::{JuniorGrade, Full}; | ^^^^ -error: glob import doesn't reexport anything because no candidate is public enough +error: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough --> $DIR/issue-46209-private-enum-variant-reexport.rs:3:13 | LL | pub use self::Professor::*; | ^^^^^^^^^^^^^^^^^^ | +note: the most public imported item is `pub(self)` + --> $DIR/issue-46209-private-enum-variant-reexport.rs:3:13 + | +LL | pub use self::Professor::*; + | ^^^^^^^^^^^^^^^^^^ + = help: reduce the glob import's visibility or increase visibility of imported items note: the lint level is defined here --> $DIR/issue-46209-private-enum-variant-reexport.rs:1:8 | @@ -46,11 +52,18 @@ error: unused imports: `Full`, `JuniorGrade` LL | pub use self::Lieutenant::{JuniorGrade, Full}; | ^^^^^^^^^^^ ^^^^ -error: glob import doesn't reexport anything because no candidate is public enough +error: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough + --> $DIR/issue-46209-private-enum-variant-reexport.rs:10:13 + | +LL | pub use self::PettyOfficer::*; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the most public imported item is `pub(self)` --> $DIR/issue-46209-private-enum-variant-reexport.rs:10:13 | LL | pub use self::PettyOfficer::*; | ^^^^^^^^^^^^^^^^^^^^^ + = help: reduce the glob import's visibility or increase visibility of imported items error: unused import: `self::PettyOfficer::*` --> $DIR/issue-46209-private-enum-variant-reexport.rs:10:13 @@ -58,11 +71,18 @@ error: unused import: `self::PettyOfficer::*` LL | pub use self::PettyOfficer::*; | ^^^^^^^^^^^^^^^^^^^^^ -error: glob import doesn't reexport anything because no candidate is public enough +error: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough + --> $DIR/issue-46209-private-enum-variant-reexport.rs:13:13 + | +LL | pub use self::Crewman::*; + | ^^^^^^^^^^^^^^^^ + | +note: the most public imported item is `pub(crate)` --> $DIR/issue-46209-private-enum-variant-reexport.rs:13:13 | LL | pub use self::Crewman::*; | ^^^^^^^^^^^^^^^^ + = help: reduce the glob import's visibility or increase visibility of imported items error: unused import: `self::Crewman::*` --> $DIR/issue-46209-private-enum-variant-reexport.rs:13:13 diff --git a/tests/ui/privacy/private-variant-reexport.stderr b/tests/ui/privacy/private-variant-reexport.stderr index 2f041934a81..d73bd1a8cc2 100644 --- a/tests/ui/privacy/private-variant-reexport.stderr +++ b/tests/ui/privacy/private-variant-reexport.stderr @@ -30,12 +30,18 @@ LL | pub use ::E::V::{self}; | = note: consider declaring type or module `V` with `pub` -error: glob import doesn't reexport anything because no candidate is public enough +error: glob import doesn't reexport anything with visibility `pub` because no imported item is public enough --> $DIR/private-variant-reexport.rs:15:13 | LL | pub use ::E::*; | ^^^^^^ | +note: the most public imported item is `pub(crate)` + --> $DIR/private-variant-reexport.rs:15:13 + | +LL | pub use ::E::*; + | ^^^^^^ + = help: reduce the glob import's visibility or increase visibility of imported items note: the lint level is defined here --> $DIR/private-variant-reexport.rs:13:8 | diff --git a/tests/ui/proc-macro/literal-to-string.rs b/tests/ui/proc-macro/literal-to-string.rs index 494d17cbeea..eb009036a9a 100644 --- a/tests/ui/proc-macro/literal-to-string.rs +++ b/tests/ui/proc-macro/literal-to-string.rs @@ -1,6 +1,5 @@ // check-pass // edition: 2021 -#![feature(c_str_literals)] // aux-build: print-tokens.rs extern crate print_tokens; diff --git a/tests/ui/proc-macro/literal-to-string.stdout b/tests/ui/proc-macro/literal-to-string.stdout index 7b27fcf798b..ec6427545f4 100644 --- a/tests/ui/proc-macro/literal-to-string.stdout +++ b/tests/ui/proc-macro/literal-to-string.stdout @@ -3,91 +3,91 @@ TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: #0 bytes(172..173), + span: #0 bytes(144..145), }, Literal { kind: Integer, symbol: "17", suffix: Some("u8"), - span: #0 bytes(182..186), + span: #0 bytes(154..158), }, Literal { kind: Float, symbol: "42.", suffix: None, - span: #0 bytes(195..198), + span: #0 bytes(167..170), }, Literal { kind: Float, symbol: "3.14", suffix: Some("f32"), - span: #0 bytes(207..214), + span: #0 bytes(179..186), }, Literal { kind: Byte, symbol: "a", suffix: None, - span: #0 bytes(223..227), + span: #0 bytes(195..199), }, Literal { kind: Byte, symbol: "\xFF", suffix: None, - span: #0 bytes(236..243), + span: #0 bytes(208..215), }, Literal { kind: Char, symbol: "c", suffix: None, - span: #0 bytes(252..255), + span: #0 bytes(224..227), }, Literal { kind: Char, symbol: "\x32", suffix: None, - span: #0 bytes(264..270), + span: #0 bytes(236..242), }, Literal { kind: Str, symbol: "\\"str\\"", suffix: None, - span: #0 bytes(279..288), + span: #0 bytes(251..260), }, Literal { kind: StrRaw(1), symbol: "\"raw\" str", suffix: None, - span: #0 bytes(297..311), + span: #0 bytes(269..283), }, Literal { kind: StrRaw(3), symbol: "very ##\"raw\"## str", suffix: None, - span: #0 bytes(320..347), + span: #0 bytes(292..319), }, Literal { kind: ByteStr, symbol: "\\"byte\\" str", suffix: None, - span: #0 bytes(356..371), + span: #0 bytes(328..343), }, Literal { kind: ByteStrRaw(1), symbol: "\"raw\" \"byte\" str", suffix: None, - span: #0 bytes(380..402), + span: #0 bytes(352..374), }, Literal { kind: CStr, symbol: "\\"c\\" str", suffix: None, - span: #0 bytes(411..423), + span: #0 bytes(383..395), }, Literal { kind: CStrRaw(1), symbol: "\"raw\" \"c\" str", suffix: None, - span: #0 bytes(432..451), + span: #0 bytes(404..423), }, ] 1 diff --git a/tests/ui/resolve/issue-39559.stderr b/tests/ui/resolve/issue-39559.stderr index e7d26d63be3..0aab54fe59d 100644 --- a/tests/ui/resolve/issue-39559.stderr +++ b/tests/ui/resolve/issue-39559.stderr @@ -5,7 +5,7 @@ LL | entries: [T; D::dim()], | ^^^^^^ cannot perform const operation using `D` | = note: type parameters may not be used in const expressions - = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs index 5037396000b..5609dc51a67 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs @@ -1,8 +1,6 @@ // run-pass // edition: 2021 -#![feature(c_str_literals)] - fn main() { assert_eq!(b"test\0", c"test".to_bytes_with_nul()); } diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs deleted file mode 100644 index ddd6d9a25da..00000000000 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs +++ /dev/null @@ -1,15 +0,0 @@ -// gate-test-c_str_literals -// known-bug: #113333 -// edition: 2021 - -macro_rules! m { - ($t:tt) => {} -} - -fn main() { - c"foo"; - // FIXME(c_str_literals): This should be ``c".."` literals are experimental` - - m!(c"test"); - // FIXME(c_str_literals): This should be ``c".."` literals are experimental` -} diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr deleted file mode 100644 index ea666e43308..00000000000 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: `c".."` literals are experimental - --> $DIR/gate.rs:10:5 - | -LL | c"foo"; - | ^^^^^^ - | - = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information - = help: add `#![feature(c_str_literals)]` to the crate attributes to enable - -error[E0658]: `c".."` literals are experimental - --> $DIR/gate.rs:13:8 - | -LL | m!(c"test"); - | ^^^^^^^ - | - = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information - = help: add `#![feature(c_str_literals)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs index 369173e2318..a7e36b2233e 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr index 82d9f9cb320..ff9006f6f97 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs index 380445d7a7f..8a5f514db7f 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs @@ -1,8 +1,6 @@ // run-pass // edition: 2021 -#![feature(c_str_literals)] - fn main() { assert_eq!( c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(), diff --git a/tests/ui/simd/libm_no_std_cant_float.rs b/tests/ui/simd/libm_no_std_cant_float.rs index 50ac8e20839..f54a1faf4f9 100644 --- a/tests/ui/simd/libm_no_std_cant_float.rs +++ b/tests/ui/simd/libm_no_std_cant_float.rs @@ -2,7 +2,7 @@ #![no_std] #![feature(portable_simd)] use core::simd::f32x4; -use core::simd::SimdFloat; +use core::simd::num::SimdFloat; // For SIMD float ops, the LLIR version which is used to implement the portable // forms of them may become calls to math.h AKA libm. So, we can't guarantee diff --git a/tests/ui/simd/libm_std_can_float.rs b/tests/ui/simd/libm_std_can_float.rs index 1c520856e98..78bd0c14022 100644 --- a/tests/ui/simd/libm_std_can_float.rs +++ b/tests/ui/simd/libm_std_can_float.rs @@ -3,7 +3,7 @@ // This is the converse of the other libm test. #![feature(portable_simd)] use std::simd::f32x4; -use std::simd::{SimdFloat, StdFloat}; +use std::simd::{num::SimdFloat, StdFloat}; // For SIMD float ops, the LLIR version which is used to implement the portable // forms of them may become calls to math.h AKA libm. So, we can't guarantee diff --git a/tests/ui/suggestions/enum-variant-arg-mismatch.stderr b/tests/ui/suggestions/enum-variant-arg-mismatch.stderr index 6d72dabf70e..16f03d16d8c 100644 --- a/tests/ui/suggestions/enum-variant-arg-mismatch.stderr +++ b/tests/ui/suggestions/enum-variant-arg-mismatch.stderr @@ -16,6 +16,10 @@ note: required by a bound in `map` | LL | fn map<'a, F: Fn(String) -> Sexpr<'a>>(f: F) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map` +help: consider wrapping the function in a closure + | +LL | map(|arg0: String| Sexpr::Ident(/* &str */)); + | ++++++++++++++ ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index 235dfcd3a2a..b9b72e0e63f 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -5,7 +5,7 @@ LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | = help: the following other types implement trait `From<T>`: - <[bool; LANES] as From<Mask<T, LANES>>> + <[bool; N] as From<Mask<T, N>>> <[T; N] as From<Simd<T, N>>> <[T; 1] as From<(T,)>> <[T; 2] as From<(T, T)>> diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr index d78de6a460c..ee924522564 100644 --- a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr +++ b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr @@ -16,6 +16,10 @@ note: required by a bound in `Trader::<'a>::set_closure` | LL | pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) { | ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure` +help: consider wrapping the function in a closure + | +LL | trader.set_closure(|arg0: &mut Trader<'_>| closure(*arg0)); + | +++++++++++++++++++++++ +++++++ help: consider adjusting the signature so it borrows its argument | LL | let closure = |trader : &mut Trader| { diff --git a/tests/ui/suggestions/non_ascii_ident.rs b/tests/ui/suggestions/non_ascii_ident.rs index 679ac4bcb6e..9c897147518 100644 --- a/tests/ui/suggestions/non_ascii_ident.rs +++ b/tests/ui/suggestions/non_ascii_ident.rs @@ -1,4 +1,7 @@ fn main() { // There shall be no suggestions here. In particular not `Ok`. let _ = 读文; //~ ERROR cannot find value `读文` in this scope + + let f = 0f32; // Important line to make this an ICE regression test + 读文(f); //~ ERROR cannot find function `读文` in this scope } diff --git a/tests/ui/suggestions/non_ascii_ident.stderr b/tests/ui/suggestions/non_ascii_ident.stderr index 79fca3e1f61..fdcc64aef36 100644 --- a/tests/ui/suggestions/non_ascii_ident.stderr +++ b/tests/ui/suggestions/non_ascii_ident.stderr @@ -4,6 +4,12 @@ error[E0425]: cannot find value `读文` in this scope LL | let _ = 读文; | ^^^^ not found in this scope -error: aborting due to 1 previous error +error[E0425]: cannot find function `读文` in this scope + --> $DIR/non_ascii_ident.rs:6:5 + | +LL | 读文(f); + | ^^^^ not found in this scope + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/traits/subtype-recursion-limit.rs b/tests/ui/traits/subtype-recursion-limit.rs new file mode 100644 index 00000000000..5804748844e --- /dev/null +++ b/tests/ui/traits/subtype-recursion-limit.rs @@ -0,0 +1,17 @@ +// Variant of #117151 when the overflow comes entirely from subtype predicates. + +#![allow(unreachable_code)] + +use std::ptr; + +fn main() { + // Give x and y completely unconstrained types. Using a function call + // or `as` cast would create a well-formed predicate. + let x = return; + let y = return; + let mut w = (x, y); + //~^ ERROR overflow evaluating the requirement + // Avoid creating lifetimes, `Sized` bounds or function calls. + let a = (ptr::addr_of!(y), ptr::addr_of!(x)); + w = a; +} diff --git a/tests/ui/traits/subtype-recursion-limit.stderr b/tests/ui/traits/subtype-recursion-limit.stderr new file mode 100644 index 00000000000..5310f822cc3 --- /dev/null +++ b/tests/ui/traits/subtype-recursion-limit.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `_ <: *const _` + --> $DIR/subtype-recursion-limit.rs:12:17 + | +LL | let mut w = (x, y); + | ^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/well-formed-recursion-limit.rs b/tests/ui/traits/well-formed-recursion-limit.rs new file mode 100644 index 00000000000..056cf947d4b --- /dev/null +++ b/tests/ui/traits/well-formed-recursion-limit.rs @@ -0,0 +1,27 @@ +// Regression test for #117151, this used to hang the compiler + +pub type ISO<A: 'static, B: 'static> = (Box<dyn Fn(A) -> B>, Box<dyn Fn(B) -> A>); +pub fn iso<A: 'static, B: 'static, F1, F2>(a: F1, b: F2) -> ISO<A, B> +where + F1: 'static + Fn(A) -> B, + F2: 'static + Fn(B) -> A, +{ + (Box::new(a), Box::new(b)) +} +pub fn iso_un_option<A: 'static, B: 'static>(i: ISO<Option<A>, Option<B>>) -> ISO<A, B> { + let (ab, ba) = (i.ab, i.ba); + //~^ ERROR no field `ab` on type + //~| ERROR no field `ba` on type + let left = move |o_a| match o_a { + //~^ ERROR overflow evaluating the requirement + None => panic!("absured"), + Some(a) => a, + }; + let right = move |o_b| match o_b { + None => panic!("absurd"), + Some(b) => b, + }; + iso(left, right) +} + +fn main() {} diff --git a/tests/ui/traits/well-formed-recursion-limit.stderr b/tests/ui/traits/well-formed-recursion-limit.stderr new file mode 100644 index 00000000000..6f5fda02315 --- /dev/null +++ b/tests/ui/traits/well-formed-recursion-limit.stderr @@ -0,0 +1,22 @@ +error[E0609]: no field `ab` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'static)>, Box<(dyn Fn(Option<B>) -> Option<A> + 'static)>)` + --> $DIR/well-formed-recursion-limit.rs:12:23 + | +LL | let (ab, ba) = (i.ab, i.ba); + | ^^ unknown field + +error[E0609]: no field `ba` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'static)>, Box<(dyn Fn(Option<B>) -> Option<A> + 'static)>)` + --> $DIR/well-formed-recursion-limit.rs:12:29 + | +LL | let (ab, ba) = (i.ab, i.ba); + | ^^ unknown field + +error[E0275]: overflow evaluating the requirement `_ <: Option<_>` + --> $DIR/well-formed-recursion-limit.rs:15:33 + | +LL | let left = move |o_a| match o_a { + | ^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0275, E0609. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/treat-err-as-bug/delay_span_bug.rs b/tests/ui/treat-err-as-bug/span_delayed_bug.rs index f667f8eb996..dda35b9b92a 100644 --- a/tests/ui/treat-err-as-bug/delay_span_bug.rs +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.rs @@ -1,12 +1,12 @@ // compile-flags: -Ztreat-err-as-bug // failure-status: 101 // error-pattern: aborting due to `-Z treat-err-as-bug=1` -// error-pattern: [trigger_delay_span_bug] triggering a delay span bug for testing incremental +// error-pattern: [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental // normalize-stderr-test "note: .*\n\n" -> "" // normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> "" // rustc-env:RUST_BACKTRACE=0 #![feature(rustc_attrs)] -#[rustc_error(delay_span_bug_from_inside_query)] +#[rustc_error(span_delayed_bug_from_inside_query)] fn main() {} diff --git a/tests/ui/treat-err-as-bug/delay_span_bug.stderr b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr index 06a31ae86b2..a61ffaea8c2 100644 --- a/tests/ui/treat-err-as-bug/delay_span_bug.stderr +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr @@ -1,5 +1,5 @@ -error: internal compiler error: delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)] - --> $DIR/delay_span_bug.rs:12:1 +error: internal compiler error: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)] + --> $DIR/span_delayed_bug.rs:12:1 | LL | fn main() {} | ^^^^^^^^^ @@ -7,5 +7,5 @@ LL | fn main() {} error: the compiler unexpectedly panicked. this is a bug. query stack during panic: -#0 [trigger_delay_span_bug] triggering a delay span bug for testing incremental +#0 [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental end of query stack diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr index 844103d77a8..d4e2f953533 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: no errors encountered even though `delay_span_bug` issued +error: internal compiler error: no errors encountered even though `span_delayed_bug` issued error: internal compiler error: {OpaqueTypeKey { def_id: DefId(get_rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }) } }} | diff --git a/tests/ui/type-inference/generalize-subtyped-variables.rs b/tests/ui/type-inference/generalize-subtyped-variables.rs new file mode 100644 index 00000000000..f93408a43db --- /dev/null +++ b/tests/ui/type-inference/generalize-subtyped-variables.rs @@ -0,0 +1,25 @@ +// Test for specific details of how we handle higher-ranked subtyping to make +// sure that any changes are made deliberately. +// +// - `let y = x` creates a `Subtype` obligation that is deferred for later. +// - `w = a` sets the type of `x` to `Option<for<'a> fn(&'a ())>` and generalizes +// `z` first to `Option<_>` and then to `Option<fn(&'0 ())>`. +// - The various subtyping obligations are then processed. +// +// This requires that +// 1. the `Subtype` obligation from `y = x` isn't processed while the types of +// `w` and `a` are being unified. +// 2. the pending subtype obligation isn't considered when determining the type +// to generalize `z` to first (when related to the type of `y`). +// +// Found when considering fixes to #117151 +// check-pass + +fn main() { + let mut x = None; + let y = x; + let z = Default::default(); + let mut w = (&mut x, z, z); + let a = (&mut None::<fn(&())>, y, None::<fn(&'static ())>); + w = a; +} diff --git a/tests/ui/typeck/mismatched-map-under-self.stderr b/tests/ui/typeck/mismatched-map-under-self.stderr index 51491407c49..41391720a28 100644 --- a/tests/ui/typeck/mismatched-map-under-self.stderr +++ b/tests/ui/typeck/mismatched-map-under-self.stderr @@ -30,6 +30,10 @@ LL | self.map(Insertable::values).unwrap_or_default() found function signature `for<'a> fn(&'a _) -> _` note: required by a bound in `Option::<T>::map` --> $SRC_DIR/core/src/option.rs:LL:COL +help: consider wrapping the function in a closure + | +LL | self.map(|arg0: T| Insertable::values(&arg0)).unwrap_or_default() + | +++++++++ +++++++ error: aborting due to 2 previous errors diff --git a/triagebot.toml b/triagebot.toml index ed9d59b1bb9..24926690cfe 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -627,7 +627,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", "oli-obk"] +users_on_vacation = ["jyn514", "oli-obk", "wesleywiser"] [assign.adhoc_groups] compiler-team = [ |
