diff options
388 files changed, 5365 insertions, 2286 deletions
diff --git a/Cargo.lock b/Cargo.lock index 79b7d92425a..a912eee97db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,9 +175,7 @@ dependencies = [ "filetime", "getopts", "ignore", - "lazy_static", "libc", - "merge", "num_cpus", "once_cell", "opener", @@ -619,7 +617,7 @@ dependencies = [ "clippy_utils", "if_chain", "itertools 0.10.1", - "pulldown-cmark", + "pulldown-cmark 0.9.0", "quine-mc_cluskey", "regex-syntax", "rustc-semver", @@ -1954,9 +1952,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.19" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056" +checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" dependencies = [ "cc", "libc", @@ -2154,7 +2152,7 @@ dependencies = [ "log", "memchr", "opener", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "regex", "serde", "serde_derive", @@ -2222,28 +2220,6 @@ dependencies = [ ] [[package]] -name = "merge" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" -dependencies = [ - "merge_derive", - "num-traits", -] - -[[package]] -name = "merge_derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "minifier" version = "0.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2814,6 +2790,17 @@ dependencies = [ ] [[package]] +name = "pulldown-cmark" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd16514d1af5f7a71f909a44ef253cdb712a376d7ebc8ae4a471a9be9743548" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] name = "punycode" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3965,6 +3952,7 @@ dependencies = [ "arrayvec", "rustc_macros", "rustc_serialize", + "smallvec", ] [[package]] @@ -4615,7 +4603,7 @@ dependencies = [ "expect-test", "itertools 0.9.0", "minifier", - "pulldown-cmark", + "pulldown-cmark 0.9.0", "rayon", "regex", "rustdoc-json-types", diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 927d7c6aaf6..d66774040f7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -136,15 +136,15 @@ impl Attribute { pub fn value_str(&self) -> Option<Symbol> { match self.kind { - AttrKind::Normal(ref item, _) => item.meta(self.span).and_then(|meta| meta.value_str()), + AttrKind::Normal(ref item, _) => item.meta_kind().and_then(|kind| kind.value_str()), AttrKind::DocComment(..) => None, } } pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> { match self.kind { - AttrKind::Normal(ref item, _) => match item.meta(self.span) { - Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), + AttrKind::Normal(ref item, _) => match item.meta_kind() { + Some(MetaItemKind::List(list)) => Some(list), _ => None, }, AttrKind::DocComment(..) => None, @@ -228,6 +228,10 @@ impl AttrItem { span, }) } + + pub fn meta_kind(&self) -> Option<MetaItemKind> { + Some(MetaItemKind::from_mac_args(&self.args)?) + } } impl Attribute { @@ -242,7 +246,7 @@ impl Attribute { match self.kind { AttrKind::DocComment(.., data) => Some(data), AttrKind::Normal(ref item, _) if item.path == sym::doc => { - item.meta(self.span).and_then(|meta| meta.value_str()) + item.meta_kind().and_then(|kind| kind.value_str()) } _ => None, } @@ -270,6 +274,13 @@ impl Attribute { } } + pub fn meta_kind(&self) -> Option<MetaItemKind> { + match self.kind { + AttrKind::Normal(ref item, _) => item.meta_kind(), + AttrKind::DocComment(..) => None, + } + } + pub fn tokens(&self) -> AttrAnnotatedTokenStream { match self.kind { AttrKind::Normal(_, ref tokens) => tokens @@ -436,6 +447,16 @@ impl MetaItem { } impl MetaItemKind { + pub fn value_str(&self) -> Option<Symbol> { + match self { + MetaItemKind::NameValue(ref v) => match v.kind { + LitKind::Str(ref s, _) => Some(*s), + _ => None, + }, + _ => None, + } + } + pub fn mac_args(&self, span: Span) -> MacArgs { match self { MetaItemKind::Word => MacArgs::Empty, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 6bf23af81bf..0fd515750ab 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -14,13 +14,14 @@ use crate::tokenstream::*; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::thin_vec::ThinVec; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; use smallvec::{smallvec, Array, SmallVec}; use std::ops::DerefMut; -use std::{panic, process, ptr}; +use std::{panic, ptr}; pub trait ExpectOne<A: Array> { fn expect_one(self, err: &'static str) -> A::Item; @@ -283,23 +284,21 @@ pub trait MutVisitor: Sized { /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` -/// method. Abort the program if the closure panics. -/// -/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler. -/// Instead of aborting on catching a panic we need to reset the visited node to some valid but -/// possibly meaningless value and rethrow the panic. +/// method. // // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_clobber<T, F>(t: &mut T, f: F) -where - F: FnOnce(T) -> T, -{ +pub fn visit_clobber<T: DummyAstNode>(t: &mut T, f: impl FnOnce(T) -> T) { unsafe { // Safe because `t` is used in a read-only fashion by `read()` before // being overwritten by `write()`. let old_t = ptr::read(t); - let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))) - .unwrap_or_else(|_| process::abort()); + let new_t = + panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))).unwrap_or_else(|err| { + // Set `t` to some valid but possible meaningless value, + // and pass the fatal error further. + ptr::write(t, T::dummy()); + panic::resume_unwind(err); + }); ptr::write(t, new_t); } } @@ -1454,3 +1453,108 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { } vis.visit_span(&mut visibility.span); } + +/// Some value for the AST node that is valid but possibly meaningless. +pub trait DummyAstNode { + fn dummy() -> Self; +} + +impl<T> DummyAstNode for Option<T> { + fn dummy() -> Self { + Default::default() + } +} + +impl<T: DummyAstNode + 'static> DummyAstNode for P<T> { + fn dummy() -> Self { + P(DummyAstNode::dummy()) + } +} + +impl<T> DummyAstNode for ThinVec<T> { + fn dummy() -> Self { + Default::default() + } +} + +impl DummyAstNode for Item { + fn dummy() -> Self { + Item { + attrs: Default::default(), + id: DUMMY_NODE_ID, + span: Default::default(), + vis: Visibility { + kind: VisibilityKind::Public, + span: Default::default(), + tokens: Default::default(), + }, + ident: Ident::empty(), + kind: ItemKind::ExternCrate(None), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Expr { + fn dummy() -> Self { + Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::Err, + span: Default::default(), + attrs: Default::default(), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Ty { + fn dummy() -> Self { + Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Err, + span: Default::default(), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Pat { + fn dummy() -> Self { + Pat { + id: DUMMY_NODE_ID, + kind: PatKind::Wild, + span: Default::default(), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Stmt { + fn dummy() -> Self { + Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Empty, span: Default::default() } + } +} + +impl DummyAstNode for Block { + fn dummy() -> Self { + Block { + stmts: Default::default(), + id: DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span: Default::default(), + tokens: Default::default(), + could_be_bare_literal: Default::default(), + } + } +} + +impl DummyAstNode for Crate { + fn dummy() -> Self { + Crate { + attrs: Default::default(), + items: Default::default(), + span: Default::default(), + is_placeholder: Default::default(), + } + } +} diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 0a9b264aa42..ebae7798433 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -24,7 +24,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub); } - PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)), + PatKind::Lit(ref e) => { + break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); + } PatKind::TupleStruct(ref qself, ref path, ref pats) => { let qpath = self.lower_qpath( pattern.id, @@ -81,8 +83,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => { break hir::PatKind::Range( - e1.as_deref().map(|e| self.lower_expr(e)), - e2.as_deref().map(|e| self.lower_expr(e)), + e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)), + e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)), self.lower_range_end(end, e2.is_some()), ); } @@ -314,4 +316,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included, } } + + /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`, + /// or paths for ranges. + // + // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions? + // That means making this work: + // + // ```rust,ignore (FIXME) + // struct S; + // macro_rules! m { + // ($a:expr) => { + // let $a = S; + // } + // } + // m!(S); + // ``` + fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> { + match expr.kind { + ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {} + ExprKind::Path(..) if allow_paths => {} + ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} + _ => { + self.diagnostic() + .span_err(expr.span, "arbitrary expressions aren't allowed in patterns"); + return self.arena.alloc(self.expr_err(expr.span)); + } + } + self.lower_expr(expr) + } } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 3c3ea2bfd35..6237a01f694 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -302,34 +302,6 @@ impl<'a> AstValidator<'a> { } } - /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`, - /// or paths for ranges. - // - // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions? - // That means making this work: - // - // ```rust,ignore (FIXME) - // struct S; - // macro_rules! m { - // ($a:expr) => { - // let $a = S; - // } - // } - // m!(S); - // ``` - fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { - match expr.kind { - ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {} - ExprKind::Path(..) if allow_paths => {} - ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} - _ => self.err_handler().span_err( - expr.span, - "arbitrary expressions aren't allowed \ - in patterns", - ), - } - } - fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { // Check only lifetime parameters are present and that the lifetime // parameters that are present have no bounds. @@ -1426,25 +1398,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_param_bound(self, bound) } - fn visit_pat(&mut self, pat: &'a Pat) { - match &pat.kind { - PatKind::Lit(expr) => { - self.check_expr_within_pat(expr, false); - } - PatKind::Range(start, end, _) => { - if let Some(expr) = start { - self.check_expr_within_pat(expr, true); - } - if let Some(expr) = end { - self.check_expr_within_pat(expr, true); - } - } - _ => {} - } - - visit::walk_pat(self, pat) - } - fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { self.check_late_bound_lifetime_defs(&t.bound_generic_params); visit::walk_poly_trait_ref(self, t, m); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f0676caed46..91fa4595241 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1116,7 +1116,9 @@ impl<'a> State<'a> { self.print_ident(ident); self.word_space(":"); self.print_type(ty); - self.space(); + if body.is_some() { + self.space(); + } self.end(); // end the head-ibox if let Some(body) = body { self.word_space("="); @@ -2239,7 +2241,6 @@ impl<'a> State<'a> { } ast::ExprKind::TryBlock(ref blk) => { self.head("try"); - self.space(); self.print_block_with_attrs(blk, attrs) } ast::ExprKind::Err => { @@ -2521,7 +2522,6 @@ impl<'a> State<'a> { PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => { if let Some(e) = begin { self.print_expr(e); - self.space(); } match *end_kind { RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 11cdbe84acc..df23eaf24bc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::{ error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, }; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; @@ -334,13 +334,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match variance_info { ty::VarianceDiagInfo::None => {} - ty::VarianceDiagInfo::Mut { kind, ty } => { - let kind_name = match kind { - ty::VarianceDiagMutKind::Ref => "reference", - ty::VarianceDiagMutKind::RawPtr => "pointer", + ty::VarianceDiagInfo::Invariant { ty, param_index } => { + let (desc, note) = match ty.kind() { + ty::RawPtr(ty_mut) => { + assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut); + ( + format!("a mutable pointer to {}", ty_mut.ty), + "mutable pointers are invariant over their type parameter".to_string(), + ) + } + ty::Ref(_, inner_ty, mutbl) => { + assert_eq!(*mutbl, rustc_hir::Mutability::Mut); + ( + format!("a mutable reference to {}", inner_ty), + "mutable references are invariant over their type parameter" + .to_string(), + ) + } + ty::Adt(adt, substs) => { + let generic_arg = substs[param_index as usize]; + let identity_substs = + InternalSubsts::identity_for_item(self.infcx.tcx, adt.did); + let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs); + let base_generic_arg = identity_substs[param_index as usize]; + let adt_desc = adt.descr(); + + let desc = format!( + "the type {ty}, which makes the generic argument {generic_arg} invariant" + ); + let note = format!( + "the {adt_desc} {base_ty} is invariant over the parameter {base_generic_arg}" + ); + (desc, note) + } + _ => panic!("Unexpected type {:?}", ty), }; - diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",)); - diag.note(&format!("mutable {kind_name}s are invariant over their type parameter")); + diag.note(&format!("requirement occurs because of {desc}",)); + diag.note(¬e); diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance"); } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 63ffcb3ec45..fe34d6e7ca9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1394,10 +1394,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::NullaryOp(_op, _ty) => { // nullary ops take no dynamic input; no borrowck effect. - // - // FIXME: is above actually true? Do we want to track - // the fact that uninitialized data can be created via - // `NullOp::Box`? } Rvalue::Aggregate(ref aggregate_kind, ref operands) => { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 100ac578f92..4a70535c63b 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,5 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; -use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; +use rustc_index::bit_set::SparseBitMatrix; +use rustc_index::interval::IntervalSet; +use rustc_index::interval::SparseIntervalMatrix; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_middle::mir::{BasicBlock, Body, Location}; @@ -110,11 +112,11 @@ crate enum RegionElement { PlaceholderRegion(ty::PlaceholderRegion), } -/// When we initially compute liveness, we use a bit matrix storing -/// points for each region-vid. +/// When we initially compute liveness, we use an interval matrix storing +/// liveness ranges for each region-vid. crate struct LivenessValues<N: Idx> { elements: Rc<RegionValueElements>, - points: SparseBitMatrix<N, PointIndex>, + points: SparseIntervalMatrix<N, PointIndex>, } impl<N: Idx> LivenessValues<N> { @@ -122,7 +124,7 @@ impl<N: Idx> LivenessValues<N> { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. crate fn new(elements: Rc<RegionValueElements>) -> Self { - Self { points: SparseBitMatrix::new(elements.num_points), elements } + Self { points: SparseIntervalMatrix::new(elements.num_points), elements } } /// Iterate through each region that has a value in this set. @@ -140,7 +142,7 @@ impl<N: Idx> LivenessValues<N> { /// Adds all the elements in the given bit array into the given /// region. Returns whether any of them are newly added. - crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool { + crate fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool { debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); self.points.union_row(row, locations) } @@ -153,7 +155,7 @@ impl<N: Idx> LivenessValues<N> { /// Returns `true` if the region `r` contains the given element. crate fn contains(&self, row: N, location: Location) -> bool { let index = self.elements.point_from_location(location); - self.points.contains(row, index) + self.points.row(row).map_or(false, |r| r.contains(index)) } /// Returns an iterator of all the elements contained by the region `r` @@ -221,7 +223,7 @@ impl PlaceholderIndices { crate struct RegionValues<N: Idx> { elements: Rc<RegionValueElements>, placeholder_indices: Rc<PlaceholderIndices>, - points: SparseBitMatrix<N, PointIndex>, + points: SparseIntervalMatrix<N, PointIndex>, free_regions: SparseBitMatrix<N, RegionVid>, /// Placeholders represent bound regions -- so something like `'a` @@ -241,7 +243,7 @@ impl<N: Idx> RegionValues<N> { let num_placeholders = placeholder_indices.len(); Self { elements: elements.clone(), - points: SparseBitMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points), placeholder_indices: placeholder_indices.clone(), free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 0969b9a508f..094af20f52e 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::HybridBitSet; +use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::ty::{Ty, TypeFoldable}; @@ -105,12 +106,12 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { /// Points where the current variable is "use live" -- meaning /// that there is a future "full use" that may use its value. - use_live_at: HybridBitSet<PointIndex>, + use_live_at: IntervalSet<PointIndex>, /// Points where the current variable is "drop live" -- meaning /// that there is no future "full use" that may use its value, but /// there is a future drop. - drop_live_at: HybridBitSet<PointIndex>, + drop_live_at: IntervalSet<PointIndex>, /// Locations where drops may occur. drop_locations: Vec<Location>, @@ -125,8 +126,8 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { LivenessResults { cx, defs: HybridBitSet::new_empty(num_points), - use_live_at: HybridBitSet::new_empty(num_points), - drop_live_at: HybridBitSet::new_empty(num_points), + use_live_at: IntervalSet::new(num_points), + drop_live_at: IntervalSet::new(num_points), drop_locations: vec![], stack: vec![], } @@ -165,7 +166,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { drop_used: Vec<(Local, Location)>, live_locals: FxHashSet<Local>, ) { - let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + let locations = IntervalSet::new(self.cx.elements.num_points()); for (local, location) in drop_used { if !live_locals.contains(&local) { @@ -456,7 +457,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { fn add_use_live_facts_for( &mut self, value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!("add_use_live_facts_for(value={:?})", value); @@ -473,7 +474,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { dropped_local: Local, dropped_ty: Ty<'tcx>, drop_locations: &[Location], - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!( "add_drop_live_constraint(\ @@ -521,7 +522,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { elements: &RegionValueElements, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!("make_all_regions_live(value={:?})", value); debug!( diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index a107f5993b5..eb08170959b 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -72,6 +72,52 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne } } +fn handle_array_element( + cx: &mut base::ExtCtxt<'_>, + has_errors: &mut bool, + missing_literals: &mut Vec<rustc_span::Span>, + expr: &P<rustc_ast::Expr>, +) -> Option<u8> { + match expr.kind { + ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { + if !*has_errors { + cx.span_err(expr.span, "cannot concatenate doubly nested array"); + } + *has_errors = true; + None + } + ast::ExprKind::Lit(ref lit) => match lit.kind { + ast::LitKind::Int( + val, + ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + ) if val <= u8::MAX.into() => Some(val as u8), + + ast::LitKind::Byte(val) => Some(val), + ast::LitKind::ByteStr(_) => { + if !*has_errors { + cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") + .note("byte strings are treated as arrays of bytes") + .help("try flattening the array") + .emit(); + } + *has_errors = true; + None + } + _ => { + if !*has_errors { + invalid_type_err(cx, expr, true); + } + *has_errors = true; + None + } + }, + _ => { + missing_literals.push(expr.span); + None + } + } +} + pub fn expand_concat_bytes( cx: &mut base::ExtCtxt<'_>, sp: rustc_span::Span, @@ -88,48 +134,27 @@ pub fn expand_concat_bytes( match e.kind { ast::ExprKind::Array(ref exprs) => { for expr in exprs { - match expr.kind { - ast::ExprKind::Array(_) => { - if !has_errors { - cx.span_err(expr.span, "cannot concatenate doubly nested array"); - } - has_errors = true; - } - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed - | ast::LitIntType::Unsigned(ast::UintTy::U8), - ) if val <= u8::MAX.into() => { - accumulator.push(val as u8); - } - - ast::LitKind::Byte(val) => { - accumulator.push(val); - } - ast::LitKind::ByteStr(_) => { - if !has_errors { - cx.struct_span_err( - expr.span, - "cannot concatenate doubly nested array", - ) - .note("byte strings are treated as arrays of bytes") - .help("try flattening the array") - .emit(); - } - has_errors = true; - } - _ => { - if !has_errors { - invalid_type_err(cx, expr, true); - } - has_errors = true; - } - }, - _ => { - missing_literals.push(expr.span); + if let Some(elem) = + handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + { + accumulator.push(elem); + } + } + } + ast::ExprKind::Repeat(ref expr, ref count) => { + if let ast::ExprKind::Lit(ast::Lit { + kind: ast::LitKind::Int(count_val, _), .. + }) = count.value.kind + { + if let Some(elem) = + handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + { + for _ in 0..count_val { + accumulator.push(elem); } } + } else { + cx.span_err(count.value.span, "repeat count is not a positive number"); } } ast::ExprKind::Lit(ref lit) => match lit.kind { diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index bfddd7073ff..ecd16736e7c 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -7,28 +7,29 @@ pub(crate) mod printf { pub enum Substitution<'a> { /// A formatted output substitution with its internal byte offset. Format(Format<'a>), - /// A literal `%%` escape. - Escape, + /// A literal `%%` escape, with its start and end indices. + Escape((usize, usize)), } impl<'a> Substitution<'a> { pub fn as_str(&self) -> &str { match *self { Substitution::Format(ref fmt) => fmt.span, - Substitution::Escape => "%%", + Substitution::Escape(_) => "%%", } } pub fn position(&self) -> Option<InnerSpan> { match *self { Substitution::Format(ref fmt) => Some(fmt.position), - _ => None, + Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)), } } pub fn set_position(&mut self, start: usize, end: usize) { - if let Substitution::Format(ref mut fmt) = self { - fmt.position = InnerSpan::new(start, end); + match self { + Substitution::Format(ref mut fmt) => fmt.position = InnerSpan::new(start, end), + Substitution::Escape(ref mut pos) => *pos = (start, end), } } @@ -39,7 +40,7 @@ pub(crate) mod printf { pub fn translate(&self) -> Result<String, Option<String>> { match *self { Substitution::Format(ref fmt) => fmt.translate(), - Substitution::Escape => Err(None), + Substitution::Escape(_) => Err(None), } } } @@ -304,14 +305,9 @@ pub(crate) mod printf { fn next(&mut self) -> Option<Self::Item> { let (mut sub, tail) = parse_next_substitution(self.s)?; self.s = tail; - match sub { - Substitution::Format(_) => { - if let Some(inner_span) = sub.position() { - sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos); - self.pos += inner_span.end; - } - } - Substitution::Escape => self.pos += 2, + if let Some(InnerSpan { start, end }) = sub.position() { + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; } Some(sub) } @@ -340,7 +336,7 @@ pub(crate) mod printf { let at = { let start = s.find('%')?; if let '%' = s[start + 1..].chars().next()? { - return Some((Substitution::Escape, &s[start + 2..])); + return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])); } Cur::new_at(s, start) diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs index 1336aab7316..fc7442470ac 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -13,9 +13,9 @@ macro_rules! assert_eq_pnsat { fn test_escape() { assert_eq!(pns("has no escapes"), None); assert_eq!(pns("has no escapes, either %"), None); - assert_eq!(pns("*so* has a %% escape"), Some((S::Escape, " escape"))); - assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape"))); - assert_eq!(pns("trailing escape %%"), Some((S::Escape, ""))); + assert_eq!(pns("*so* has a %% escape"), Some((S::Escape((11, 13)), " escape"))); + assert_eq!(pns("%% leading escape"), Some((S::Escape((0, 2)), " leading escape"))); + assert_eq!(pns("trailing escape %%"), Some((S::Escape((16, 18)), ""))); } #[test] diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 7b73d3c00e6..3aba528abfd 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -5,6 +5,21 @@ on: - pull_request jobs: + rustfmt: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v2 + + - name: Install rustfmt + run: | + rustup component add rustfmt + + - name: Rustfmt + run: | + cargo fmt --check + build: runs-on: ${{ matrix.os }} timeout-minutes: 60 diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml index c5b96a47828..a019793edd8 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml @@ -3,7 +3,7 @@ name: Test nightly Cranelift on: push: schedule: - - cron: '1 17 * * *' # At 01:17 UTC every day. + - cron: '17 1 * * *' # At 01:17 UTC every day. jobs: build: diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index b6567aca786..5aeaf3a1788 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -7,6 +7,7 @@ perf.data.old *.events *.string* /y.bin +/y.bin.dSYM /build /build_sysroot/sysroot_src /build_sysroot/compiler-builtins diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 900411286b5..3be4250296e 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -40,31 +40,12 @@ unstable-features = ["jit", "inline_asm"] jit = ["cranelift-jit", "libloading"] inline_asm = [] -[profile.dev] -# By compiling dependencies with optimizations, performing tests gets much faster. -opt-level = 3 - -[profile.dev.package.rustc_codegen_cranelift] -# Disabling optimizations for cg_clif itself makes compilation after a change faster. -opt-level = 0 - -[profile.release.package.rustc_codegen_cranelift] -incremental = true - # Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the # execution time of build scripts is so fast that optimizing them slows down the total build time. -[profile.dev.build-override] -opt-level = 0 -debug = false - [profile.release.build-override] opt-level = 0 debug = false -[profile.dev.package.cranelift-codegen-meta] -opt-level = 0 -debug = false - [profile.release.package.cranelift-codegen-meta] opt-level = 0 debug = false diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index dad8ed90b53..8a2db5a43ec 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -37,7 +37,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/build/cargo build +$ $cg_clif_dir/build/cargo-clif build ``` This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index ccc50ee4a59..1382c7e5379 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -10,6 +10,18 @@ pub(crate) fn build_backend( let mut cmd = Command::new("cargo"); cmd.arg("build").arg("--target").arg(host_triple); + cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode + + let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + + if env::var("CI").as_ref().map(|val| &**val) == Ok("true") { + // Deny warnings on CI + rustflags += " -Dwarnings"; + + // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway + cmd.env("CARGO_BUILD_INCREMENTAL", "false"); + } + if use_unstable_features { cmd.arg("--features").arg("unstable-features"); } @@ -22,25 +34,20 @@ pub(crate) fn build_backend( _ => unreachable!(), } + // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing + // LD_LIBRARY_PATH if cfg!(unix) { if cfg!(target_os = "macos") { - cmd.env( - "RUSTFLAGS", - "-Csplit-debuginfo=unpacked \ + rustflags += " -Csplit-debuginfo=unpacked \ -Clink-arg=-Wl,-rpath,@loader_path/../lib \ - -Zosx-rpath-install-name" - .to_string() - + env::var("RUSTFLAGS").as_deref().unwrap_or(""), - ); + -Zosx-rpath-install-name"; } else { - cmd.env( - "RUSTFLAGS", - "-Clink-arg=-Wl,-rpath=$ORIGIN/../lib ".to_string() - + env::var("RUSTFLAGS").as_deref().unwrap_or(""), - ); + rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib "; } } + cmd.env("RUSTFLAGS", rustflags); + eprintln!("[BUILD] rustc_codegen_cranelift"); crate::utils::spawn_and_wait(cmd); diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 1c78e7b5171..2956fb698e1 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -46,9 +46,9 @@ pub(crate) fn build_sysroot( // Build and copy cargo wrapper let mut build_cargo_wrapper_cmd = Command::new("rustc"); build_cargo_wrapper_cmd - .arg("scripts/cargo.rs") + .arg("scripts/cargo-clif.rs") .arg("-o") - .arg(target_dir.join("cargo")) + .arg(target_dir.join("cargo-clif")) .arg("-g"); spawn_and_wait(build_cargo_wrapper_cmd); diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md index bcc5745d9d1..785c7383783 100644 --- a/compiler/rustc_codegen_cranelift/docs/usage.md +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -9,7 +9,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/build/cargo build +$ $cg_clif_dir/build/cargo-clif build ``` This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. @@ -32,7 +32,7 @@ In jit mode cg_clif will immediately execute your code without creating an execu > The jit mode will probably need cargo integration to make this possible. ```bash -$ $cg_clif_dir/build/cargo jit +$ $cg_clif_dir/build/cargo-clif jit ``` or @@ -45,7 +45,7 @@ There is also an experimental lazy jit mode. In this mode functions are only com first called. ```bash -$ $cg_clif_dir/build/cargo lazy-jit +$ $cg_clif_dir/build/cargo-clif lazy-jit ``` ## Shell diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index cbfdb3c44f3..ef3b575d393 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -129,6 +129,7 @@ fn call_return_u128_pair() { return_u128_pair(); } +#[allow(unreachable_code)] // FIXME false positive fn main() { take_unique(Unique { pointer: 0 as *const (), diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 7b5db307a2d..cab94c0b8cf 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-12-20" +channel = "nightly-2021-12-30" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs index 41d82b581cd..41d82b581cd 100644 --- a/compiler/rustc_codegen_cranelift/scripts/cargo.rs +++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 46c3b5b7f11..73600faa1e9 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -./y.rs build +./y.rs build --no-unstable-features source scripts/config.sh echo "[SETUP] Rust fork" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 99fddf5361e..6bcc3049ecc 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -47,6 +47,8 @@ rm src/test/ui/codegen/init-large-type.rs # same rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected rm src/test/ui/issues/issue-33992.rs # unsupported linkages rm src/test/ui/issues/issue-51947.rs # same +rm src/test/incremental/hashes/function_interfaces.rs # same +rm src/test/incremental/hashes/statics.rs # same rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants rm src/test/ui/mir/mir_raw_fat_ptr.rs # same @@ -60,18 +62,14 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n rm src/test/incremental/hashes/inline_asm.rs # inline asm rm src/test/incremental/issue-72386.rs # same -rm src/test/incremental/issue-49482.rs # same -rm src/test/incremental/issue-54059.rs # same rm src/test/incremental/lto.rs # requires lto +rm src/test/incremental/dirty_clean.rs # TODO rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/ rm -r src/test/run-make/unstable-flag-required # same rm -r src/test/run-make/rustdoc-* # same rm -r src/test/run-make/emit-named-files # requires full --emit support -rm src/test/pretty/asm.rs # inline asm -rm src/test/pretty/raw-str-nonexpr.rs # same - rm -r src/test/run-pass-valgrind/unsized-locals rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning @@ -97,6 +95,12 @@ rm src/test/ui/command/command-current-dir.rs # can't find libstd.so rm src/test/ui/abi/stack-protector.rs # requires stack protector support +rm src/test/incremental/issue-80691-bad-eval-cache.rs # wrong exit code +rm src/test/incremental/spike-neg1.rs # errors out for some reason +rm src/test/incremental/spike-neg2.rs # same + +rm src/test/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM + echo "[TEST] rustc test suite" -RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui} +RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental} popd diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index fd2b3761ff0..bdb3de0936d 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -80,73 +80,73 @@ function base_sysroot_tests() { function extended_sysroot_tests() { pushd rand - ../build/cargo clean + ../build/cargo-clif clean if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[TEST] rust-random/rand" - ../build/cargo test --workspace + ../build/cargo-clif test --workspace else echo "[AOT] rust-random/rand" - ../build/cargo build --workspace --target $TARGET_TRIPLE --tests + ../build/cargo-clif build --workspace --target $TARGET_TRIPLE --tests fi popd pushd simple-raytracer if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[BENCH COMPILE] ebobby/simple-raytracer" - hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo clean" \ + hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \ "RUSTC=rustc RUSTFLAGS='' cargo build" \ - "../build/cargo build" + "../build/cargo-clif build" echo "[BENCH RUN] ebobby/simple-raytracer" cp ./target/debug/main ./raytracer_cg_clif hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif else - ../build/cargo clean + ../build/cargo-clif clean echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" echo "[COMPILE] ebobby/simple-raytracer" - ../build/cargo build --target $TARGET_TRIPLE + ../build/cargo-clif build --target $TARGET_TRIPLE echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" fi popd pushd build_sysroot/sysroot_src/library/core/tests echo "[TEST] libcore" - ../../../../../build/cargo clean + ../../../../../build/cargo-clif clean if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - ../../../../../build/cargo test + ../../../../../build/cargo-clif test else - ../../../../../build/cargo build --target $TARGET_TRIPLE --tests + ../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests fi popd pushd regex echo "[TEST] rust-lang/regex example shootout-regex-dna" - ../build/cargo clean + ../build/cargo-clif clean export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning # Make sure `[codegen mono items] start` doesn't poison the diff - ../build/cargo build --example shootout-regex-dna --target $TARGET_TRIPLE + ../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then cat examples/regexdna-input.txt \ - | ../build/cargo run --example shootout-regex-dna --target $TARGET_TRIPLE \ + | ../build/cargo-clif run --example shootout-regex-dna --target $TARGET_TRIPLE \ | grep -v "Spawned thread" > res.txt diff -u res.txt examples/regexdna-output.txt fi if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[TEST] rust-lang/regex tests" - ../build/cargo test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q + ../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q else echo "[AOT] rust-lang/regex tests" - ../build/cargo build --tests --target $TARGET_TRIPLE + ../build/cargo-clif build --tests --target $TARGET_TRIPLE fi popd pushd portable-simd echo "[TEST] rust-lang/portable-simd" - ../build/cargo clean - ../build/cargo build --all-targets --target $TARGET_TRIPLE + ../build/cargo-clif clean + ../build/cargo-clif build --all-targets --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - ../build/cargo test -q + ../build/cargo-clif test -q fi popd } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fc2f04f146e..b16f5af66f2 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -715,30 +715,6 @@ fn codegen_stmt<'tcx>( let operand = operand.load_scalar(fx); lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } - Rvalue::NullaryOp(NullOp::Box, content_ty) => { - let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap(); - let content_ty = fx.monomorphize(content_ty); - let layout = fx.layout_of(content_ty); - let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64); - let llalign = fx.bcx.ins().iconst(usize_type, layout.align.abi.bytes() as i64); - let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); - - // Allocate space: - let def_id = - match fx.tcx.lang_items().require(rustc_hir::LangItem::ExchangeMalloc) { - Ok(id) => id, - Err(s) => { - fx.tcx - .sess - .fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); - let func_ref = fx.get_function_ref(instance); - let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]); - let ptr = fx.bcx.inst_results(call)[0]; - lval.write_cvalue(fx, CValue::by_val(ptr, box_layout)); - } Rvalue::NullaryOp(null_op, ty) => { assert!( lval.layout() @@ -749,7 +725,6 @@ fn codegen_stmt<'tcx>( let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::Box => unreachable!(), }; let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into()); lval.write_cvalue(fx, val); diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 644204d10b8..3b6025c73d1 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -237,7 +237,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) module: &'m mut dyn Module, pub(crate) tcx: TyCtxt<'tcx>, pub(crate) target_config: TargetFrontendConfig, // Cached from module - pub(crate) pointer_type: Type, // Cached from module + pub(crate) pointer_type: Type, // Cached from module pub(crate) constants_cx: ConstantCx, pub(crate) instance: Instance<'tcx>, diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index 4120ba6e533..589910ede96 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -67,7 +67,7 @@ impl WriterRelocate { } /// Perform the collected relocations to be usable for JIT usage. - #[cfg(feature = "jit")] + #[cfg(all(feature = "jit", not(windows)))] pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> { for reloc in self.relocs.drain(..) { match reloc.name { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index dd19dd5d2b9..638b025be22 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -10,7 +10,7 @@ use crate::prelude::*; use rustc_index::vec::IndexVec; use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::ir::{LabelValueLoc, ValueLabel}; +use cranelift_codegen::ir::{Endianness, LabelValueLoc, ValueLabel}; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::ValueLocRange; @@ -23,15 +23,6 @@ use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64}; pub(crate) use emit::{DebugReloc, DebugRelocName}; pub(crate) use unwind::UnwindContext; -fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian { - use rustc_target::abi::Endian; - - match tcx.data_layout.endian { - Endian::Big => RunTimeEndian::Big, - Endian::Little => RunTimeEndian::Little, - } -} - pub(crate) struct DebugContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -60,6 +51,11 @@ impl<'tcx> DebugContext<'tcx> { address_size: isa.frontend_config().pointer_bytes(), }; + let endian = match isa.endianness() { + Endianness::Little => RunTimeEndian::Little, + Endianness::Big => RunTimeEndian::Big, + }; + let mut dwarf = DwarfUnit::new(encoding); let producer = format!( @@ -108,7 +104,7 @@ impl<'tcx> DebugContext<'tcx> { DebugContext { tcx, - endian: target_endian(tcx), + endian, dwarf, unit_range_list: RangeList(Vec::new()), diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index f0896ea0e16..e4f28338096 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -2,6 +2,7 @@ use crate::prelude::*; +use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; use cranelift_object::ObjectProduct; @@ -17,8 +18,11 @@ pub(crate) struct UnwindContext { } impl UnwindContext { - pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { - let endian = super::target_endian(tcx); + pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { + let endian = match isa.endianness() { + Endianness::Little => RunTimeEndian::Little, + Endianness::Big => RunTimeEndian::Big, + }; let mut frame_table = FrameTable::default(); let cie_id = if let Some(mut cie) = isa.create_systemv_cie() { diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 7f888c80464..046e4393a68 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -243,7 +243,7 @@ pub(crate) fn run_aot( let isa = crate::build_isa(tcx.sess, &backend_config); let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string()); assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); - let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true); + let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 3f288474827..cb18f42f741 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -141,7 +141,7 @@ impl<'tcx> CodegenCx<'tcx> { assert_eq!(pointer_ty(tcx), isa.pointer_type()); let unwind_context = - UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); + UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None }; CodegenCx { tcx, diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 60a2101c689..47925f72c2c 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -18,12 +18,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1" [[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -36,15 +30,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if", -] - -[[package]] name = "fm" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -56,7 +41,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef" dependencies = [ "gccjit_sys", ] @@ -64,7 +49,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef" dependencies = [ "libc 0.1.12", ] @@ -85,33 +70,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", - "libc 0.2.102", + "libc 0.2.112", "wasi", ] [[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "libc 0.2.102", -] - -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", + "libc 0.2.112", ] [[package]] @@ -122,7 +91,7 @@ checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" dependencies = [ "fm", "getopts", - "libc 0.2.102", + "libc 0.2.112", "num_cpus", "termcolor", "threadpool", @@ -138,9 +107,9 @@ checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" [[package]] name = "libc" -version = "0.2.102" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "memchr" @@ -155,25 +124,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", - "libc 0.2.102", -] - -[[package]] -name = "object" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" -dependencies = [ - "crc32fast", - "indexmap", - "memchr", + "libc 0.2.112", ] [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "rand" @@ -181,7 +139,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ - "libc 0.2.102", + "libc 0.2.112", "rand_chacha", "rand_core", "rand_hc", @@ -257,7 +215,6 @@ dependencies = [ "ar", "gccjit", "lang_tester", - "object", "target-lexicon", "tempfile", ] @@ -284,7 +241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", - "libc 0.2.102", + "libc 0.2.112", "rand", "redox_syscall", "remove_dir_all", @@ -321,7 +278,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ - "libc 0.2.102", + "libc 0.2.112", ] [[package]] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 9e8c195c15f..21f0bfbf69d 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -23,11 +23,6 @@ target-lexicon = "0.10.0" ar = "0.8.0" -[dependencies.object] -version = "0.25.0" -default-features = false -features = ["read", "std", "write"] # We don't need WASM support. - [dev-dependencies] lang_tester = "0.3.9" tempfile = "3.1.0" diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md index 709d93c6edb..1fcfb5f6e20 100644 --- a/compiler/rustc_codegen_gcc/Readme.md +++ b/compiler/rustc_codegen_gcc/Readme.md @@ -111,6 +111,8 @@ Or add a breakpoint to `add_error` in gdb and print the line number using: p loc->m_line ``` +To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. + ### How to use a custom-build rustc * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh index 87df2f2102b..a932c1c8372 100644 --- a/compiler/rustc_codegen_gcc/config.sh +++ b/compiler/rustc_codegen_gcc/config.sh @@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then fi fi -export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" +export RUSTFLAGS="$linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" # FIXME(antoyo): remove once the atomic shim is gone if [[ `uname` == 'Darwin' ]]; then diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch index ee5ba449fb8..73e9c858caf 100644 --- a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch +++ b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch @@ -46,4 +46,24 @@ index 4bc44e9..8e3c7a4 100644 #[test] fn cell_allows_array_cycle() { +diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs +index 3e00e0a..8e5663b 100644 +--- a/library/core/tests/slice.rs ++++ b/library/core/tests/slice.rs +@@ -2108,6 +2108,7 @@ fn test_copy_within_panics_src_out_of_bounds() { + bytes.copy_within(usize::MAX..=usize::MAX, 0); + } + ++/* + #[test] + fn test_is_sorted() { + let empty: [i32; 0] = []; +@@ -2122,6 +2123,7 @@ fn test_is_sorted() { + assert!(!["c", "bb", "aaa"].is_sorted()); + assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + } ++*/ + + #[test] + fn test_slice_run_destructors() { -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch new file mode 100644 index 00000000000..8954f91021f --- /dev/null +++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch @@ -0,0 +1,24 @@ +From b1ae000f6da1abd3b8e9b80c40bc11c89b8ae93c Mon Sep 17 00:00:00 2001 +From: bjorn3 <bjorn3@users.noreply.github.com> +Date: Thu, 30 Dec 2021 16:54:40 +0100 +Subject: [PATCH] [core] Disable portable-simd test + +--- + library/core/tests/lib.rs | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs +index ec70034..7cd9e21 100644 +--- a/library/core/tests/lib.rs ++++ b/library/core/tests/lib.rs +@@ -121,7 +121,6 @@ mod pattern; + mod pin; + mod ptr; + mod result; +-mod simd; + mod slice; + mod str; + mod str_lossy; +-- +2.26.2.7.g19db9cfb68 + diff --git a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch new file mode 100644 index 00000000000..bf74a74c7c4 --- /dev/null +++ b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch @@ -0,0 +1,30 @@ +From 0ffdd8eda8df364391c8ac6e1ce92c73ba9254d4 Mon Sep 17 00:00:00 2001 +From: bjorn3 <bjorn3@users.noreply.github.com> +Date: Fri, 3 Dec 2021 12:16:30 +0100 +Subject: [PATCH] Disable long running tests + +--- + library/core/tests/slice.rs | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs +index 2c8f00a..44847ee 100644 +--- a/library/core/tests/slice.rs ++++ b/library/core/tests/slice.rs +@@ -2332,7 +2332,8 @@ macro_rules! empty_max_mut { + }; + } + ++/* + #[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) + take_tests! { + slice: &[(); usize::MAX], method: take, + (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), +@@ -2345,3 +2347,4 @@ take_tests! { + (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), + } ++*/ +-- +2.26.2.7.g19db9cfb68 + diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index d311a33f807..ee0822f6c31 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1 +1 @@ -nightly-2021-09-28 +nightly-2021-12-30 diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 10edcf36955..453bcd601d3 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -18,30 +18,30 @@ use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. // -// 1. Rust asm operands go along as one list of operands. Operands themselves indicate -// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be +// 1. Rust asm operands go along as one list of operands. Operands themselves indicate +// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be // both "in" and "out" (`inout(reg)`). // -// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, -// this means that all "out" operands must go before "in" operands. "In" and "out" operands +// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, +// this means that all "out" operands must go before "in" operands. "In" and "out" operands // cannot interleave. // -// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important +// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important // because the asm template refers to operands by index. // // Mapping from Rust to GCC index would be 1-1 if it wasn't for... // -// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. -// Contrary, Rust expresses clobbers through "out" operands that aren't tied to +// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. +// Contrary, Rust expresses clobbers through "out" operands that aren't tied to // a variable (`_`), and such "clobbers" do have index. // -// 4. Furthermore, GCC Extended Asm does not support explicit register constraints -// (like `out("eax")`) directly, offering so-called "local register variables" -// as a workaround. These variables need to be declared and initialized *before* -// the Extended Asm block but *after* normal local variables +// 4. Furthermore, GCC Extended Asm does not support explicit register constraints +// (like `out("eax")`) directly, offering so-called "local register variables" +// as a workaround. These variables need to be declared and initialized *before* +// the Extended Asm block but *after* normal local variables // (see comment in `codegen_inline_asm` for explanation). // -// With that in mind, let's see how we translate Rust syntax to GCC +// With that in mind, let's see how we translate Rust syntax to GCC // (from now on, `CC` stands for "constraint code"): // // * `out(reg_class) var` -> translated to output operand: `"=CC"(var)` @@ -52,18 +52,17 @@ use crate::type_of::LayoutGccExt; // // * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list // -// * `inout(reg_class) in_var => out_var` -> translated to two operands: +// * `inout(reg_class) in_var => out_var` -> translated to two operands: // output: `"=CC"(in_var)` -// input: `"num"(out_var)` where num is the GCC index +// input: `"num"(out_var)` where num is the GCC index // of the corresponding output operand // -// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, +// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, // where "tmp" is a temporary unused variable // -// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above -// with `"r"(var)` constraint, +// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above +// with `"r"(var)` constraint, // and one register variable assigned to the desired register. -// const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t"; const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix"; @@ -131,7 +130,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX); let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX); - // GCC index of an output operand equals its position in the array + // GCC index of an output operand equals its position in the array let mut outputs = vec![]; // GCC index of an input operand equals its position in the array @@ -145,9 +144,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let mut constants_len = 0; // There are rules we must adhere to if we want GCC to do the right thing: - // + // // * Every local variable that the asm block uses as an output must be declared *before* - // the asm block. + // the asm block. // * There must be no instructions whatsoever between the register variables and the asm. // // Therefore, the backend must generate the instructions strictly in this order: @@ -159,7 +158,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // We also must make sure that no input operands are emitted before output operands. // // This is why we work in passes, first emitting local vars, then local register vars. - // Also, we don't emit any asm operands immediately; we save them to + // Also, we don't emit any asm operands immediately; we save them to // the one of the buffers to be emitted later. // 1. Normal variables (and saving operands to buffers). @@ -172,7 +171,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)), // When `reg` is a class and not an explicit register but the out place is not specified, // we need to create an unused output variable to assign the output to. This var - // needs to be of a type that's "compatible" with the register class, but specific type + // needs to be of a type that's "compatible" with the register class, but specific type // doesn't matter. (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())), (Register(_), Some(_)) => { @@ -200,7 +199,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let tmp_var = self.current_func().new_local(None, ty, "output_register"); outputs.push(AsmOutOperand { - constraint, + constraint, rust_idx, late, readwrite: false, @@ -211,12 +210,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::In { reg, value } => { if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { - inputs.push(AsmInOperand { - constraint: Cow::Borrowed(constraint), - rust_idx, + inputs.push(AsmInOperand { + constraint: Cow::Borrowed(constraint), + rust_idx, val: value.immediate() }); - } + } else { // left for the next pass continue @@ -226,7 +225,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { constraint - } + } else { // left for the next pass continue @@ -235,22 +234,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // Rustc frontend guarantees that input and output types are "compatible", // so we can just use input var's type for the output variable. // - // This decision is also backed by the fact that LLVM needs in and out - // values to be of *exactly the same type*, not just "compatible". + // This decision is also backed by the fact that LLVM needs in and out + // values to be of *exactly the same type*, not just "compatible". // I'm not sure if GCC is so picky too, but better safe than sorry. let ty = in_value.layout.gcc_type(self.cx, false); let tmp_var = self.current_func().new_local(None, ty, "output_register"); // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate - // it to one "readwrite (+) output variable", otherwise we translate it to two + // it to one "readwrite (+) output variable", otherwise we translate it to two // "out and tied in" vars as described above. let readwrite = out_place.is_none(); outputs.push(AsmOutOperand { - constraint, + constraint, rust_idx, late, readwrite, - tmp_var, + tmp_var, out_place, }); @@ -259,8 +258,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let constraint = Cow::Owned(out_gcc_idx.to_string()); inputs.push(AsmInOperand { - constraint, - rust_idx, + constraint, + rust_idx, val: in_value.immediate() }); } @@ -287,7 +286,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { let out_place = if let Some(place) = place { place - } + } else { // processed in the previous pass continue @@ -298,7 +297,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { tmp_var.set_register_name(reg_name); outputs.push(AsmOutOperand { - constraint: "r".into(), + constraint: "r".into(), rust_idx, late, readwrite: false, @@ -318,9 +317,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { reg_var.set_register_name(reg_name); self.llbb().add_assignment(None, reg_var, value.immediate()); - inputs.push(AsmInOperand { - constraint: "r".into(), - rust_idx, + inputs.push(AsmInOperand { + constraint: "r".into(), + rust_idx, val: reg_var.to_rvalue() }); } @@ -331,31 +330,23 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // `inout("explicit register") in_var => out_var` InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { - let out_place = if let Some(place) = out_place { - place - } - else { - // processed in the previous pass - continue - }; - // See explanation in the first pass. let ty = in_value.layout.gcc_type(self.cx, false); let tmp_var = self.current_func().new_local(None, ty, "output_register"); tmp_var.set_register_name(reg_name); outputs.push(AsmOutOperand { - constraint: "r".into(), + constraint: "r".into(), rust_idx, late, readwrite: false, tmp_var, - out_place: Some(out_place) + out_place, }); let constraint = Cow::Owned((outputs.len() - 1).to_string()); - inputs.push(AsmInOperand { - constraint, + inputs.push(AsmInOperand { + constraint, rust_idx, val: in_value.immediate() }); @@ -364,8 +355,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // processed in the previous pass } - InlineAsmOperandRef::Const { .. } - | InlineAsmOperandRef::SymFn { .. } + InlineAsmOperandRef::Const { .. } + | InlineAsmOperandRef::SymFn { .. } | InlineAsmOperandRef::SymStatic { .. } => { // processed in the previous pass } @@ -460,7 +451,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if !intel_dialect { template_str.push_str(INTEL_SYNTAX_INS); } - + // 4. Generate Extended Asm block let block = self.llbb(); @@ -479,7 +470,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) { - // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient + // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient // on all architectures. For instance, what about FP stack? extended_asm.add_clobber("cc"); } @@ -498,10 +489,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { self.call(self.type_void(), builtin_unreachable, &[], None); } - // Write results to outputs. + // Write results to outputs. // // We need to do this because: - // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases + // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases // (especially with current `rustc_backend_ssa` API). // 2. Not every output operand has an `out_place`, and it's required by `add_output_operand`. // @@ -509,7 +500,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // generates `out_place = tmp_var;` assignments if out_place exists. for op in &outputs { if let Some(place) = op.out_place { - OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); + OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); } } diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 4962d016152..334ef32f1d1 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -1,4 +1,4 @@ -use std::fs; +use std::{env, fs}; use gccjit::OutputKind; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; @@ -42,17 +42,17 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); - match &*module.name { - "std_example.7rcbfp3g-cgu.15" => { - println!("Dumping reproducer {}", module.name); - let _ = fs::create_dir("/tmp/reproducers"); - // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by - // transmuting an rvalue to an lvalue. - // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue - context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name)); - println!("Dumped reproducer {}", module.name); - }, - _ => (), + if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") { + println!("Module {}", module.name); + } + if env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) { + println!("Dumping reproducer {}", module.name); + let _ = fs::create_dir("/tmp/reproducers"); + // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by + // transmuting an rvalue to an lvalue. + // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue + context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name)); + println!("Dumped reproducer {}", module.name); } context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); } diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index dee70bf7536..8b23e96066e 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -81,7 +81,10 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul for arg in &tcx.sess.opts.cg.llvm_args { context.add_command_line_option(arg); } + // NOTE: an optimization (https://github.com/rust-lang/rustc_codegen_gcc/issues/53). context.add_command_line_option("-fno-semantic-interposition"); + // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292). + context.add_command_line_option("-fno-strict-aliasing"); if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") { context.set_dump_code_on_compile(true); } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index fff2aa6df7c..379c88bbd40 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -200,7 +200,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { let mut all_args_match = true; let mut param_types = vec![]; - let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) { let param = gcc_func.get_param_type(index); if param != arg.get_type() { @@ -277,7 +277,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local or call add_eval(). - let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); let mut return_type = gcc_func.get_return_type(); let current_block = self.current_block.borrow().expect("block"); let void_type = self.context.new_type::<()>(); @@ -605,22 +605,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { - // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: - // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 if a.get_type() != b.get_type() { b = self.context.new_cast(None, b, a.get_type()); } - let res = self.current_func().new_local(None, b.get_type(), "andResult"); - self.llbb().add_assignment(None, res, a & b); - res.to_rvalue() + a & b } - fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: - // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 - let res = self.current_func().new_local(None, b.get_type(), "orResult"); - self.llbb().add_assignment(None, res, a | b); - res.to_rvalue() + fn or(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + if a.get_type() != b.get_type() { + b = self.context.new_cast(None, b, a.get_type()); + } + a | b } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -628,8 +623,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): use new_unary_op()? - self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a + self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { @@ -816,7 +810,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let volatile_const_void_ptr_type = self.context.new_type::<()>() + .make_const() + .make_volatile() + .make_pointer(); let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); self.context.new_call(None, atomic_load, &[ptr, ordering]) } @@ -941,7 +938,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): handle alignment. let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let volatile_const_void_ptr_type = self.context.new_type::<()>() + .make_volatile() + .make_pointer(); let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because @@ -981,12 +980,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value = ptr.dereference(None).to_rvalue(); - if value_type.is_array().is_some() { + if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); let element = self.context.new_array_access(None, value, index); element.get_address(None) } - else if let Some(vector_type) = value_type.is_vector() { + else if let Some(vector_type) = value_type.dyncast_vector() { let array_type = vector_type.get_element_type().make_pointer(); let array = self.bitcast(ptr, array_type); let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); @@ -1009,7 +1008,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): check that it indeed sign extend the value. - if dest_ty.is_vector().is_some() { + if dest_ty.dyncast_vector().is_some() { // TODO(antoyo): nothing to do as it is only for LLVM? return value; } @@ -1081,7 +1080,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let right_type = rhs.get_type(); if left_type != right_type { // NOTE: because libgccjit cannot compare function pointers. - if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() { + if left_type.dyncast_function_ptr_type().is_some() && right_type.dyncast_function_ptr_type().is_some() { lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); } @@ -1189,12 +1188,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value_type = aggregate_value.get_type(); - if value_type.is_array().is_some() { + if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); let element = self.context.new_array_access(None, aggregate_value, index); element.get_address(None) } - else if value_type.is_vector().is_some() { + else if value_type.dyncast_vector().is_some() { panic!(); } else if let Some(pointer_type) = value_type.get_pointee() { @@ -1221,11 +1220,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let value_type = aggregate_value.get_type(); let lvalue = - if value_type.is_array().is_some() { + if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); self.context.new_array_access(None, aggregate_value, index) } - else if value_type.is_vector().is_some() { + else if value_type.dyncast_vector().is_some() { panic!(); } else if let Some(pointer_type) = value_type.get_pointee() { @@ -1404,7 +1403,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.cx } - fn do_not_inline(&mut self, _llret: RValue<'gcc>) { + fn apply_attrs_to_cleanup_callsite(&mut self, _llret: RValue<'gcc>) { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ec542e55681..5851826147d 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,5 +1,4 @@ use std::convert::TryFrom; -use std::convert::TryInto; use gccjit::LValue; use gccjit::{Block, CType, RValue, Type, ToRValue}; @@ -44,7 +43,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let string = self.context.new_string_literal(&*string); let sym = self.generate_local_symbol_name("str"); let global = self.declare_private_global(&sym, self.val_ty(string)); - global.global_set_initializer_value(string); + global.global_set_initializer_rvalue(string); global // TODO(antoyo): set linkage. } @@ -79,7 +78,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> bytes.iter() .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) .collect(); - context.new_rvalue_from_array(None, typ, &elements) + context.new_array_constructor(None, typ, &elements) } pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool { @@ -120,13 +119,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { - let num64: Result<i64, _> = num.try_into(); - if let Ok(num) = num64 { - // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant. - // The operations >> 64 and | low are making the normal case a non-constant. - return self.context.new_rvalue_from_long(typ, num as i64); - } - if num >> 64 != 0 { // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()? let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); @@ -193,7 +185,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // TODO(antoyo): cache the type? It's anonymous, so probably not. let typ = self.type_struct(&fields, packed); let struct_type = typ.is_struct().expect("struct type"); - self.context.new_rvalue_from_struct(None, struct_type, values) + self.context.new_struct_constructor(None, struct_type.as_type(), None, values) } fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 205498acc31..ba4589bd810 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -20,7 +20,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { if value.get_type() == self.bool_type.make_pointer() { if let Some(pointee) = typ.get_pointee() { - if pointee.is_vector().is_some() { + if pointee.dyncast_vector().is_some() { panic!() } } @@ -31,9 +31,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { - if let Some(global_value) = self.const_globals.borrow().get(&cv) { - // TODO(antoyo): upgrade alignment. - return *global_value; + // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the + // following: + for (value, variable) in &*self.const_globals.borrow() { + if format!("{:?}", value) == format!("{:?}", cv) { + // TODO(antoyo): upgrade alignment. + return *variable; + } } let global_value = self.static_addr_of_mut(cv, align, kind); // TODO(antoyo): set global constant. @@ -77,7 +81,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { else { value }; - global.global_set_initializer_value(value); + global.global_set_initializer_rvalue(value); // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. @@ -176,7 +180,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { }; // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used // globally. - global.global_set_initializer_value(cv); + global.global_set_initializer_rvalue(cv); // TODO(antoyo): set unnamed address. global.get_address(None) } @@ -371,7 +375,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg real_name.push_str(&sym); let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section); // TODO(antoyo): set linkage. - global2.global_set_initializer_value(global1.get_address(None)); + global2.global_set_initializer_rvalue(global1.get_address(None)); // TODO(antoyo): use global_set_initializer() when it will work. global2 } diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 7677ade7314..dfcd1b62312 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -1,16 +1,6 @@ use std::cell::{Cell, RefCell}; -use gccjit::{ - Block, - Context, - CType, - Function, - FunctionType, - LValue, - RValue, - Struct, - Type, -}; +use gccjit::{Block, CType, Context, Function, FunctionType, LValue, RValue, Struct, Type}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::traits::{ BackendTypes, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 0782adeb6a1..572ac559d09 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -526,7 +526,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = if result_type.is_signed(self.cx) { - self.context.new_bitcast(None, value, typ) + self.context.new_cast(None, value, typ) } else { value @@ -690,7 +690,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }, }; - self.context.new_bitcast(None, result, result_type) + self.context.new_cast(None, result, result_type) } fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { @@ -741,6 +741,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); let not_low_and_not_high = not_low & not_high; let index = not_high + not_low_and_not_high; + // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in + // gcc. + // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the + // compilation stage. + let index = self.context.new_cast(None, index, self.i32_type); let res = self.context.new_array_access(None, result, index); @@ -764,7 +769,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let arg = if result_type.is_signed(self.cx) { let new_type = result_type.to_unsigned(self.cx); - self.context.new_bitcast(None, arg, new_type) + self.context.new_cast(None, arg, new_type) } else { arg @@ -816,10 +821,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); let not_low_and_not_high = not_low & not_high; let index = not_low + not_low_and_not_high; + // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in + // gcc. + // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the + // compilation stage. + let index = self.context.new_cast(None, index, self.i32_type); let res = self.context.new_array_access(None, result, index); - return self.context.new_bitcast(None, res, result_type); + return self.context.new_cast(None, res, result_type); } else { unimplemented!("count_trailing_zeroes for {:?}", arg_type); @@ -833,7 +843,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { arg }; let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); - self.context.new_bitcast(None, res, result_type) + self.context.new_cast(None, res, result_type) } fn int_width(&self, typ: Type<'gcc>) -> i64 { @@ -847,7 +857,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = if result_type.is_signed(self.cx) { - self.context.new_bitcast(None, value, value_type) + self.context.new_cast(None, value, value_type) } else { value @@ -863,7 +873,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let low = self.context.new_cast(None, value, self.cx.ulonglong_type); let low = self.context.new_call(None, popcount, &[low]); let res = high + low; - return self.context.new_bitcast(None, res, result_type); + return self.context.new_cast(None, res, result_type); } // First step. @@ -888,7 +898,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = left + right; if value_type.is_u8(&self.cx) { - return self.context.new_bitcast(None, value, result_type); + return self.context.new_cast(None, value, result_type); } // Fourth step. @@ -899,7 +909,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = left + right; if value_type.is_u16(&self.cx) { - return self.context.new_bitcast(None, value, result_type); + return self.context.new_cast(None, value, result_type); } // Fifth step. @@ -910,7 +920,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = left + right; if value_type.is_u32(&self.cx) { - return self.context.new_bitcast(None, value, result_type); + return self.context.new_cast(None, value, result_type); } // Sixth step. @@ -920,7 +930,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let right = shifted & mask; let value = left + right; - self.context.new_bitcast(None, value, result_type) + self.context.new_cast(None, value, result_type) } // Algorithm from: https://blog.regehr.org/archives/1063 diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 30a33b99e50..20347f18786 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -20,7 +20,6 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; -extern crate rustc_symbol_mangling; extern crate rustc_target; // This prevents duplicating functions and statics that are already part of the host rustc process. @@ -91,8 +90,6 @@ impl CodegenBackend for GccCodegenBackend { let target_cpu = target_cpu(tcx.sess); let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module); - rustc_symbol_mangling::test::report_symbol_names(tcx); - Box::new(res) } diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 3545e1b6281..28e2adc492b 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -122,7 +122,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if typ.is_integral() { TypeKind::Integer } - else if typ.is_vector().is_some() { + else if typ.dyncast_vector().is_some() { TypeKind::Vector } else { @@ -141,10 +141,10 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> { - if let Some(typ) = ty.is_array() { + if let Some(typ) = ty.dyncast_array() { typ } - else if let Some(vector_type) = ty.is_vector() { + else if let Some(vector_type) = ty.dyncast_vector() { vector_type.get_element_type() } else if let Some(typ) = ty.get_pointee() { diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh index 944d0ce516e..b9aeee79550 100755 --- a/compiler/rustc_codegen_gcc/test.sh +++ b/compiler/rustc_codegen_gcc/test.sh @@ -183,7 +183,7 @@ EOF git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro. - RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" + RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" echo "[TEST] rustc test suite" COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS" diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs index 48c0203d594..46abbb553bf 100644 --- a/compiler/rustc_codegen_gcc/tests/run/asm.rs +++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs @@ -3,6 +3,10 @@ // Run-time: // status: 0 +#![feature(asm_const, asm_sym)] + +use std::arch::{asm, global_asm}; + global_asm!(" .global add_asm add_asm: @@ -15,6 +19,16 @@ extern "C" { fn add_asm(a: i64, b: i64) -> i64; } +pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) { + asm!( + "rep movsb", + inout("rdi") dst => _, + inout("rsi") src => _, + inout("rcx") len => _, + options(preserves_flags, nostack) + ); +} + fn main() { unsafe { asm!("nop"); @@ -60,11 +74,11 @@ fn main() { } assert_eq!(x, 43); - // check inout(reg_class) x + // check inout(reg_class) x let mut x: u64 = 42; unsafe { asm!("add {0}, {0}", - inout(reg) x + inout(reg) x ); } assert_eq!(x, 84); @@ -73,7 +87,7 @@ fn main() { let mut x: u64 = 42; unsafe { asm!("add r11, r11", - inout("r11") x + inout("r11") x ); } assert_eq!(x, 84); @@ -96,12 +110,12 @@ fn main() { assert_eq!(res, 7); assert_eq!(rem, 2); - // check const + // check const let mut x: u64 = 42; unsafe { asm!("add {}, {}", inout(reg) x, - const 1 + const 1 ); } assert_eq!(x, 43); @@ -148,4 +162,11 @@ fn main() { assert_eq!(x, 42); assert_eq!(unsafe { add_asm(40, 2) }, 42); + + let array1 = [1u8, 2, 3]; + let mut array2 = [0u8, 0, 0]; + unsafe { + mem_cpy(array2.as_mut_ptr(), array1.as_ptr(), 3); + } + assert_eq!(array1, array2); } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 4bb1fed2d51..ddba43cd1f1 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -3,7 +3,7 @@ use crate::back::write::{ }; use crate::llvm::archive_ro::ArchiveRO; use crate::llvm::{self, build_string, False, True}; -use crate::{LlvmCodegenBackend, ModuleLlvm}; +use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{ @@ -596,7 +596,10 @@ pub(crate) fn run_pass_manager( // tools/lto/LTOCodeGenerator.cpp debug!("running the pass manager"); unsafe { - if write::should_use_new_llvm_pass_manager(cgcx, config) { + if llvm_util::should_use_new_llvm_pass_manager( + &config.new_llvm_pass_manager, + &cgcx.target_arch, + ) { let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); write::optimize_with_new_llvm_pass_manager( diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index fb194a98a0d..fd7c58c8e32 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -416,21 +416,6 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> { .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()) } -pub(crate) fn should_use_new_llvm_pass_manager( - cgcx: &CodegenContext<LlvmCodegenBackend>, - config: &ModuleConfig, -) -> bool { - // The new pass manager is enabled by default for LLVM >= 13. - // This matches Clang, which also enables it since Clang 13. - - // FIXME: There are some perf issues with the new pass manager - // when targeting s390x, so it is temporarily disabled for that - // arch, see https://github.com/rust-lang/rust/issues/89609 - config - .new_llvm_pass_manager - .unwrap_or_else(|| cgcx.target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0)) -} - pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( cgcx: &CodegenContext<LlvmCodegenBackend>, diag_handler: &Handler, @@ -473,6 +458,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( let extra_passes = config.passes.join(","); + let llvm_plugins = config.llvm_plugins.join(","); + // FIXME: NewPM doesn't provide a facility to pass custom InlineParams. // We would have to add upstream support for this first, before we can support // config.inline_threshold and our more aggressive default thresholds. @@ -502,6 +489,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( selfprofile_after_pass_callback, extra_passes.as_ptr().cast(), extra_passes.len(), + llvm_plugins.as_ptr().cast(), + llvm_plugins.len(), ); result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes")) } @@ -530,7 +519,10 @@ pub(crate) unsafe fn optimize( } if let Some(opt_level) = config.opt_level { - if should_use_new_llvm_pass_manager(cgcx, config) { + if llvm_util::should_use_new_llvm_pass_manager( + &config.new_llvm_pass_manager, + &cgcx.target_arch, + ) { let opt_stage = match cgcx.lto { Lto::Fat => llvm::OptStage::PreLinkFatLTO, Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8c3054b23ff..5217fa2758f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1201,8 +1201,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED) } } - fn do_not_inline(&mut self, llret: &'ll Value) { - llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); + fn apply_attrs_to_cleanup_callsite(&mut self, llret: &'ll Value) { + // Cleanup is always the cold path. + llvm::Attribute::Cold.apply_callsite(llvm::AttributePlace::Function, llret); + + // In LLVM versions with deferred inlining (currently, system LLVM < 14), + // inlining drop glue can lead to exponential size blowup, see #41696 and #92110. + if !llvm_util::is_rust_llvm() && llvm_util::get_version() < (14, 0, 0) { + llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); + } } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 9f24a95482c..bb16bc5dccd 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_session::config::{CFGuard, CrateType, DebugInfo}; +use rustc_session::config::{BranchProtection, CFGuard, CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -242,6 +242,34 @@ pub unsafe fn create_module<'ll>( } } + if sess.target.arch == "aarch64" { + let BranchProtection { bti, pac_ret: pac } = sess.opts.debugging_opts.branch_protection; + + llvm::LLVMRustAddModuleFlag( + llmod, + "branch-target-enforcement\0".as_ptr().cast(), + bti.into(), + ); + + llvm::LLVMRustAddModuleFlag( + llmod, + "sign-return-address\0".as_ptr().cast(), + pac.is_some().into(), + ); + let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); + llvm::LLVMRustAddModuleFlag( + llmod, + "sign-return-address-all\0".as_ptr().cast(), + pac_opts.leaf.into(), + ); + let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true }; + llvm::LLVMRustAddModuleFlag( + llmod, + "sign-return-address-with-bkey\0".as_ptr().cast(), + is_bkey.into(), + ); + } + llmod } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 90d0d5caba1..a6e06ffa819 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -47,6 +47,7 @@ fn declare_raw_fn<'ll>( attributes::default_optimisation_attrs(cx.tcx.sess, llfn); attributes::non_lazy_bind(cx.sess(), llfn); + llfn } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 6c911938ccc..6450b7490bd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1902,6 +1902,8 @@ extern "C" { pub fn LLVMRustVersionMinor() -> u32; pub fn LLVMRustVersionPatch() -> u32; + pub fn LLVMRustIsRustLLVM() -> bool; + pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32); pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; @@ -2313,6 +2315,8 @@ extern "C" { end_callback: SelfProfileAfterPassCallback, ExtraPasses: *const c_char, ExtraPassesLen: size_t, + LLVMPlugins: *const c_char, + LLVMPluginsLen: size_t, ) -> LLVMRustResult; pub fn LLVMRustPrintModule( M: &Module, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e4935ac431c..d49df29f453 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -121,14 +121,20 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMInitializePasses(); - // Register LLVM plugins by loading them into the compiler process. - for plugin in &sess.opts.debugging_opts.llvm_plugins { - let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e)); - debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin); - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long. - mem::forget(lib); + // Use the legacy plugin registration if we don't use the new pass manager + if !should_use_new_llvm_pass_manager( + &sess.opts.debugging_opts.new_llvm_pass_manager, + &sess.target.arch, + ) { + // Register LLVM plugins by loading them into the compiler process. + for plugin in &sess.opts.debugging_opts.llvm_plugins { + let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e)); + debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin); + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + mem::forget(lib); + } } rustc_llvm::initialize_available_targets(); @@ -217,6 +223,12 @@ pub fn get_version() -> (u32, u32, u32) { } } +/// Returns `true` if this LLVM is Rust's bundled LLVM (and not system LLVM). +pub fn is_rust_llvm() -> bool { + // Can be called without initializing LLVM + unsafe { llvm::LLVMRustIsRustLLVM() } +} + pub fn print_passes() { // Can be called without initializing LLVM unsafe { @@ -411,3 +423,13 @@ pub fn tune_cpu(sess: &Session) -> Option<&str> { let name = sess.opts.debugging_opts.tune_cpu.as_ref()?; Some(handle_native(name)) } + +pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_arch: &str) -> bool { + // The new pass manager is enabled by default for LLVM >= 13. + // This matches Clang, which also enables it since Clang 13. + + // FIXME: There are some perf issues with the new pass manager + // when targeting s390x, so it is temporarily disabled for that + // arch, see https://github.com/rust-lang/rust/issues/89609 + user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0)) +} diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index d6af6104155..0281fd929c5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -113,6 +113,7 @@ pub struct ModuleConfig { pub inline_threshold: Option<u32>, pub new_llvm_pass_manager: Option<bool>, pub emit_lifetime_markers: bool, + pub llvm_plugins: Vec<String>, } impl ModuleConfig { @@ -260,6 +261,7 @@ impl ModuleConfig { inline_threshold: sess.opts.cg.inline_threshold, new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager, emit_lifetime_markers: sess.emit_lifetime_markers(), + llvm_plugins: if_regular!(sess.opts.debugging_opts.llvm_plugins.clone(), vec![]), } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e914e493269..dcfe5fcc2ca 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -160,11 +160,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { let llret = bx.call(fn_ty, fn_ptr, &llargs, self.funclet(fx)); bx.apply_attrs_callsite(&fn_abi, llret); if fx.mir[self.bb].is_cleanup { - // Cleanup is always the cold path. Don't inline - // drop glue. Also, when there is a deeply-nested - // struct, there are "symmetry" issues that cause - // exponential inlining - see issue #41696. - bx.do_not_inline(llret); + bx.apply_attrs_to_cleanup_callsite(llret); } if let Some((ret_dest, target)) = destination { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6f960ca44cd..679c4576701 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,7 +8,6 @@ use crate::traits::*; use crate::MemFlags; use rustc_apfloat::{ieee, Float, Round, Status}; -use rustc_hir::lang_items::LangItem; use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; @@ -486,31 +485,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) } - mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { - let content_ty = self.monomorphize(content_ty); - let content_layout = bx.cx().layout_of(content_ty); - let llsize = bx.cx().const_usize(content_layout.size.bytes()); - let llalign = bx.cx().const_usize(content_layout.align.abi.bytes()); - let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); - let llty_ptr = bx.cx().backend_type(box_layout); - - // Allocate space: - let def_id = match bx.tcx().lang_items().require(LangItem::ExchangeMalloc) { - Ok(id) => id, - Err(s) => { - bx.cx().sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(bx.tcx(), def_id); - let r = bx.cx().get_fn_addr(instance); - let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p()); - let call = bx.call(ty, r, &[llsize, llalign], None); - let val = bx.pointercast(call, llty_ptr); - - let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; - (bx, operand) - } - mir::Rvalue::NullaryOp(null_op, ty) => { let ty = self.monomorphize(ty); assert!(bx.cx().type_is_sized(ty)); @@ -518,7 +492,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), - mir::NullOp::Box => unreachable!(), }; let val = bx.cx().const_usize(val); let tcx = self.cx.tcx(); diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 158e658301e..48d88095855 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -311,5 +311,5 @@ pub trait BuilderMethods<'a, 'tcx>: ) -> Self::Value; fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn do_not_inline(&mut self, llret: Self::Value); + fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fef0e00e507..30e9cbe4403 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -398,13 +398,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) } - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) - } - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // The step limit has already been hit in a previous call to `before_terminator`. if ecx.machine.steps_remaining == 0 { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 246807a112a..0fc3827d16c 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -156,7 +156,7 @@ pub enum StackPopCleanup { /// `ret` stores the block we jump to on a normal return, while `unwind` /// stores the block used for cleanup during unwinding. Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind }, - /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. + /// Just do nothing: Used by Main and for TLS hooks in miri. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away /// the entire `ecx` when it is done). diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 6a03b699d47..23ec3875cbc 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -212,12 +212,6 @@ pub trait Machine<'mir, 'tcx>: Sized { right: &ImmTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>; - /// Heap allocations via the `box` keyword. - fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: &PlaceTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx>; - /// Called to read the specified `local` from the `frame`. /// Since reading a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6e37aae0f5e..3daa1d3c2b3 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -271,10 +271,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(place.to_ref(self), &dest)?; } - NullaryOp(mir::NullOp::Box, _) => { - M::box_alloc(self, &dest)?; - } - NullaryOp(null_op, ty) => { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; @@ -289,7 +285,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), - mir::NullOp::Box => unreachable!(), }; self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6be3e19a833..5a398c2f45a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -14,6 +14,7 @@ use rustc_middle::mir::interpret::InterpError; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::DUMMY_SP; use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange}; use std::hash::Hash; @@ -736,9 +737,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline(always)] fn visit_union( &mut self, - _op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::PointerTag>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { + // Special check preventing `UnsafeCell` inside unions in the inner part of constants. + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) { + if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) { + throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); + } + } Ok(()) } 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 1d5f4630152..dd749c03934 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -632,7 +632,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} - Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, ref operand) => { diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 1537de993d1..55fba5d7ddf 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -508,7 +508,6 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::NullaryOp(op, _) => match op { - NullOp::Box => return Err(Unpromotable), NullOp::SizeOf => {} NullOp::AlignOf => {} }, diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs index b5d2d24736c..716259142d1 100644 --- a/compiler/rustc_data_structures/src/thin_vec.rs +++ b/compiler/rustc_data_structures/src/thin_vec.rs @@ -5,7 +5,7 @@ use std::iter::FromIterator; /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`). /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`, /// which uses only a single (null) pointer. -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq)] pub struct ThinVec<T>(Option<Box<Vec<T>>>); impl<T> ThinVec<T> { @@ -20,6 +20,13 @@ impl<T> ThinVec<T> { pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { self.into_iter() } + + pub fn push(&mut self, item: T) { + match *self { + ThinVec(Some(ref mut vec)) => vec.push(item), + ThinVec(None) => *self = vec![item].into(), + } + } } impl<T> From<Vec<T>> for ThinVec<T> { @@ -101,10 +108,7 @@ impl<T> Extend<T> for ThinVec<T> { } fn extend_one(&mut self, item: T) { - match *self { - ThinVec(Some(ref mut vec)) => vec.push(item), - ThinVec(None) => *self = vec![item].into(), - } + self.push(item) } fn extend_reserve(&mut self, additional: usize) { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index ba675daac41..f216a661487 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1160,13 +1160,18 @@ macro_rules! assign_id { impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_crate(&mut self, krate: &mut ast::Crate) { - let span = krate.span; - let empty_crate = - || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None }; - let mut fold_crate = |krate: ast::Crate| { + visit_clobber(krate, |krate| { + let span = krate.span; let mut krate = match self.configure(krate) { Some(krate) => krate, - None => return empty_crate(), + None => { + return ast::Crate { + attrs: Vec::new(), + items: Vec::new(), + span, + is_placeholder: None, + }; + } }; if let Some(attr) = self.take_first_attr(&mut krate) { @@ -1177,10 +1182,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { noop_visit_crate(&mut krate, self); krate - }; - - // Cannot use `visit_clobber` here, see the FIXME on it. - *krate = fold_crate(mem::replace(krate, empty_crate())); + }) } fn visit_expr(&mut self, expr: &mut P<ast::Expr>) { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 96754cc3c8f..c17286dfbe3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1954,7 +1954,6 @@ impl<'a> State<'a> { PatKind::Range(ref begin, ref end, ref end_kind) => { if let Some(expr) = begin { self.print_expr(expr); - self.space(); } match *end_kind { RangeEnd::Included => self.word("..."), diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index b984a1321e0..89419bfce6f 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -10,3 +10,4 @@ doctest = false arrayvec = { version = "0.7", default-features = false } rustc_serialize = { path = "../rustc_serialize" } rustc_macros = { path = "../rustc_macros" } +smallvec = "1" diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs new file mode 100644 index 00000000000..6da95053b11 --- /dev/null +++ b/compiler/rustc_index/src/interval.rs @@ -0,0 +1,269 @@ +use std::iter::Step; +use std::marker::PhantomData; +use std::ops::Bound; +use std::ops::RangeBounds; + +use crate::vec::Idx; +use crate::vec::IndexVec; +use smallvec::SmallVec; + +#[cfg(test)] +mod tests; + +/// Stores a set of intervals on the indices. +#[derive(Debug, Clone)] +pub struct IntervalSet<I> { + // Start, end + map: SmallVec<[(u32, u32); 4]>, + domain: usize, + _data: PhantomData<I>, +} + +#[inline] +fn inclusive_start<T: Idx>(range: impl RangeBounds<T>) -> u32 { + match range.start_bound() { + Bound::Included(start) => start.index() as u32, + Bound::Excluded(start) => start.index() as u32 + 1, + Bound::Unbounded => 0, + } +} + +#[inline] +fn inclusive_end<T: Idx>(domain: usize, range: impl RangeBounds<T>) -> Option<u32> { + let end = match range.end_bound() { + Bound::Included(end) => end.index() as u32, + Bound::Excluded(end) => end.index().checked_sub(1)? as u32, + Bound::Unbounded => domain.checked_sub(1)? as u32, + }; + Some(end) +} + +impl<I: Idx> IntervalSet<I> { + pub fn new(domain: usize) -> IntervalSet<I> { + IntervalSet { map: SmallVec::new(), domain, _data: PhantomData } + } + + pub fn clear(&mut self) { + self.map.clear(); + } + + pub fn iter(&self) -> impl Iterator<Item = I> + '_ + where + I: Step, + { + self.iter_intervals().flatten() + } + + /// Iterates through intervals stored in the set, in order. + pub fn iter_intervals(&self) -> impl Iterator<Item = std::ops::Range<I>> + '_ + where + I: Step, + { + self.map.iter().map(|&(start, end)| I::new(start as usize)..I::new(end as usize + 1)) + } + + /// Returns true if we increased the number of elements present. + pub fn insert(&mut self, point: I) -> bool { + self.insert_range(point..=point) + } + + /// Returns true if we increased the number of elements present. + pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool { + let start = inclusive_start(range.clone()); + let Some(mut end) = inclusive_end(self.domain, range) else { + // empty range + return false; + }; + if start > end { + return false; + } + + loop { + // This condition looks a bit weird, but actually makes sense. + // + // if r.0 == end + 1, then we're actually adjacent, so we want to + // continue to the next range. We're looking here for the first + // range which starts *non-adjacently* to our end. + let next = self.map.partition_point(|r| r.0 <= end + 1); + if let Some(last) = next.checked_sub(1) { + let (prev_start, prev_end) = &mut self.map[last]; + if *prev_end + 1 >= start { + // If the start for the inserted range is adjacent to the + // end of the previous, we can extend the previous range. + if start < *prev_start { + // Our range starts before the one we found. We'll need + // to *remove* it, and then try again. + // + // FIXME: This is not so efficient; we may need to + // recurse a bunch of times here. Instead, it's probably + // better to do something like drain_filter(...) on the + // map to be able to delete or modify all the ranges in + // start..=end and then potentially re-insert a new + // range. + end = std::cmp::max(end, *prev_end); + self.map.remove(last); + } else { + // We overlap with the previous range, increase it to + // include us. + // + // Make sure we're actually going to *increase* it though -- + // it may be that end is just inside the previously existing + // set. + return if end > *prev_end { + *prev_end = end; + true + } else { + false + }; + } + } else { + // Otherwise, we don't overlap, so just insert + self.map.insert(last + 1, (start, end)); + return true; + } + } else { + if self.map.is_empty() { + // Quite common in practice, and expensive to call memcpy + // with length zero. + self.map.push((start, end)); + } else { + self.map.insert(next, (start, end)); + } + return true; + } + } + } + + pub fn contains(&self, needle: I) -> bool { + let needle = needle.index() as u32; + let last = match self.map.partition_point(|r| r.0 <= needle).checked_sub(1) { + Some(idx) => idx, + None => { + // All ranges in the map start after the new range's end + return false; + } + }; + let (_, prev_end) = &self.map[last]; + needle <= *prev_end + } + + pub fn superset(&self, other: &IntervalSet<I>) -> bool + where + I: Step, + { + // FIXME: Performance here is probably not great. We will be doing a lot + // of pointless tree traversals. + other.iter().all(|elem| self.contains(elem)) + } + + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Returns the maximum (last) element present in the set from `range`. + pub fn last_set_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> { + let start = inclusive_start(range.clone()); + let Some(end) = inclusive_end(self.domain, range) else { + // empty range + return None; + }; + if start > end { + return None; + } + let last = match self.map.partition_point(|r| r.0 <= end).checked_sub(1) { + Some(idx) => idx, + None => { + // All ranges in the map start after the new range's end + return None; + } + }; + let (_, prev_end) = &self.map[last]; + if start <= *prev_end { Some(I::new(std::cmp::min(*prev_end, end) as usize)) } else { None } + } + + pub fn insert_all(&mut self) { + self.clear(); + self.map.push((0, self.domain.try_into().unwrap())); + } + + pub fn union(&mut self, other: &IntervalSet<I>) -> bool + where + I: Step, + { + assert_eq!(self.domain, other.domain); + let mut did_insert = false; + for range in other.iter_intervals() { + did_insert |= self.insert_range(range); + } + did_insert + } +} + +/// This data structure optimizes for cases where the stored bits in each row +/// are expected to be highly contiguous (long ranges of 1s or 0s), in contrast +/// to BitMatrix and SparseBitMatrix which are optimized for +/// "random"/non-contiguous bits and cheap(er) point queries at the expense of +/// memory usage. +#[derive(Clone)] +pub struct SparseIntervalMatrix<R, C> +where + R: Idx, + C: Idx, +{ + rows: IndexVec<R, IntervalSet<C>>, + column_size: usize, +} + +impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> { + pub fn new(column_size: usize) -> SparseIntervalMatrix<R, C> { + SparseIntervalMatrix { rows: IndexVec::new(), column_size } + } + + pub fn rows(&self) -> impl Iterator<Item = R> { + self.rows.indices() + } + + pub fn row(&self, row: R) -> Option<&IntervalSet<C>> { + self.rows.get(row) + } + + fn ensure_row(&mut self, row: R) -> &mut IntervalSet<C> { + self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size)); + &mut self.rows[row] + } + + pub fn union_row(&mut self, row: R, from: &IntervalSet<C>) -> bool + where + C: Step, + { + self.ensure_row(row).union(from) + } + + pub fn union_rows(&mut self, read: R, write: R) -> bool + where + C: Step, + { + if read == write || self.rows.get(read).is_none() { + return false; + } + self.ensure_row(write); + let (read_row, write_row) = self.rows.pick2_mut(read, write); + write_row.union(read_row) + } + + pub fn insert_all_into_row(&mut self, row: R) { + self.ensure_row(row).insert_all(); + } + + pub fn insert_range(&mut self, row: R, range: impl RangeBounds<C> + Clone) { + self.ensure_row(row).insert_range(range); + } + + pub fn insert(&mut self, row: R, point: C) -> bool { + self.ensure_row(row).insert(point) + } + + pub fn contains(&self, row: R, point: C) -> bool { + self.row(row).map_or(false, |r| r.contains(point)) + } +} diff --git a/compiler/rustc_index/src/interval/tests.rs b/compiler/rustc_index/src/interval/tests.rs new file mode 100644 index 00000000000..d90b449f326 --- /dev/null +++ b/compiler/rustc_index/src/interval/tests.rs @@ -0,0 +1,199 @@ +use super::*; + +#[test] +fn insert_collapses() { + let mut set = IntervalSet::<u32>::new(3000); + set.insert_range(9831..=9837); + set.insert_range(43..=9830); + assert_eq!(set.iter_intervals().collect::<Vec<_>>(), [43..9838]); +} + +#[test] +fn contains() { + let mut set = IntervalSet::new(300); + set.insert(0u32); + assert!(set.contains(0)); + set.insert_range(0..10); + assert!(set.contains(9)); + assert!(!set.contains(10)); + set.insert_range(10..11); + assert!(set.contains(10)); +} + +#[test] +fn insert() { + for i in 0..30usize { + let mut set = IntervalSet::new(300); + for j in i..30usize { + set.insert(j); + for k in i..j { + assert!(set.contains(k)); + } + } + } + + let mut set = IntervalSet::new(300); + set.insert_range(0..1u32); + assert!(set.contains(0), "{:?}", set.map); + assert!(!set.contains(1)); + set.insert_range(1..1); + assert!(set.contains(0)); + assert!(!set.contains(1)); + + let mut set = IntervalSet::new(300); + set.insert_range(4..5u32); + set.insert_range(5..10); + assert_eq!(set.iter().collect::<Vec<_>>(), [4, 5, 6, 7, 8, 9]); + set.insert_range(3..7); + assert_eq!(set.iter().collect::<Vec<_>>(), [3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(3..5); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(0..3); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(0..10); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(5..10); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(5..13); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); +} + +#[test] +fn insert_range() { + #[track_caller] + fn check<R>(range: R) + where + R: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug, + { + let mut set = IntervalSet::new(300); + set.insert_range(range.clone()); + for i in set.iter() { + assert!(range.contains(&i)); + } + for i in range.clone() { + assert!(set.contains(i), "A: {} in {:?}, inserted {:?}", i, set, range); + } + set.insert_range(range.clone()); + for i in set.iter() { + assert!(range.contains(&i), "{} in {:?}", i, set); + } + for i in range.clone() { + assert!(set.contains(i), "B: {} in {:?}, inserted {:?}", i, set, range); + } + } + check(10..10); + check(10..100); + check(10..30); + check(0..5); + check(0..250); + check(200..250); + + check(10..=10); + check(10..=100); + check(10..=30); + check(0..=5); + check(0..=250); + check(200..=250); + + for i in 0..30 { + for j in i..30 { + check(i..j); + check(i..=j); + } + } +} + +#[test] +fn insert_range_dual() { + let mut set = IntervalSet::<u32>::new(300); + set.insert_range(0..3); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2]); + set.insert_range(5..7); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 5, 6]); + set.insert_range(3..4); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 5, 6]); + set.insert_range(3..5); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6]); +} + +#[test] +fn last_set_before_adjacent() { + let mut set = IntervalSet::<u32>::new(300); + set.insert_range(0..3); + set.insert_range(3..5); + assert_eq!(set.last_set_in(0..3), Some(2)); + assert_eq!(set.last_set_in(0..5), Some(4)); + assert_eq!(set.last_set_in(3..5), Some(4)); + set.insert_range(2..5); + assert_eq!(set.last_set_in(0..3), Some(2)); + assert_eq!(set.last_set_in(0..5), Some(4)); + assert_eq!(set.last_set_in(3..5), Some(4)); +} + +#[test] +fn last_set_in() { + fn easy(set: &IntervalSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> { + let mut last_leq = None; + for e in set.iter() { + if needle.contains(&e) { + last_leq = Some(e); + } + } + last_leq + } + + #[track_caller] + fn cmp(set: &IntervalSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) { + assert_eq!( + set.last_set_in(needle.clone()), + easy(set, needle.clone()), + "{:?} in {:?}", + needle, + set + ); + } + let mut set = IntervalSet::new(300); + cmp(&set, 50..=50); + set.insert(64); + cmp(&set, 64..=64); + set.insert(64 - 1); + cmp(&set, 0..=64 - 1); + cmp(&set, 0..=5); + cmp(&set, 10..100); + set.insert(100); + cmp(&set, 100..110); + cmp(&set, 99..100); + cmp(&set, 99..=100); + + for i in 0..=30 { + for j in i..=30 { + for k in 0..30 { + let mut set = IntervalSet::new(100); + cmp(&set, ..j); + cmp(&set, i..); + cmp(&set, i..j); + cmp(&set, i..=j); + set.insert(k); + cmp(&set, ..j); + cmp(&set, i..); + cmp(&set, i..j); + cmp(&set, i..=j); + } + } + } +} diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index a9efd6bb8bc..359b1859c68 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -7,6 +7,7 @@ #![feature(let_else)] pub mod bit_set; +pub mod interval; pub mod vec; // FIXME(#56935): Work around ICEs during cross-compilation. diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 5e48fbf253d..da71edbd2d9 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -572,8 +572,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // (e.g., #41849). relate::relate_substs(self, None, a_subst, b_subst) } else { - let opt_variances = self.tcx().variances_of(item_def_id); - relate::relate_substs(self, Some(&opt_variances), a_subst, b_subst) + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst) } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 2904b3f5b70..3804e100307 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -11,7 +11,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ErrorReported, Handler}; use rustc_lint::LintStore; use rustc_middle::ty; -use rustc_parse::new_parser_from_source_str; +use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; @@ -91,7 +91,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String s ))); let filename = FileName::cfg_spec_source_code(&s); - let mut parser = new_parser_from_source_str(&sess, filename, s.to_string()); macro_rules! error { ($reason: expr) => { @@ -102,26 +101,27 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String }; } - match &mut parser.parse_meta_item() { - Ok(meta_item) if parser.token == token::Eof => { - if meta_item.path.segments.len() != 1 { - error!("argument key must be an identifier"); - } - match &meta_item.kind { - MetaItemKind::List(..) => { - error!(r#"expected `key` or `key="value"`"#); - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - error!("argument value must be a string"); + match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { + Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(meta_item) if parser.token == token::Eof => { + if meta_item.path.segments.len() != 1 { + error!("argument key must be an identifier"); } - MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = meta_item.ident().expect("multi-segment cfg key"); - return (ident.name, meta_item.value_str()); + match &meta_item.kind { + MetaItemKind::List(..) => {} + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { + error!("argument value must be a string"); + } + MetaItemKind::NameValue(..) | MetaItemKind::Word => { + let ident = meta_item.ident().expect("multi-segment cfg key"); + return (ident.name, meta_item.value_str()); + } } } - } - Ok(..) => {} - Err(err) => err.cancel(), + Ok(..) => {} + Err(err) => err.cancel(), + }, + Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), } error!(r#"expected `key` or `key="value"`"#); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c651feaaa66..816e770f012 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,10 +8,11 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate use rustc_session::config::{ rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes, }; -use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; use rustc_session::config::{ - Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel, + BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion, + WasiExecModel, }; +use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; @@ -593,6 +594,7 @@ fn test_codegen_options_tracking_hash() { tracked!(relocation_model, Some(RelocModel::Pic)); tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); + tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); } @@ -717,6 +719,10 @@ fn test_debugging_options_tracking_hash() { tracked!(asm_comments, true); tracked!(assume_incomplete_release, true); tracked!(binary_dep_depinfo, true); + tracked!( + branch_protection, + BranchProtection { bti: true, pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B }) } + ); tracked!(chalk, true); tracked!(codegen_backend, Some("abc".to_string())); tracked!(crate_attr, vec!["abc".to_string()]); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index b04f91634cc..cb51555f5ca 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -484,7 +484,7 @@ pub(crate) fn check_attr_crate_type( return; } - if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind { + if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() { let span = spanned.span; let lev_candidate = find_best_match_for_name( &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(), diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 4f77db8a24d..f06fc3edf58 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -17,6 +17,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" @@ -753,7 +754,8 @@ LLVMRustOptimizeWithNewPassManager( void* LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileAfterPassCallback AfterPassCallback, - const char *ExtraPasses, size_t ExtraPassesLen) { + const char *ExtraPasses, size_t ExtraPassesLen, + const char *LLVMPlugins, size_t LLVMPluginsLen) { Module *TheModule = unwrap(ModuleRef); TargetMachine *TM = unwrap(TMRef); OptimizationLevel OptLevel = fromRust(OptLevelRust); @@ -924,6 +926,20 @@ LLVMRustOptimizeWithNewPassManager( } } + if (LLVMPluginsLen) { + auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen); + SmallVector<StringRef> Plugins; + PluginsStr.split(Plugins, ',', -1, false); + for (auto PluginPath: Plugins) { + auto Plugin = PassPlugin::Load(PluginPath.str()); + if (!Plugin) { + LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str()); + continue; + } + Plugin->registerPassBuilderCallbacks(PB); + } + } + #if LLVM_VERSION_GE(13, 0) ModulePassManager MPM; #else diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 3fbf020c552..025a0ee376e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -716,6 +716,14 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } +extern "C" bool LLVMRustIsRustLLVM() { +#ifdef LLVM_RUSTLLVM + return true; +#else + return false; +#endif +} + extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name, uint32_t Value) { unwrap(M)->addModuleFlag(Module::Warning, Name, Value); diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 66e6b571beb..3351564299c 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -1,6 +1,7 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, quote_spanned}; use syn::parse_quote; +use syn::spanned::Spanned; pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; @@ -104,6 +105,8 @@ fn decodable_body( } fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream { + let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span()); + let decode_inner_method = if let syn::Type::Reference(_) = field.ty { quote! { ::rustc_middle::ty::codec::RefDecodable::decode } } else { @@ -111,20 +114,21 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro }; let (decode_method, opt_field_name) = if is_struct { let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string()); - ( - proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()), - quote! { #field_name, }, - ) + (proc_macro2::Ident::new("read_struct_field", field_span), quote! { #field_name, }) } else { - ( - proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()), - quote! {}, - ) + (proc_macro2::Ident::new("read_enum_variant_arg", field_span), quote! {}) + }; + + let __decoder = quote! { __decoder }; + // Use the span of the field for the method call, so + // that backtraces will point to the field. + let decode_call = quote_spanned! {field_span=> + ::rustc_serialize::Decoder::#decode_method( + #__decoder, #opt_field_name #decode_inner_method) }; quote! { - match ::rustc_serialize::Decoder::#decode_method( - __decoder, #opt_field_name #decode_inner_method) { + match #decode_call { ::std::result::Result::Ok(__res) => __res, ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index caf29df2276..8ff3b1e72d8 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -45,7 +45,8 @@ use std::num::NonZeroUsize; use std::path::Path; use tracing::debug; -pub use cstore_impl::{provide, provide_extern}; +pub(super) use cstore_impl::provide; +pub use cstore_impl::provide_extern; use rustc_span::hygiene::HygieneDecodeContext; mod cstore_impl; @@ -1099,10 +1100,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; // Iterate over all children. - let macros_only = self.dep_kind.lock().macros_only(); - if !macros_only { - let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty); - + if let Some(children) = self.root.tables.children.get(self, id) { for child_index in children.decode((self, sess)) { // FIXME: Merge with the logic below. if let None | Some(EntryKind::ForeignMod | EntryKind::Impl(_)) = @@ -1171,11 +1169,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { if let EntryKind::Mod(exports) = kind { for exp in exports.decode((self, sess)) { - match exp.res { - Res::Def(DefKind::Macro(..), _) => {} - _ if macros_only => continue, - _ => {} - } callback(exp); } } @@ -1375,6 +1368,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } + fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a { + self.root.traits.decode(self).map(|index| self.local_def_id(index)) + } + fn get_implementations_for_trait( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 06b72d537c2..7ffc586fda3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -195,6 +195,8 @@ provide! { <'tcx> tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } + traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + implementations_of_trait => { cdata.get_implementations_for_trait(tcx, Some(other)) } @@ -239,7 +241,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) } } -pub fn provide(providers: &mut Providers) { +pub(in crate::rmeta) fn provide(providers: &mut Providers) { // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about @@ -528,4 +530,8 @@ impl CrateStore for CStore { ) -> ExpnId { self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash) } + + fn import_source_files(&self, sess: &Session, cnum: CrateNum) { + self.get_crate_data(cnum).imported_source_files(sess); + } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 531ed4c3d6d..3942846e79d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -27,6 +27,7 @@ use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; @@ -612,10 +613,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_def_path_table(); let def_path_table_bytes = self.position() - i; + // Encode the def IDs of traits, for rustdoc and diagnostics. + i = self.position(); + let traits = self.encode_traits(); + let traits_bytes = self.position() - i; + // Encode the def IDs of impls, for coherence checking. i = self.position(); let impls = self.encode_impls(); - let impl_bytes = self.position() - i; + let impls_bytes = self.position() - i; let tcx = self.tcx; @@ -715,7 +721,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), - symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(), + symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(), crate_deps, dylib_dependency_formats, @@ -726,6 +732,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { native_libraries, foreign_modules, source_map, + traits, impls, exported_symbols, interpret_alloc_index, @@ -753,7 +760,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes); eprintln!(" native bytes: {}", native_lib_bytes); eprintln!(" source_map bytes: {}", source_map_bytes); - eprintln!(" impl bytes: {}", impl_bytes); + eprintln!(" traits bytes: {}", traits_bytes); + eprintln!(" impls bytes: {}", impls_bytes); eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes); eprintln!(" def-path table bytes: {}", def_path_table_bytes); eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes); @@ -1790,12 +1798,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(&tcx.lang_items().missing) } + fn encode_traits(&mut self) -> Lazy<[DefIndex]> { + empty_proc_macro!(self); + self.lazy(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index)) + } + /// Encodes an index, mapping each trait to its (local) implementations. fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { + debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); - debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; - let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; + let mut visitor = ImplsVisitor { tcx, impls: FxHashMap::default() }; tcx.hir().visit_all_item_likes(&mut visitor); let mut all_impls: Vec<_> = visitor.impls.into_iter().collect(); @@ -2040,27 +2053,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } -struct ImplVisitor<'tcx> { +struct ImplsVisitor<'tcx> { tcx: TyCtxt<'tcx>, impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>, } -impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> { +impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { - if let hir::ItemKind::Impl { .. } = item.kind { - if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) { - let simplified_self_ty = fast_reject::simplify_type( - self.tcx, - trait_ref.self_ty(), - SimplifyParams::No, - StripReferences::No, - ); + match item.kind { + hir::ItemKind::Impl(..) => { + if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) { + let simplified_self_ty = fast_reject::simplify_type( + self.tcx, + trait_ref.self_ty(), + SimplifyParams::No, + StripReferences::No, + ); - self.impls - .entry(trait_ref.def_id) - .or_default() - .push((item.def_id.local_def_index, simplified_self_ty)); + self.impls + .entry(trait_ref.def_id) + .or_default() + .push((item.def_id.local_def_index, simplified_self_ty)); + } } + _ => {} } } @@ -2209,3 +2225,34 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { EncodedMetadata { raw_data: result } } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + traits_in_crate: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + + #[derive(Default)] + struct TraitsVisitor { + traits: Vec<DefId>, + } + impl ItemLikeVisitor<'_> for TraitsVisitor { + fn visit_item(&mut self, item: &hir::Item<'_>) { + if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind { + self.traits.push(item.def_id.to_def_id()); + } + } + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} + } + + let mut visitor = TraitsVisitor::default(); + tcx.hir().visit_all_item_likes(&mut visitor); + // Bring everything into deterministic order. + visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); + tcx.arena.alloc_slice(&visitor.traits) + }, + + ..*providers + }; +} diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5ce239ac704..35016453369 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; use rustc_middle::thir; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; @@ -29,8 +30,8 @@ use rustc_target::spec::{PanicStrategy, TargetTriple}; use std::marker::PhantomData; use std::num::NonZeroUsize; +pub use decoder::provide_extern; use decoder::DecodeContext; -pub use decoder::{provide, provide_extern}; crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use encoder::EncodeContext; pub use encoder::{encode_metadata, EncodedMetadata}; @@ -222,6 +223,7 @@ crate struct CrateRoot<'tcx> { diagnostic_items: Lazy<[(Symbol, DefIndex)]>, native_libraries: Lazy<[NativeLib]>, foreign_modules: Lazy<[ForeignModule]>, + traits: Lazy<[DefIndex]>, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, proc_macro_data: Option<ProcMacroData>, @@ -453,3 +455,8 @@ struct GeneratorData<'tcx> { const TAG_VALID_SPAN_LOCAL: u8 = 0; const TAG_VALID_SPAN_FOREIGN: u8 = 1; const TAG_PARTIAL_SPAN: u8 = 2; + +pub fn provide(providers: &mut Providers) { + encoder::provide(providers); + decoder::provide(providers); +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c7c306e7d06..52ef380001c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2336,8 +2336,6 @@ pub enum NullOp { SizeOf, /// Returns the minimum alignment of a type AlignOf, - /// Creates a new uninitialized box for a value of that type - Box, } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index e577df48205..dc53dc8de9d 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -195,7 +195,6 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), @@ -215,9 +214,7 @@ impl<'tcx> Rvalue<'tcx> { /// whether its only shallowly initialized (`Rvalue::Box`). pub fn initialization_state(&self) -> RvalueInitializationState { match *self { - Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => { - RvalueInitializationState::Shallow - } + Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, _ => RvalueInitializationState::Deep, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ad3f61d0784..027c0c64924 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1609,11 +1609,11 @@ rustc_queries! { desc { "fetching all foreign CrateNum instances" } } - /// A vector of every trait accessible in the whole crate - /// (i.e., including those from subcrates). This is used only for - /// error reporting. - query all_traits(_: ()) -> &'tcx [DefId] { - desc { "fetching all foreign and local traits" } + /// A list of all traits in a crate, used by rustdoc and error reporting. + /// NOTE: Not named just `traits` due to a naming conflict. + query traits_in_crate(_: CrateNum) -> &'tcx [DefId] { + desc { "fetching all traits in a crate" } + separate_provide_extern } /// The list of symbols exported from the given crate. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index caa7008f108..dd571e29bf6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1577,6 +1577,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn const_eval_limit(self) -> Limit { self.limits(()).const_eval_limit } + + pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { + iter::once(LOCAL_CRATE) + .chain(self.crates(()).iter().copied()) + .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) + } } /// A trait implemented for all `X<'a>` types that can be safely and diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 37d99766da9..78ccfbd5e8c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -77,7 +77,7 @@ pub use self::sty::{ GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, - UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, + UpvarSubsts, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 905a5c47d2b..63ed318cadb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -6,7 +6,7 @@ use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; +use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; @@ -59,8 +59,9 @@ pub trait TypeRelation<'tcx>: Sized { item_def_id, a_subst, b_subst ); - let opt_variances = self.tcx().variances_of(item_def_id); - relate_substs(self, Some(opt_variances), a_subst, b_subst) + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst) } /// Switch variance for the purpose of relating `a` and `b`. @@ -116,7 +117,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a: ty::TypeAndMut<'tcx>, b: ty::TypeAndMut<'tcx>, - kind: ty::VarianceDiagMutKind, + base_ty: Ty<'tcx>, ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> { debug!("{}.mts({:?}, {:?})", relation.tag(), a, b); if a.mutbl != b.mutbl { @@ -125,7 +126,9 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( let mutbl = a.mutbl; let (variance, info) = match mutbl { ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }), + ast::Mutability::Mut => { + (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 }) + } }; let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?; Ok(ty::TypeAndMut { ty, mutbl }) @@ -134,15 +137,29 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, - variances: Option<&[ty::Variance]>, + variances: Option<(DefId, &[ty::Variance])>, a_subst: SubstsRef<'tcx>, b_subst: SubstsRef<'tcx>, ) -> RelateResult<'tcx, SubstsRef<'tcx>> { let tcx = relation.tcx(); + let mut cached_ty = None; let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| { - let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b) + let (variance, variance_info) = match variances { + Some((ty_def_id, variances)) => { + let variance = variances[i]; + let variance_info = if variance == ty::Invariant { + let ty = + cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst)); + ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } + } else { + ty::VarianceDiagInfo::default() + }; + (variance, variance_info) + } + None => (ty::Invariant, ty::VarianceDiagInfo::default()), + }; + relation.relate_with_variance(variance, variance_info, a, b) }); tcx.mk_substs(params) @@ -436,7 +453,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( } (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { - let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?; + let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; Ok(tcx.mk_ptr(mt)) } @@ -449,7 +466,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( )?; let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; - let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?; + let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; Ok(tcx.mk_ref(r, mt)) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8706661b250..c24a1d8eb52 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2282,36 +2282,26 @@ pub enum VarianceDiagInfo<'tcx> { /// We will not add any additional information to error messages. #[default] None, - /// We switched our variance because a type occurs inside - /// the generic argument of a mutable reference or pointer - /// (`*mut T` or `&mut T`). In either case, our variance - /// will always be `Invariant`. - Mut { - /// Tracks whether we had a mutable pointer or reference, - /// for better error messages - kind: VarianceDiagMutKind, - /// The type parameter of the mutable pointer/reference - /// (the `T` in `&mut T` or `*mut T`). + /// We switched our variance because a generic argument occurs inside + /// the invariant generic argument of another type. + Invariant { + /// The generic type containing the generic parameter + /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`) ty: Ty<'tcx>, + /// The index of the generic parameter being used + /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) + param_index: u32, }, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum VarianceDiagMutKind { - /// A mutable raw pointer (`*mut T`) - RawPtr, - /// A mutable reference (`&mut T`) - Ref, -} - impl<'tcx> VarianceDiagInfo<'tcx> { /// Mirrors `Variance::xform` - used to 'combine' the existing /// and new `VarianceDiagInfo`s when our variance changes. pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> { - // For now, just use the first `VarianceDiagInfo::Mut` that we see + // For now, just use the first `VarianceDiagInfo::Invariant` that we see match self { VarianceDiagInfo::None => other, - VarianceDiagInfo::Mut { .. } => self, + VarianceDiagInfo::Invariant { .. } => self, } } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index feb85d4ffdf..2e00b4f9a5e 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -343,19 +343,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) | Rvalue::Len(..) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) - | Rvalue::NullaryOp(NullOp::Box, _) => { - // This returns an rvalue with uninitialized contents. We can't - // move out of it here because it is an rvalue - assignments always - // completely initialize their place. - // - // However, this does not matter - MIR building is careful to - // only emit a shallow free for the partially-initialized - // temporary. - // - // In any case, if we want to fix this, we have to register a - // special move and change the `statement_effect` functions. - } + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 7e56e062fc9..ecc8e7a6f1a 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -239,13 +239,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("can't const prop heap allocations") - } - fn access_local( _ecx: &InterpCx<'mir, 'tcx, Self>, frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b1fa9041342..b70c24b76d5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -688,15 +688,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => bug!(), } } - mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.tcx; - let exchange_malloc_fn_def_id = - tcx.require_lang_item(LangItem::ExchangeMalloc, None); - let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 55ae808dc30..40d12c4a22d 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,7 +4,7 @@ // and `#[unstable (..)]`), but are not declared in one single location // (unlike lang features), which means we need to collect them instead. -use rustc_ast::{Attribute, MetaItem, MetaItemKind}; +use rustc_ast::{Attribute, MetaItemKind}; use rustc_errors::struct_span_err; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_middle::hir::map::Map; @@ -34,8 +34,8 @@ impl<'tcx> LibFeatureCollector<'tcx> { // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`, // `#[rustc_const_unstable (..)]`). if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { - let meta_item = attr.meta(); - if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item { + let meta_kind = attr.meta_kind(); + if let Some(MetaItemKind::List(ref metas)) = meta_kind { let mut feature = None; let mut since = None; for meta in metas { diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 11f54ea66fa..6a88e123537 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -495,6 +495,20 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { .entry(index) .or_insert_with(|| { let stable_id = file_index_to_stable_id[&index].translate(tcx); + + // If this `SourceFile` is from a foreign crate, then make sure + // that we've imported all of the source files from that crate. + // This has usually already been done during macro invocation. + // However, when encoding query results like `TypeckResults`, + // we might encode an `AdtDef` for a foreign type (because it + // was referenced in the body of the function). There is no guarantee + // that we will load the source files from that crate during macro + // expansion, so we use `import_source_files` to ensure that the foreign + // source files are actually imported before we call `source_file_by_stable_id`. + if stable_id.cnum != LOCAL_CRATE { + self.tcx.cstore_untracked().import_source_files(self.tcx.sess, stable_id.cnum); + } + source_map .source_file_by_stable_id(stable_id) .expect("failed to lookup `SourceFile` in new context") diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5098cef11e8..57305023138 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2379,7 +2379,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::While(ref cond, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { this.with_rib(ValueNS, NormalRibKind, |this| { + let old = this.diagnostic_metadata.in_if_condition.replace(cond); this.visit_expr(cond); + this.diagnostic_metadata.in_if_condition = old; this.visit_block(block); }) }); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index de5ff231d61..f2c7959ddb6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -781,6 +781,10 @@ impl Options { }, } } + + pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { + self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) + } } impl DebuggingOptions { @@ -794,10 +798,6 @@ impl DebuggingOptions { deduplicate_diagnostics: self.deduplicate_diagnostics, } } - - pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { - self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) - } } // The type of entry function, so users can have their own entry functions @@ -843,6 +843,30 @@ impl Passes { } } +#[derive(Clone, Copy, Hash, Debug, PartialEq)] +pub enum PAuthKey { + A, + B, +} + +#[derive(Clone, Copy, Hash, Debug, PartialEq)] +pub struct PacRet { + pub leaf: bool, + pub key: PAuthKey, +} + +#[derive(Clone, Copy, Hash, Debug, PartialEq)] +pub struct BranchProtection { + pub bti: bool, + pub pac_ret: Option<PacRet>, +} + +impl Default for BranchProtection { + fn default() -> Self { + BranchProtection { bti: false, pac_ret: None } + } +} + pub const fn default_lib_output() -> CrateType { CrateType::Rlib } @@ -2092,6 +2116,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } + // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes + // precedence. + match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) { + (Some(smv_c), Some(smv_z)) if smv_c != smv_z => { + early_error( + error_format, + "incompatible values passed for `-C symbol-mangling-version` \ + and `-Z symbol-mangling-version`", + ); + } + (Some(SymbolManglingVersion::V0), _) => {} + (Some(_), _) if !debugging_opts.unstable_options => { + early_error( + error_format, + "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", + ); + } + (None, None) => {} + (None, smv) => { + early_warn( + error_format, + "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`", + ); + cg.symbol_mangling_version = smv; + } + _ => {} + } + if debugging_opts.instrument_coverage.is_some() && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off) { @@ -2103,19 +2155,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent + // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over // multiple runs, including some changes to source code; so mangled names must be consistent // across compilations. - match debugging_opts.symbol_mangling_version { - None => { - debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0); - } + match cg.symbol_mangling_version { + None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0), Some(SymbolManglingVersion::Legacy) => { early_warn( error_format, "-Z instrument-coverage requires symbol mangling version `v0`, \ - but `-Z symbol-mangling-version=legacy` was specified", + but `-C symbol-mangling-version=legacy` was specified", ); } Some(SymbolManglingVersion::V0) => {} @@ -2497,9 +2547,9 @@ impl PpMode { crate mod dep_tracking { use super::LdImpl; use super::{ - CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto, - LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, - SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, + BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, + LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, + SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -2593,6 +2643,7 @@ crate mod dep_tracking { OutputType, RealFileName, LocationDetail, + BranchProtection, ); impl<T1, T2> DepTrackingHash for (T1, T2) diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 59e7abc2ea3..281fc887633 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -201,6 +201,12 @@ pub trait CrateStore: std::fmt::Debug { index_guess: u32, hash: ExpnHash, ) -> ExpnId; + + /// Imports all `SourceFile`s from the given crate into the current session. + /// This normally happens automatically when we decode a `Span` from + /// that crate's metadata - however, the incr comp cache needs + /// to trigger this manually when decoding a foreign `Span` + fn import_source_files(&self, sess: &Session, cnum: CrateNum); } pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9090524c933..c8adc9f00a1 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -415,6 +415,8 @@ mod desc { pub const parse_gcc_ld: &str = "one of: no value, `lld`"; pub const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; + pub const parse_branch_protection: &str = + "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`"; } mod parse { @@ -955,6 +957,32 @@ mod parse { } true } + + crate fn parse_branch_protection(slot: &mut BranchProtection, v: Option<&str>) -> bool { + match v { + Some(s) => { + for opt in s.split(',') { + match opt { + "bti" => slot.bti = true, + "pac-ret" if slot.pac_ret.is_none() => { + slot.pac_ret = Some(PacRet { leaf: false, key: PAuthKey::A }) + } + "leaf" => match slot.pac_ret.as_mut() { + Some(pac) => pac.leaf = true, + _ => return false, + }, + "b-key" => match slot.pac_ret.as_mut() { + Some(pac) => pac.key = PAuthKey::B, + _ => return false, + }, + _ => return false, + }; + } + } + _ => return false, + } + true + } } options! { @@ -1055,6 +1083,9 @@ options! { "how to handle split-debuginfo, a platform-specific option"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), + symbol_mangling_version: Option<SymbolManglingVersion> = (None, + parse_symbol_mangling_version, [TRACKED], + "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), target_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], @@ -1096,6 +1127,8 @@ options! { (default: no)"), borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED], "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"), + branch_protection: BranchProtection = (BranchProtection::default(), parse_branch_protection, [TRACKED], + "set options for branch target identification and pointer authentication on AArch64"), cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED], "the codegen unit partitioning strategy to use"), chalk: bool = (false, parse_bool, [TRACKED], @@ -1197,7 +1230,7 @@ options! { instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ - implies `-Z symbol-mangling-version=v0`. Optional values are: + implies `-C symbol-mangling-version=v0`. Optional values are: `=all` (implicit value) `=except-unused-generics` `=except-unused-functions` diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 65b5852bc39..1f38240ee41 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -237,7 +237,7 @@ fn compute_symbol_name<'tcx>( // Pick the crate responsible for the symbol mangling version, which has to: // 1. be stable for each instance, whether it's being defined or imported - // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible + // 2. obey each crate's own `-C symbol-mangling-version`, as much as possible // We solve these as follows: // 1. because symbol names depend on both `def_id` and `instantiating_crate`, // both their `CrateNum`s are stable for any given instance, so we can pick @@ -245,7 +245,7 @@ fn compute_symbol_name<'tcx>( // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess.opts.debugging_opts.get_symbol_mangling_version() + tcx.sess.opts.get_symbol_mangling_version() } else { tcx.symbol_mangling_version(mangling_version_crate) }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index b5c5724f56e..a9ae0ec53c7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1567,14 +1567,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some) }; let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); - let all_traits = self.tcx.all_traits(()); - let traits_with_same_path: std::collections::BTreeSet<_> = all_traits - .iter() - .filter(|trait_def_id| **trait_def_id != trait_ref.def_id()) - .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path) + let traits_with_same_path: std::collections::BTreeSet<_> = self + .tcx + .all_traits() + .filter(|trait_def_id| *trait_def_id != trait_ref.def_id()) + .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path) .collect(); for trait_with_same_path in traits_with_same_path { - if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) { + if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) { let impl_span = self.tcx.def_span(impl_def_id); err.span_help(impl_span, "trait impl with same name found"); let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 1b79e537634..c38680651af 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -724,7 +724,7 @@ impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase< /// var bound at index `0`. For types, we use a `BoundVar` index equal to /// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed` /// variant (which has a `DefId`). -fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { +fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind { ty::GenericParamDefKind::Type { .. } => tcx .mk_ty(ty::Bound( diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 92f2760e62c..90c698db8fb 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -138,7 +138,7 @@ fn compute_implied_outlives_bounds<'tcx>( /// this down to determine what relationships would have to hold for /// `T: 'a` to hold. We get to assume that the caller has validated /// those relationships. -fn implied_bounds_from_components( +fn implied_bounds_from_components<'tcx>( sub_region: ty::Region<'tcx>, sup_components: SmallVec<[Component<'tcx>; 4]>, ) -> Vec<OutlivesBound<'tcx>> { diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 8612499623b..b814b984dae 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -2,7 +2,6 @@ //! the guts are broken up into modules; see the comments in those modules. #![feature(crate_visibility_modifier)] -#![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 87530cf9961..46c2f7e4cf2 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -57,7 +57,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + }) } -fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { +fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool { match p.kind().skip_binder() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, ty::PredicateKind::Trait(..) diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index cc0b7d5817b..6fcac9fcdc6 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -70,7 +70,7 @@ struct AscribeUserTypeCx<'me, 'tcx> { fulfill_cx: &'me mut dyn TraitEngine<'tcx>, } -impl AscribeUserTypeCx<'me, 'tcx> { +impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { fn normalize<T>(&mut self, value: T) -> T where T: TypeFoldable<'tcx>, @@ -195,7 +195,7 @@ fn type_op_eq<'tcx>( }) } -fn type_op_normalize<T>( +fn type_op_normalize<'tcx, T>( infcx: &InferCtxt<'_, 'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, @@ -210,28 +210,28 @@ where Ok(value) } -fn type_op_normalize_ty( +fn type_op_normalize_ty<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Ty<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize) } -fn type_op_normalize_predicate( +fn type_op_normalize_predicate<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Predicate<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Predicate<'tcx>>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize) } -fn type_op_normalize_fn_sig( +fn type_op_normalize_fn_sig<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<FnSig<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, FnSig<'tcx>>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize) } -fn type_op_normalize_poly_fn_sig( +fn type_op_normalize_poly_fn_sig<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<PolyFnSig<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, PolyFnSig<'tcx>>>, NoSolution> { diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 03518dc8d12..f7f4c52c2a1 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -7,7 +7,7 @@ mod prelude2021; pub mod probe; mod suggest; -pub use self::suggest::{SelfSource, TraitInfo}; +pub use self::suggest::SelfSource; pub use self::CandidateSource::*; pub use self::MethodError::*; @@ -31,7 +31,6 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use self::probe::{IsSuggestion, ProbeScope}; pub fn provide(providers: &mut ty::query::Providers) { - suggest::provide(providers); probe::provide(providers); } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index f3a5fbbb444..7f9c75c7fee 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -5,8 +5,8 @@ use crate::check::FnCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Namespace, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; +use rustc_hir::def::Namespace; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -1922,76 +1922,10 @@ impl Ord for TraitInfo { } } -/// Retrieves all traits in this crate and any dependent crates. +/// Retrieves all traits in this crate and any dependent crates, +/// and wraps them into `TraitInfo` for custom sorting. pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> { - tcx.all_traits(()).iter().map(|&def_id| TraitInfo { def_id }).collect() -} - -/// Computes all traits in this crate and any dependent crates. -fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] { - use hir::itemlikevisit; - - let mut traits = vec![]; - - // Crate-local: - - struct Visitor<'a> { - traits: &'a mut Vec<DefId>, - } - - impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> { - fn visit_item(&mut self, i: &'v hir::Item<'v>) { - match i.kind { - hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => { - self.traits.push(i.def_id.to_def_id()); - } - _ => (), - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} - - fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} - } - - tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits }); - - // Cross-crate: - - let mut external_mods = FxHashSet::default(); - fn handle_external_res( - tcx: TyCtxt<'_>, - traits: &mut Vec<DefId>, - external_mods: &mut FxHashSet<DefId>, - res: Res<!>, - ) { - match res { - Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => { - traits.push(def_id); - } - Res::Def(DefKind::Mod, def_id) => { - if !external_mods.insert(def_id) { - return; - } - for child in tcx.item_children(def_id).iter() { - handle_external_res(tcx, traits, external_mods, child.res) - } - } - _ => {} - } - } - for &cnum in tcx.crates(()).iter() { - let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; - handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id)); - } - - tcx.arena.alloc_from_iter(traits) -} - -pub fn provide(providers: &mut ty::query::Providers) { - providers.all_traits = compute_all_traits; + tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect() } fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option<Span>, bool) { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e7b728d491b..2fb5590016e 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2894,7 +2894,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } } else if attr.has_name(sym::instruction_set) { - codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) { + codegen_fn_attrs.instruction_set = match attr.meta_kind() { Some(MetaItemKind::List(ref items)) => match items.as_slice() { [NestedMetaItem::MetaItem(set)] => { let segments = @@ -2999,7 +2999,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { if !attr.has_name(sym::inline) { return ia; } - match attr.meta().map(|i| i.kind) { + match attr.meta_kind() { Some(MetaItemKind::Word) => InlineAttr::Hint, Some(MetaItemKind::List(ref items)) => { inline_span = Some(attr.span); @@ -3038,7 +3038,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { return ia; } let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit(); - match attr.meta().map(|i| i.kind) { + match attr.meta_kind() { Some(MetaItemKind::Word) => { err(attr.span, "expected one argument"); ia diff --git a/config.toml.example b/config.toml.example index 4dd953a495d..f24f8e81a79 100644 --- a/config.toml.example +++ b/config.toml.example @@ -488,9 +488,12 @@ changelog-seen = 2 # FIXME(#75760): Some UI tests fail when this option is enabled. #parallel-compiler = false -# The default linker that will be hard-coded into the generated compiler for -# targets that don't specify linker explicitly in their target specifications. -# Note that this is not the linker used to link said compiler. +# The default linker that will be hard-coded into the generated +# compiler for targets that don't specify a default linker explicitly +# in their target specifications. Note that this is not the linker +# used to link said compiler. It can also be set per-target (via the +# `[target.<triple>]` block), which may be useful in a cross-compilation +# setting. # # See https://doc.rust-lang.org/rustc/codegen-options/index.html#linker for more information. #default-linker = <none> (path) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2863da05932..6fdaa8b950a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -148,7 +148,7 @@ use self::spec_extend::SpecExtend; #[cfg(not(no_global_oom_handling))] mod spec_extend; -/// A contiguous growable array type, written as `Vec<T>` and pronounced 'vector'. +/// A contiguous growable array type, written as `Vec<T>`, short for 'vector'. /// /// # Examples /// @@ -2141,12 +2141,17 @@ impl<T, A: Allocator> Vec<T, A> { unsafe fn split_at_spare_mut_with_len( &mut self, ) -> (&mut [T], &mut [MaybeUninit<T>], &mut usize) { - let Range { start: ptr, end: spare_ptr } = self.as_mut_ptr_range(); + let ptr = self.as_mut_ptr(); + // SAFETY: + // - `ptr` is guaranteed to be valid for `self.len` elements + // - but the allocation extends out to `self.buf.capacity()` elements, possibly + // uninitialized + let spare_ptr = unsafe { ptr.add(self.len) }; let spare_ptr = spare_ptr.cast::<MaybeUninit<T>>(); let spare_len = self.buf.capacity() - self.len; // SAFETY: - // - `ptr` is guaranteed to be valid for `len` elements + // - `ptr` is guaranteed to be valid for `self.len` elements // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized` unsafe { let initialized = slice::from_raw_parts_mut(ptr, self.len); diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs index 2b8a5f3cbf3..788f0cce01b 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -102,8 +102,7 @@ impl<T> OnceCell<T> { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get_mut(&mut self) -> Option<&mut T> { - // SAFETY: Safe because we have unique access - unsafe { &mut *self.inner.get() }.as_mut() + self.inner.get_mut().as_mut() } /// Sets the contents of the cell to `value`. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 49dce89a494..0599f274013 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -585,6 +585,7 @@ impl<T> [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] #[inline] + #[track_caller] pub const fn swap(&mut self, a: usize, b: usize) { let _ = &self[a]; let _ = &self[b]; @@ -1501,6 +1502,7 @@ impl<T> [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[track_caller] pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which @@ -1531,6 +1533,7 @@ impl<T> [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[track_caller] pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which @@ -1670,6 +1673,7 @@ impl<T> [T] { /// ``` #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] + #[track_caller] pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) { let (a, b) = self.split_at(N); // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) @@ -1701,6 +1705,7 @@ impl<T> [T] { /// ``` #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] + #[track_caller] pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) { let (a, b) = self.split_at_mut(N); // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 5ef23871e8b..c64377dfbc8 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -349,6 +349,33 @@ impl<K, V, S> HashMap<K, V, S> { Keys { inner: self.iter() } } + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + #[inline] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] + pub fn into_keys(self) -> IntoKeys<K, V> { + IntoKeys { inner: self.into_iter() } + } + /// An iterator visiting all values in arbitrary order. /// The iterator element type is `&'a V`. /// @@ -399,6 +426,33 @@ impl<K, V, S> HashMap<K, V, S> { ValuesMut { inner: self.iter_mut() } } + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec<i32> = map.into_values().collect(); + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] + pub fn into_values(self) -> IntoValues<K, V> { + IntoValues { inner: self.into_iter() } + } + /// An iterator visiting all key-value pairs in arbitrary order. /// The iterator element type is `(&'a K, &'a V)`. /// @@ -555,6 +609,29 @@ impl<K, V, S> HashMap<K, V, S> { DrainFilter { base: self.base.drain_filter(pred) } } + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect(); + /// map.retain(|&k, _| k % 2 == 0); + /// assert_eq!(map.len(), 4); + /// ``` + #[inline] + #[stable(feature = "retain_hash_collection", since = "1.18.0")] + pub fn retain<F>(&mut self, f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.base.retain(f) + } + /// Clears the map, removing all key-value pairs. Keeps the allocated memory /// for reuse. /// @@ -937,83 +1014,6 @@ where { self.base.remove_entry(k) } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. - /// The elements are visited in unsorted (and unspecified) order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect(); - /// map.retain(|&k, _| k % 2 == 0); - /// assert_eq!(map.len(), 4); - /// ``` - #[inline] - #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain<F>(&mut self, f: F) - where - F: FnMut(&K, &mut V) -> bool, - { - self.base.retain(f) - } - - /// Creates a consuming iterator visiting all the keys in arbitrary order. - /// The map cannot be used after calling this. - /// The iterator element type is `K`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let map = HashMap::from([ - /// ("a", 1), - /// ("b", 2), - /// ("c", 3), - /// ]); - /// - /// let mut vec: Vec<&str> = map.into_keys().collect(); - /// // The `IntoKeys` iterator produces keys in arbitrary order, so the - /// // keys must be sorted to test them against a sorted array. - /// vec.sort_unstable(); - /// assert_eq!(vec, ["a", "b", "c"]); - /// ``` - #[inline] - #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_keys(self) -> IntoKeys<K, V> { - IntoKeys { inner: self.into_iter() } - } - - /// Creates a consuming iterator visiting all the values in arbitrary order. - /// The map cannot be used after calling this. - /// The iterator element type is `V`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let map = HashMap::from([ - /// ("a", 1), - /// ("b", 2), - /// ("c", 3), - /// ]); - /// - /// let mut vec: Vec<i32> = map.into_values().collect(); - /// // The `IntoValues` iterator produces values in arbitrary order, so - /// // the values must be sorted to test them against a sorted array. - /// vec.sort_unstable(); - /// assert_eq!(vec, [1, 2, 3]); - /// ``` - #[inline] - #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_values(self) -> IntoValues<K, V> { - IntoValues { inner: self.into_iter() } - } } impl<K, V, S> HashMap<K, V, S> diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index a1e28c0b0a6..0d087772bf9 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -290,6 +290,28 @@ impl<T, S> HashSet<T, S> { DrainFilter { base: self.base.drain_filter(pred) } } + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + #[stable(feature = "retain_hash_collection", since = "1.18.0")] + pub fn retain<F>(&mut self, f: F) + where + F: FnMut(&T) -> bool, + { + self.base.retain(f) + } + /// Clears the set, removing all values. /// /// # Examples @@ -906,28 +928,6 @@ where { self.base.take(value) } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` such that `f(&e)` returns `false`. - /// The elements are visited in unsorted (and unspecified) order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]); - /// set.retain(|&k| k % 2 == 0); - /// assert_eq!(set.len(), 3); - /// ``` - #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain<F>(&mut self, f: F) - where - F: FnMut(&T) -> bool, - { - self.base.retain(f) - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 0f9912fa64d..982ad189878 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -3,6 +3,7 @@ mod tests; use crate::borrow::{Borrow, Cow}; use crate::cmp; +use crate::collections::TryReserveError; use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::iter::{Extend, FromIterator}; @@ -265,6 +266,43 @@ impl OsString { self.inner.reserve(additional) } + /// Tries to reserve capacity for at least `additional` more length units + /// in the given `OsString`. The string may reserve more space to avoid + /// frequent reallocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve_2)] + /// use std::ffi::{OsStr, OsString}; + /// use std::collections::TryReserveError; + /// + /// fn process_data(data: &str) -> Result<OsString, TryReserveError> { + /// let mut s = OsString::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// s.try_reserve(OsStr::new(data).len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// s.push(data); + /// + /// Ok(s) + /// } + /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); + /// ``` + #[unstable(feature = "try_reserve_2", issue = "91789")] + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve(additional) + } + /// Reserves the minimum capacity for exactly `additional` more capacity to /// be inserted in the given `OsString`. Does nothing if the capacity is /// already sufficient. @@ -290,6 +328,49 @@ impl OsString { self.inner.reserve_exact(additional) } + /// Tries to reserve the minimum capacity for exactly `additional` + /// more length units in the given `OsString`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the `OsString` more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: OsString::try_reserve + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve_2)] + /// use std::ffi::{OsStr, OsString}; + /// use std::collections::TryReserveError; + /// + /// fn process_data(data: &str) -> Result<OsString, TryReserveError> { + /// let mut s = OsString::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// s.try_reserve_exact(OsStr::new(data).len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// s.push(data); + /// + /// Ok(s) + /// } + /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); + /// ``` + #[unstable(feature = "try_reserve_2", issue = "91789")] + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(additional) + } + /// Shrinks the capacity of the `OsString` to match its length. /// /// # Examples diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 4029125a375..70a7d7a8cab 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1140,8 +1140,8 @@ impl From<Ipv4Addr> for u32 { /// ``` /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe); - /// assert_eq!(0xcafebabe, u32::from(addr)); + /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); + /// assert_eq!(0x12345678, u32::from(addr)); /// ``` #[inline] fn from(ip: Ipv4Addr) -> u32 { @@ -1159,8 +1159,8 @@ impl From<u32> for Ipv4Addr { /// ``` /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::from(0xcafebabe); - /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr); + /// let addr = Ipv4Addr::from(0x12345678); + /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); /// ``` #[inline] fn from(ip: u32) -> Ipv4Addr { diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index ae96d6b4df4..ccbc182240c 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -2,6 +2,7 @@ //! systems: just a `Vec<u8>`/`[u8]`. use crate::borrow::Cow; +use crate::collections::TryReserveError; use crate::fmt; use crate::fmt::Write; use crate::mem; @@ -113,11 +114,21 @@ impl Buf { } #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve(additional) + } + + #[inline] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(additional) + } + + #[inline] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 7e09a4fd561..78e92a3331a 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -1,6 +1,7 @@ /// The underlying OsString/OsStr implementation on Windows is a /// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. use crate::borrow::Cow; +use crate::collections::TryReserveError; use crate::fmt; use crate::mem; use crate::rc::Rc; @@ -104,10 +105,18 @@ impl Buf { self.inner.reserve(additional) } + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve(additional) + } + pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(additional) + } + pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index 2cd1e29f6c4..9f978789a62 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -39,22 +39,6 @@ impl CommandEnv { result } - // Apply these changes directly to the current environment - pub fn apply(&self) { - if self.clear { - for (k, _) in env::vars_os() { - env::remove_var(k); - } - } - for (key, maybe_val) in self.vars.iter() { - if let Some(ref val) = maybe_val { - env::set_var(key, val); - } else { - env::remove_var(key); - } - } - } - pub fn is_unchanged(&self) -> bool { !self.clear && self.vars.is_empty() } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 6e29bc61454..7a6e6246357 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -22,6 +22,7 @@ use core::str::next_code_point; use crate::borrow::Cow; use crate::char; +use crate::collections::TryReserveError; use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::iter::FromIterator; @@ -231,11 +232,47 @@ impl Wtf8Buf { self.bytes.reserve(additional) } + /// Tries to reserve capacity for at least `additional` more length units + /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid + /// frequent reallocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.bytes.try_reserve(additional) + } + #[inline] pub fn reserve_exact(&mut self, additional: usize) { self.bytes.reserve_exact(additional) } + /// Tries to reserve the minimum capacity for exactly `additional` + /// length units in the given `Wtf8Buf`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the `Wtf8Buf` more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: Wtf8Buf::try_reserve + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.bytes.try_reserve_exact(additional) + } + #[inline] pub fn shrink_to_fit(&mut self) { self.bytes.shrink_to_fit() diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index bcf2ec06022..9f7f10d0d00 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -972,10 +972,13 @@ pub fn park_timeout(dur: Duration) { /// A unique identifier for a running thread. /// -/// A `ThreadId` is an opaque object that has a unique value for each thread -/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's -/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`] -/// method on a [`Thread`]. +/// A `ThreadId` is an opaque object that uniquely identifies each thread +/// created during the lifetime of a process. `ThreadId`s are guaranteed not to +/// be reused, even when a thread terminates. `ThreadId`s are under the control +/// of Rust's standard library and there may not be any relationship between +/// `ThreadId` and the underlying platform's notion of a thread identifier -- +/// the two concepts cannot, therefore, be used interchangeably. A `ThreadId` +/// can be retrieved from the [`id`] method on a [`Thread`]. /// /// # Examples /// diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 2516f3452b1..608e587cf34 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -13,20 +13,12 @@ // running tests while providing a base that other test frameworks may // build off of. -// N.B., this is also specified in this crate's Cargo.toml, but librustc_ast contains logic specific to -// this crate, which relies on this attribute (rather than the value of `--crate-name` passed by -// cargo) to detect this crate. - -#![crate_name = "test"] #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] -#![feature(libc)] -#![feature(rustc_private)] #![feature(nll)] #![feature(available_parallelism)] #![feature(bench_black_box)] #![feature(internal_output_capture)] -#![feature(panic_unwind)] #![feature(staged_api)] #![feature(termination_trait_lib)] #![feature(test)] @@ -444,8 +436,8 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd .into_iter() .map(|x| { let testfn = match x.testfn { - DynBenchFn(bench) => DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b))) + DynBenchFn(benchfn) => DynTestFn(Box::new(move || { + bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) })), StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) @@ -544,11 +536,9 @@ pub fn run_test( TestRunOpts { strategy, nocapture: opts.nocapture, concurrency, time: opts.time_options }; match testfn { - DynBenchFn(bencher) => { + DynBenchFn(benchfn) => { // Benchmarks aren't expected to panic, so we run them all in-process. - crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, |harness| { - bencher.run(harness) - }); + crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn); None } StaticBenchFn(benchfn) => { diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index 45fae9c76b4..40b05704b40 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -1,5 +1,4 @@ #![allow(missing_docs)] -#![allow(deprecated)] // Float use std::mem; diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 3512a57e8e4..37bb38fb0df 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -74,11 +74,6 @@ impl fmt::Display for TestName { } } -/// Represents a benchmark function. -pub trait TDynBenchFn: Send { - fn run(&self, harness: &mut Bencher); -} - // A function that runs a test. If the function returns successfully, // the test succeeds; if the function panics then the test fails. We // may need to come up with a more clever definition of test in order @@ -87,7 +82,7 @@ pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), DynTestFn(Box<dyn FnOnce() + Send>), - DynBenchFn(Box<dyn TDynBenchFn + 'static>), + DynBenchFn(Box<dyn Fn(&mut Bencher) + Send>), } impl TestFn { diff --git a/rustfmt.toml b/rustfmt.toml index 265f2194fef..aa0d4888f08 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -19,7 +19,6 @@ ignore = [ "library/backtrace", "library/portable-simd", "library/stdarch", - "compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc", "src/doc/book", "src/doc/edition-guide", @@ -36,4 +35,9 @@ ignore = [ "src/tools/rust-analyzer", "src/tools/rustfmt", "src/tools/rust-installer", + + # these are ignored by a standard cargo fmt run + "compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file + "compiler/rustc_codegen_cranelift/example", + "compiler/rustc_codegen_cranelift/scripts", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1ce1f0b26db..b68b2163f87 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -44,11 +44,9 @@ libc = "0.2" serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" toml = "0.5" -lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" opener = "0.5" -merge = "0.1.0" once_cell = "1.7.2" [target.'cfg(windows)'.dependencies.winapi] diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index ed53a98e9a5..7105a2457e2 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -15,6 +15,8 @@ //! switching compilers for the bootstrap and for build scripts will probably //! never get replaced. +include!("../dylib_util.rs"); + use std::env; use std::path::PathBuf; use std::process::{Child, Command}; @@ -50,11 +52,11 @@ fn main() { let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); - let mut dylib_path = bootstrap::util::dylib_path(); + let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(&libdir)); let mut cmd = Command::new(rustc); - cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Get the name of the crate we're compiling, if any. let crate_name = @@ -161,7 +163,7 @@ fn main() { eprintln!( "{} command: {:?}={:?} {:?}", prefix, - bootstrap::util::dylib_path_var(), + dylib_path_var(), env::join_paths(&dylib_path).unwrap(), cmd, ); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index e4396d53016..ad3800834b0 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -7,6 +7,8 @@ use std::ffi::OsString; use std::path::PathBuf; use std::process::Command; +include!("../dylib_util.rs"); + fn main() { let args = env::args_os().skip(1).collect::<Vec<_>>(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); @@ -20,14 +22,14 @@ fn main() { Err(_) => 0, }; - let mut dylib_path = bootstrap::util::dylib_path(); + let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(libdir.clone())); let mut cmd = Command::new(rustdoc); cmd.args(&args) .arg("--sysroot") .arg(&sysroot) - .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + .env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Force all crates compiled by this compiler to (a) be unstable and (b) // allow the `rustc_private` feature to link to other unstable crates @@ -59,7 +61,7 @@ fn main() { if verbose > 1 { eprintln!( "rustdoc command: {:?}={:?} {:?}", - bootstrap::util::dylib_path_var(), + dylib_path_var(), env::join_paths(&dylib_path).unwrap(), cmd, ); diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5df3d0bde6d..5a33073e6b0 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -15,6 +15,42 @@ import tempfile from time import time +# Acquire a lock on the build directory to make sure that +# we don't cause a race condition while building +# Lock is created in `build_dir/lock.db` +def acquire_lock(build_dir): + try: + import sqlite3 + + path = os.path.join(build_dir, "lock.db") + try: + con = sqlite3.Connection(path, timeout=0) + curs = con.cursor() + curs.execute("BEGIN EXCLUSIVE") + # The lock is released when the cursor is dropped + return curs + # If the database is busy then lock has already been acquired + # so we wait for the lock. + # We retry every quarter second so that execution is passed back to python + # so that it can handle signals + except sqlite3.OperationalError: + del con + del curs + print("Waiting for lock on build directory") + con = sqlite3.Connection(path, timeout=0.25) + curs = con.cursor() + while True: + try: + curs.execute("BEGIN EXCLUSIVE") + except sqlite3.OperationalError: + pass + return curs + except ImportError: + print("warning: sqlite3 not available in python, skipping build directory lock") + print("please file an issue on rust-lang/rust") + print("this is not a problem for non-concurrent x.py invocations") + return None + def support_xz(): try: with tempfile.NamedTemporaryFile(delete=False) as temp_file: @@ -1228,6 +1264,12 @@ def bootstrap(help_triggered): build.set_dist_environment(data["dist_server"]) build.build = args.build or build.build_triple() + + # Acquire the lock before doing any build actions + # The lock is released when `lock` is dropped + if not os.path.exists(build.build_dir): + os.makedirs(build.build_dir) + lock = acquire_lock(build.build_dir) build.update_submodules() # Fetch/build the bootstrap diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index bbd2c087cca..917abde9de1 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -351,7 +351,6 @@ pub enum Kind { Check, Clippy, Fix, - Format, Test, Bench, Dist, @@ -399,7 +398,7 @@ impl<'a> Builder<'a> { native::Lld, native::CrtBeginEnd ), - Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!( + Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!( check::Std, check::Rustc, check::Rustdoc, diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 0c16fae01bc..fac5d8db511 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -13,7 +13,8 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::Mutex; -use lazy_static::lazy_static; +// FIXME: replace with std::lazy after it gets stabilized and reaches beta +use once_cell::sync::Lazy; use crate::builder::Step; @@ -222,9 +223,7 @@ impl Interner { } } -lazy_static! { - pub static ref INTERNER: Interner = Interner::default(); -} +pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default); /// This is essentially a `HashMap` which allows storing any type in its input and /// any type in its output. It is a write-once cache; values are never evicted, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 6a734ab5177..c0ab093f952 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -662,6 +662,8 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS .env("CFG_VERSION", builder.rust_version()); let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); + let target_config = builder.config.target_config.get(&target); + cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); if let Some(ref ver_date) = builder.rust_info.commit_date() { @@ -673,9 +675,15 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS if !builder.unstable_features() { cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); } - if let Some(ref s) = builder.config.rustc_default_linker { + + // Prefer the current target's own default_linker, else a globally + // specified one. + if let Some(s) = target_config.and_then(|c| c.default_linker.as_ref()) { + cargo.env("CFG_DEFAULT_LINKER", s); + } else if let Some(ref s) = builder.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } + if builder.config.rustc_parallel { cargo.rustflag("--cfg=parallel_compiler"); cargo.rustdocflag("--cfg=parallel_compiler"); @@ -700,7 +708,6 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } let llvm_config = builder.ensure(native::Llvm { target }); cargo.env("LLVM_CONFIG", &llvm_config); - let target_config = builder.config.target_config.get(&target); if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 68e20f90b7f..5af9248583c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -18,7 +18,6 @@ pub use crate::flags::Subcommand; use crate::flags::{Color, Flags}; use crate::util::exe; use build_helper::t; -use merge::Merge; use serde::Deserialize; macro_rules! check_ci_llvm { @@ -294,6 +293,7 @@ pub struct Target { pub cxx: Option<PathBuf>, pub ar: Option<PathBuf>, pub ranlib: Option<PathBuf>, + pub default_linker: Option<PathBuf>, pub linker: Option<PathBuf>, pub ndk: Option<PathBuf>, pub sanitizers: Option<bool>, @@ -333,6 +333,10 @@ struct TomlConfig { profile: Option<String>, } +trait Merge { + fn merge(&mut self, other: Self); +} + impl Merge for TomlConfig { fn merge( &mut self, @@ -356,105 +360,136 @@ impl Merge for TomlConfig { } } -/// TOML representation of various global build decisions. -#[derive(Deserialize, Default, Clone, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Build { - build: Option<String>, - host: Option<Vec<String>>, - target: Option<Vec<String>>, - // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable - build_dir: Option<String>, - cargo: Option<String>, - rustc: Option<String>, - rustfmt: Option<PathBuf>, - docs: Option<bool>, - compiler_docs: Option<bool>, - docs_minification: Option<bool>, - submodules: Option<bool>, - fast_submodules: Option<bool>, - gdb: Option<String>, - nodejs: Option<String>, - npm: Option<String>, - python: Option<String>, - locked_deps: Option<bool>, - vendor: Option<bool>, - full_bootstrap: Option<bool>, - extended: Option<bool>, - tools: Option<HashSet<String>>, - verbose: Option<usize>, - sanitizers: Option<bool>, - profiler: Option<bool>, - cargo_native_static: Option<bool>, - low_priority: Option<bool>, - configure_args: Option<Vec<String>>, - local_rebuild: Option<bool>, - print_step_timings: Option<bool>, - print_step_rusage: Option<bool>, - check_stage: Option<u32>, - doc_stage: Option<u32>, - build_stage: Option<u32>, - test_stage: Option<u32>, - install_stage: Option<u32>, - dist_stage: Option<u32>, - bench_stage: Option<u32>, - patch_binaries_for_nix: Option<bool>, +// We are using a decl macro instead of a derive proc macro here to reduce the compile time of +// rustbuild. +macro_rules! derive_merge { + ($(#[$attr:meta])* struct $name:ident { + $($field:ident: $field_ty:ty,)* + }) => { + $(#[$attr])* + struct $name { + $($field: $field_ty,)* + } + + impl Merge for $name { + fn merge(&mut self, other: Self) { + $( + if !self.$field.is_some() { + self.$field = other.$field; + } + )* + } + } + } } -/// TOML representation of various global install decisions. -#[derive(Deserialize, Default, Clone, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Install { - prefix: Option<String>, - sysconfdir: Option<String>, - docdir: Option<String>, - bindir: Option<String>, - libdir: Option<String>, - mandir: Option<String>, - datadir: Option<String>, +derive_merge! { + /// TOML representation of various global build decisions. + #[derive(Deserialize, Default, Clone)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Build { + build: Option<String>, + host: Option<Vec<String>>, + target: Option<Vec<String>>, + // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable + build_dir: Option<String>, + cargo: Option<String>, + rustc: Option<String>, + rustfmt: Option<PathBuf>, + docs: Option<bool>, + compiler_docs: Option<bool>, + docs_minification: Option<bool>, + submodules: Option<bool>, + fast_submodules: Option<bool>, + gdb: Option<String>, + nodejs: Option<String>, + npm: Option<String>, + python: Option<String>, + locked_deps: Option<bool>, + vendor: Option<bool>, + full_bootstrap: Option<bool>, + extended: Option<bool>, + tools: Option<HashSet<String>>, + verbose: Option<usize>, + sanitizers: Option<bool>, + profiler: Option<bool>, + cargo_native_static: Option<bool>, + low_priority: Option<bool>, + configure_args: Option<Vec<String>>, + local_rebuild: Option<bool>, + print_step_timings: Option<bool>, + print_step_rusage: Option<bool>, + check_stage: Option<u32>, + doc_stage: Option<u32>, + build_stage: Option<u32>, + test_stage: Option<u32>, + install_stage: Option<u32>, + dist_stage: Option<u32>, + bench_stage: Option<u32>, + patch_binaries_for_nix: Option<bool>, + } } -/// TOML representation of how the LLVM build is configured. -#[derive(Deserialize, Default, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Llvm { - skip_rebuild: Option<bool>, - optimize: Option<bool>, - thin_lto: Option<bool>, - release_debuginfo: Option<bool>, - assertions: Option<bool>, - tests: Option<bool>, - plugins: Option<bool>, - ccache: Option<StringOrBool>, - version_check: Option<bool>, - static_libstdcpp: Option<bool>, - ninja: Option<bool>, - targets: Option<String>, - experimental_targets: Option<String>, - link_jobs: Option<u32>, - link_shared: Option<bool>, - version_suffix: Option<String>, - clang_cl: Option<String>, - cflags: Option<String>, - cxxflags: Option<String>, - ldflags: Option<String>, - use_libcxx: Option<bool>, - use_linker: Option<String>, - allow_old_toolchain: Option<bool>, - polly: Option<bool>, - clang: Option<bool>, - download_ci_llvm: Option<StringOrBool>, +derive_merge! { + /// TOML representation of various global install decisions. + #[derive(Deserialize, Default, Clone)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Install { + prefix: Option<String>, + sysconfdir: Option<String>, + docdir: Option<String>, + bindir: Option<String>, + libdir: Option<String>, + mandir: Option<String>, + datadir: Option<String>, + } } -#[derive(Deserialize, Default, Clone, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Dist { - sign_folder: Option<String>, - gpg_password_file: Option<String>, - upload_addr: Option<String>, - src_tarball: Option<bool>, - missing_tools: Option<bool>, - compression_formats: Option<Vec<String>>, +derive_merge! { + /// TOML representation of how the LLVM build is configured. + #[derive(Deserialize, Default)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Llvm { + skip_rebuild: Option<bool>, + optimize: Option<bool>, + thin_lto: Option<bool>, + release_debuginfo: Option<bool>, + assertions: Option<bool>, + tests: Option<bool>, + plugins: Option<bool>, + ccache: Option<StringOrBool>, + version_check: Option<bool>, + static_libstdcpp: Option<bool>, + ninja: Option<bool>, + targets: Option<String>, + experimental_targets: Option<String>, + link_jobs: Option<u32>, + link_shared: Option<bool>, + version_suffix: Option<String>, + clang_cl: Option<String>, + cflags: Option<String>, + cxxflags: Option<String>, + ldflags: Option<String>, + use_libcxx: Option<bool>, + use_linker: Option<String>, + allow_old_toolchain: Option<bool>, + polly: Option<bool>, + clang: Option<bool>, + download_ci_llvm: Option<StringOrBool>, + } +} + +derive_merge! { + #[derive(Deserialize, Default, Clone)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Dist { + sign_folder: Option<String>, + gpg_password_file: Option<String>, + upload_addr: Option<String>, + src_tarball: Option<bool>, + missing_tools: Option<bool>, + compression_formats: Option<Vec<String>>, + } } #[derive(Deserialize)] @@ -470,79 +505,84 @@ impl Default for StringOrBool { } } -/// TOML representation of how the Rust build is configured. -#[derive(Deserialize, Default, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct Rust { - optimize: Option<bool>, - debug: Option<bool>, - codegen_units: Option<u32>, - codegen_units_std: Option<u32>, - debug_assertions: Option<bool>, - debug_assertions_std: Option<bool>, - overflow_checks: Option<bool>, - overflow_checks_std: Option<bool>, - debug_logging: Option<bool>, - debuginfo_level: Option<u32>, - debuginfo_level_rustc: Option<u32>, - debuginfo_level_std: Option<u32>, - debuginfo_level_tools: Option<u32>, - debuginfo_level_tests: Option<u32>, - run_dsymutil: Option<bool>, - backtrace: Option<bool>, - incremental: Option<bool>, - parallel_compiler: Option<bool>, - default_linker: Option<String>, - channel: Option<String>, - description: Option<String>, - musl_root: Option<String>, - rpath: Option<bool>, - verbose_tests: Option<bool>, - optimize_tests: Option<bool>, - codegen_tests: Option<bool>, - ignore_git: Option<bool>, - dist_src: Option<bool>, - save_toolstates: Option<String>, - codegen_backends: Option<Vec<String>>, - lld: Option<bool>, - use_lld: Option<bool>, - llvm_tools: Option<bool>, - deny_warnings: Option<bool>, - backtrace_on_ice: Option<bool>, - verify_llvm_ir: Option<bool>, - thin_lto_import_instr_limit: Option<u32>, - remap_debuginfo: Option<bool>, - jemalloc: Option<bool>, - test_compare_mode: Option<bool>, - llvm_libunwind: Option<String>, - control_flow_guard: Option<bool>, - new_symbol_mangling: Option<bool>, - profile_generate: Option<String>, - profile_use: Option<String>, - // ignored; this is set from an env var set by bootstrap.py - download_rustc: Option<StringOrBool>, +derive_merge! { + /// TOML representation of how the Rust build is configured. + #[derive(Deserialize, Default)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct Rust { + optimize: Option<bool>, + debug: Option<bool>, + codegen_units: Option<u32>, + codegen_units_std: Option<u32>, + debug_assertions: Option<bool>, + debug_assertions_std: Option<bool>, + overflow_checks: Option<bool>, + overflow_checks_std: Option<bool>, + debug_logging: Option<bool>, + debuginfo_level: Option<u32>, + debuginfo_level_rustc: Option<u32>, + debuginfo_level_std: Option<u32>, + debuginfo_level_tools: Option<u32>, + debuginfo_level_tests: Option<u32>, + run_dsymutil: Option<bool>, + backtrace: Option<bool>, + incremental: Option<bool>, + parallel_compiler: Option<bool>, + default_linker: Option<String>, + channel: Option<String>, + description: Option<String>, + musl_root: Option<String>, + rpath: Option<bool>, + verbose_tests: Option<bool>, + optimize_tests: Option<bool>, + codegen_tests: Option<bool>, + ignore_git: Option<bool>, + dist_src: Option<bool>, + save_toolstates: Option<String>, + codegen_backends: Option<Vec<String>>, + lld: Option<bool>, + use_lld: Option<bool>, + llvm_tools: Option<bool>, + deny_warnings: Option<bool>, + backtrace_on_ice: Option<bool>, + verify_llvm_ir: Option<bool>, + thin_lto_import_instr_limit: Option<u32>, + remap_debuginfo: Option<bool>, + jemalloc: Option<bool>, + test_compare_mode: Option<bool>, + llvm_libunwind: Option<String>, + control_flow_guard: Option<bool>, + new_symbol_mangling: Option<bool>, + profile_generate: Option<String>, + profile_use: Option<String>, + // ignored; this is set from an env var set by bootstrap.py + download_rustc: Option<StringOrBool>, + } } -/// TOML representation of how each build target is configured. -#[derive(Deserialize, Default, Merge)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct TomlTarget { - cc: Option<String>, - cxx: Option<String>, - ar: Option<String>, - ranlib: Option<String>, - linker: Option<String>, - llvm_config: Option<String>, - llvm_filecheck: Option<String>, - android_ndk: Option<String>, - sanitizers: Option<bool>, - profiler: Option<bool>, - crt_static: Option<bool>, - musl_root: Option<String>, - musl_libdir: Option<String>, - wasi_root: Option<String>, - qemu_rootfs: Option<String>, - no_std: Option<bool>, +derive_merge! { + /// TOML representation of how each build target is configured. + #[derive(Deserialize, Default)] + #[serde(deny_unknown_fields, rename_all = "kebab-case")] + struct TomlTarget { + cc: Option<String>, + cxx: Option<String>, + ar: Option<String>, + ranlib: Option<String>, + default_linker: Option<PathBuf>, + linker: Option<String>, + llvm_config: Option<String>, + llvm_filecheck: Option<String>, + android_ndk: Option<String>, + sanitizers: Option<bool>, + profiler: Option<bool>, + crt_static: Option<bool>, + musl_root: Option<String>, + musl_libdir: Option<String>, + wasi_root: Option<String>, + qemu_rootfs: Option<String>, + no_std: Option<bool>, + } } impl Config { @@ -1109,10 +1149,6 @@ impl Config { self.verbose > 0 } - pub fn very_verbose(&self) -> bool { - self.verbose > 1 - } - pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool { self.target_config.get(&target).map(|t| t.sanitizers).flatten().unwrap_or(self.sanitizers) } diff --git a/src/bootstrap/dylib_util.rs b/src/bootstrap/dylib_util.rs new file mode 100644 index 00000000000..6d75272c501 --- /dev/null +++ b/src/bootstrap/dylib_util.rs @@ -0,0 +1,28 @@ +// Various utilities for working with dylib paths. +// +// This file is meant to be included directly to avoid a dependency on the bootstrap library from +// the rustc and rustdoc wrappers. This improves compilation time by reducing the linking time. + +/// Returns the environment variable which the dynamic library lookup path +/// resides in for this platform. +pub fn dylib_path_var() -> &'static str { + if cfg!(target_os = "windows") { + "PATH" + } else if cfg!(target_os = "macos") { + "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" + } else { + "LD_LIBRARY_PATH" + } +} + +/// Parses the `dylib_path_var()` environment variable, returning a list of +/// paths that are members of this lookup path. +pub fn dylib_path() -> Vec<PathBuf> { + let var = match env::var_os(dylib_path_var()) { + Some(v) => v, + None => return vec![], + }; + env::split_paths(&var).collect() +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 82462f9758e..8569089f701 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -110,7 +110,6 @@ use std::fs::{self, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command}; -use std::slice; use std::str; #[cfg(unix)] @@ -472,10 +471,6 @@ impl Build { build } - pub fn build_triple(&self) -> &[Interned<String>] { - slice::from_ref(&self.build.triple) - } - // modified from `check_submodule` and `update_submodule` in bootstrap.py /// Given a path to the directory of a submodule, update it. /// diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 57178aa382f..ee58bedcc87 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -16,11 +16,6 @@ use build_helper::t; use crate::builder::Builder; use crate::config::{Config, TargetSelection}; -/// Returns the `name` as the filename of a static library for `target`. -pub fn staticlib(name: &str, target: TargetSelection) -> String { - if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) } -} - /// Given an executable called `name`, return the filename for the /// executable for a particular target. pub fn exe(name: &str, target: TargetSelection) -> String { @@ -54,29 +49,7 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) { cmd.env(dylib_path_var(), t!(env::join_paths(list))); } -/// Returns the environment variable which the dynamic library lookup path -/// resides in for this platform. -pub fn dylib_path_var() -> &'static str { - if cfg!(target_os = "windows") { - "PATH" - } else if cfg!(target_os = "macos") { - "DYLD_LIBRARY_PATH" - } else if cfg!(target_os = "haiku") { - "LIBRARY_PATH" - } else { - "LD_LIBRARY_PATH" - } -} - -/// Parses the `dylib_path_var()` environment variable, returning a list of -/// paths that are members of this lookup path. -pub fn dylib_path() -> Vec<PathBuf> { - let var = match env::var_os(dylib_path_var()) { - Some(v) => v, - None => return vec![], - }; - env::split_paths(&var).collect() -} +include!("dylib_util.rs"); /// Adds a list of lookup paths to `cmd`'s link library lookup path. pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) { @@ -103,21 +76,6 @@ fn link_lib_path() -> Vec<PathBuf> { env::split_paths(&var).collect() } -/// `push` all components to `buf`. On windows, append `.exe` to the last component. -pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { - let (&file, components) = components.split_last().expect("at least one component required"); - let mut file = file.to_owned(); - - if cfg!(windows) { - file.push_str(".exe"); - } - - buf.extend(components); - buf.push(file); - - buf -} - pub struct TimeIt(bool, Instant); /// Returns an RAII structure that prints out how long it took to drop. diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 6e77bb0a09b..d4701a25614 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.5.1 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.5.3 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/doc/unstable-book/src/compiler-flags/branch-protection.md b/src/doc/unstable-book/src/compiler-flags/branch-protection.md new file mode 100644 index 00000000000..85403748e1d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/branch-protection.md @@ -0,0 +1,18 @@ +# `branch-protection` + +This option lets you enable branch authentication instructions on AArch64. +This option is ignored for non-AArch64 architectures. +It takes some combination of the following values, separated by a `,`. + +- `pac-ret` - Enable pointer authentication for non-leaf functions. +- `leaf` - Enable pointer authentication for all functions, including leaf functions. +- `b-key` - Sign return addresses with key B, instead of the default key A. +- `bti` - Enable branch target identification. + +`leaf` and `b-key` are only valid if `pac-ret` was previously specified. +For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but +`-Z branch-protection=bti,leaf,pac-ret` is not. + +Rust's standard library does not ship with BTI or pointer authentication enabled by default. +In Cargo projects the standard library can be recompiled with pointer authentication using the nightly +[build-std](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) feature. diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md index f4d1ca0ec69..39eb407269c 100644 --- a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md @@ -27,7 +27,7 @@ When running a coverage-instrumented program, the counter values are written to [`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic [llvm code coverage mapping format]: https://llvm.org/docs/CoverageMappingFormat.html -> **Note**: `-Z instrument-coverage` also automatically enables `-Z symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended, but be aware that this demangler is also experimental. The `v0` demangler can be overridden by explicitly adding `-Z symbol-mangling-version=legacy`. +> **Note**: `-Z instrument-coverage` also automatically enables `-C symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended, but be aware that this demangler is also experimental. The `v0` demangler can be overridden by explicitly adding `-Z unstable-options -C symbol-mangling-version=legacy`. [#60705]: https://github.com/rust-lang/rust/issues/60705 diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 3c9b6f5006d..a3cb982f277 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -8,7 +8,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } -pulldown-cmark = { version = "0.8", default-features = false } +pulldown-cmark = { version = "0.9", default-features = false } minifier = "0.0.41" rayon = "1.3.1" serde = { version = "1.0", features = ["derive"] } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index dca02cb25bd..f54ab9f2b11 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trace!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); - for &trait_def_id in self.cx.tcx.all_traits(()).iter() { + for trait_def_id in self.cx.tcx.all_traits() { if !self.cx.cache.access_levels.is_public(trait_def_id) || self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 5da20953bf2..ce0ac322af9 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -540,7 +541,7 @@ fn build_module( name: prim_ty.as_sym(), args: clean::GenericArgs::AngleBracketed { args: Vec::new(), - bindings: Vec::new(), + bindings: ThinVec::new(), }, }], }, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dbed66421e5..959be5478b4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -148,7 +148,7 @@ fn clean_trait_ref_with_bindings( path } -impl Clean<Path> for ty::TraitRef<'tcx> { +impl Clean<Path> for ty::TraitRef<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Path { clean_trait_ref_with_bindings(cx, *self, &[]) } @@ -549,7 +549,7 @@ impl Clean<Generics> for hir::Generics<'_> { fn clean_ty_generics( cx: &mut DocContext<'_>, gens: &ty::Generics, - preds: ty::GenericPredicates<'tcx>, + preds: ty::GenericPredicates<'_>, ) -> Generics { // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, // since `Clean for ty::Predicate` would consume them. @@ -579,7 +579,7 @@ fn clean_ty_generics( .collect::<Vec<GenericParamDef>>(); // param index -> [(DefId of trait, associated type name, type)] - let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default(); + let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'_>)>>::default(); let where_predicates = preds .predicates @@ -708,8 +708,8 @@ fn clean_ty_generics( fn clean_fn_or_proc_macro( item: &hir::Item<'_>, - sig: &'a hir::FnSig<'a>, - generics: &'a hir::Generics<'a>, + sig: &hir::FnSig<'_>, + generics: &hir::Generics<'_>, body_id: hir::BodyId, name: &mut Symbol, cx: &mut DocContext<'_>, @@ -1387,7 +1387,7 @@ impl Clean<Type> for hir::Ty<'_> { } /// Returns `None` if the type could not be normalized -fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> { +fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> { // HACK: low-churn fix for #79459 while we wait for a trait normalization fix if !cx.tcx.sess.opts.debugging_opts.normalize_docs { return None; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2b1a1d4a600..2ee5de24687 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2060,14 +2060,14 @@ rustc_data_structures::static_assert_size!(GenericArg, 80); #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum GenericArgs { - AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> }, + AngleBracketed { args: Vec<GenericArg>, bindings: ThinVec<TypeBinding> }, Parenthesized { inputs: Vec<Type>, output: Option<Box<Type>> }, } // `GenericArgs` is in every `PathSegment`, so its size can significantly // affect rustdoc's memory usage. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(GenericArgs, 56); +rustc_data_structures::static_assert_size!(GenericArgs, 40); #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct PathSegment { @@ -2078,7 +2078,7 @@ crate struct PathSegment { // `PathSegment` usually occurs multiple times in every `Path`, so its size can // significantly affect rustdoc's memory usage. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(PathSegment, 64); +rustc_data_structures::static_assert_size!(PathSegment, 48); #[derive(Clone, Debug)] crate struct Typedef { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 7d5e2e36bd1..43dcb611a37 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -10,6 +10,7 @@ use crate::visit_lib::LibEmbargoVisitor; use rustc_ast as ast; use rustc_ast::tokenstream::TokenTree; +use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -108,7 +109,7 @@ fn external_generic_args( if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { let inputs = match ty_kind.unwrap() { ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), - _ => return GenericArgs::AngleBracketed { args, bindings }, + _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() }, }; let output = None; // FIXME(#20299) return type comes from a projection now @@ -118,7 +119,7 @@ fn external_generic_args( // }; GenericArgs::Parenthesized { inputs, output } } else { - GenericArgs::AngleBracketed { args, bindings } + GenericArgs::AngleBracketed { args, bindings: bindings.into() } } } @@ -143,7 +144,7 @@ pub(super) fn external_path( /// Remove the generic arguments from a path. crate fn strip_path_generics(mut path: Path) -> Path { for ps in path.segments.iter_mut() { - ps.args = GenericArgs::AngleBracketed { args: vec![], bindings: vec![] } + ps.args = GenericArgs::AngleBracketed { args: vec![], bindings: ThinVec::new() } } path @@ -223,7 +224,7 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { }) } -crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { +crate fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { match n.val { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) => { let mut s = if let Some(def) = def.as_local() { @@ -294,7 +295,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tcx>) -> String { +fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &ty::Const<'_>) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct.val, ct.ty.kind()) { @@ -362,7 +363,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { } crate fn get_auto_trait_and_blanket_impls( - cx: &mut DocContext<'tcx>, + cx: &mut DocContext<'_>, item_def_id: DefId, ) -> impl Iterator<Item = Item> { let auto_impls = cx diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3948f9fa7e7..32b66278bf4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -369,10 +369,8 @@ crate fn run_global_ctxt( impl_trait_bounds: Default::default(), generated_synthetics: Default::default(), auto_traits: tcx - .all_traits(()) - .iter() - .cloned() - .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) + .all_traits() + .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)) .collect(), module_trait_cache: FxHashMap::default(), cache: Cache::new(access_levels, render_options.document_private), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3a7c7186877..981eb9589e9 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -955,7 +955,7 @@ fn fmt_type<'cx>( Ok((ref url, _, ref path)) if !f.alternate() => { write!( f, - "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \ + "<a class=\"associatedtype\" href=\"{url}#{shortty}.{name}\" \ title=\"type {path}::{name}\">{name}</a>", url = url, shortty = ItemType::AssocType, diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 688860f94e1..39f58cdd821 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -187,7 +187,7 @@ struct TokenIter<'a> { src: &'a str, } -impl Iterator for TokenIter<'a> { +impl<'a> Iterator for TokenIter<'a> { type Item = (TokenKind, &'a str); fn next(&mut self) -> Option<(TokenKind, &'a str)> { if self.src.is_empty() { @@ -227,7 +227,7 @@ struct PeekIter<'a> { iter: TokenIter<'a>, } -impl PeekIter<'a> { +impl<'a> PeekIter<'a> { fn new(iter: TokenIter<'a>) -> Self { Self { stored: VecDeque::new(), peek_pos: 0, iter } } @@ -254,7 +254,7 @@ impl PeekIter<'a> { } } -impl Iterator for PeekIter<'a> { +impl<'a> Iterator for PeekIter<'a> { type Item = (TokenKind, &'a str); fn next(&mut self) -> Option<Self::Item> { self.peek_pos = 0; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 545b409175e..3fd9c0a1944 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -538,7 +538,7 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator } let event = self.inner.next(); - if let Some((Event::Start(Tag::Heading(level)), _)) = event { + if let Some((Event::Start(Tag::Heading(level, _, _)), _)) = event { let mut id = String::new(); for event in &mut self.inner { match &event.0 { @@ -560,7 +560,8 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); } - let level = std::cmp::min(level + (self.heading_offset as u32), MAX_HEADER_LEVEL); + let level = + std::cmp::min(level as u32 + (self.heading_offset as u32), MAX_HEADER_LEVEL); self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0)); let start_tags = format!( @@ -773,7 +774,7 @@ crate fn find_testable_code<T: doctest::Tester>( tests.add_test(text, block_info, line); prev_offset = offset.start; } - Event::Start(Tag::Heading(level)) => { + Event::Start(Tag::Heading(level, _, _)) => { register_header = Some(level as u32); } Event::Text(ref s) if register_header.is_some() => { @@ -1053,7 +1054,7 @@ impl Markdown<'_> { let mut replacer = |broken_link: BrokenLink<'_>| { links .iter() - .find(|link| &*link.original_text == broken_link.reference) + .find(|link| link.original_text.as_str() == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) }; @@ -1134,7 +1135,7 @@ impl MarkdownSummaryLine<'_> { let mut replacer = |broken_link: BrokenLink<'_>| { links .iter() - .find(|link| &*link.original_text == broken_link.reference) + .find(|link| link.original_text.as_str() == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) }; @@ -1168,7 +1169,7 @@ fn markdown_summary_with_limit( let mut replacer = |broken_link: BrokenLink<'_>| { link_names .iter() - .find(|link| &*link.original_text == broken_link.reference) + .find(|link| link.original_text.as_str() == &*broken_link.reference) .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) }; @@ -1311,10 +1312,10 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> { }; let mut push = |link: BrokenLink<'_>| { - let span = span_for_link(&CowStr::Borrowed(link.reference), link.span); + let span = span_for_link(&link.reference, link.span); links.borrow_mut().push(MarkdownLink { kind: LinkType::ShortcutUnknown, - link: link.reference.to_owned(), + link: link.reference.to_string(), range: span, }); None diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3e7711181f7..16334890da6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -788,7 +788,7 @@ fn assoc_type( ) { write!( w, - "{}type <a href=\"{}\" class=\"type\">{}</a>", + "{}type <a href=\"{}\" class=\"associatedtype\">{}</a>", extra, naive_assoc_href(it, link, cx), it.name.as_ref().unwrap() diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 7803a779727..54d9b6905c5 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -92,7 +92,7 @@ impl<'tcx> SpanMapVisitor<'tcx> { } } -impl Visitor<'tcx> for SpanMapVisitor<'tcx> { +impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { type Map = rustc_middle::hir::map::Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 962a954ff74..04c2b7a0c9a 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -142,7 +142,7 @@ impl DocVisitor for SourceCollector<'_, '_> { } } -impl SourceCollector<'_, 'tcx> { +impl SourceCollector<'_, '_> { /// Renders the given filename into its corresponding HTML source file. fn emit_source( &mut self, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index cbb078f2ab3..e5c667a37c6 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2007,6 +2007,16 @@ details.rustdoc-toggle[open] > summary.hideme::after { max-width: 100vw; width: 100vw; } + + /* Position of the "[-]" element. */ + details.rustdoc-toggle:not(.top-doc) > summary { + margin-left: 10px; + } + .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before, + #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before, + #main-content > div > details.rustdoc-toggle > summary::before { + left: -11px; + } } @media print { diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index dea6d08396f..38040eeca52 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -167,29 +167,35 @@ pre, .rustdoc.source .example-wrap { .content .item-info::before { color: #ccc; } -.content span.foreigntype, .content a.foreigntype { color: #ef57ff; } -.content span.union, .content a.union { color: #98a01c; } +.content span.foreigntype, .content a.foreigntype { color: #ffa0a5; } +.content span.union, .content a.union { color: #ffa0a5; } .content span.constant, .content a.constant, -.content span.static, .content a.static { color: #6380a0; } -.content span.primitive, .content a.primitive { color: #32889b; } -.content span.traitalias, .content a.traitalias { color: #57d399; } -.content span.keyword, .content a.keyword { color: #de5249; } +.content span.static, .content a.static { color: #39AFD7; } +.content span.primitive, .content a.primitive { color: #ffa0a5; } +.content span.traitalias, .content a.traitalias { color: #39AFD7; } +.content span.keyword, .content a.keyword { color: #39AFD7; } .content span.externcrate, .content span.mod, .content a.mod { - color: #acccf9; + color: #39AFD7; } .content span.struct, .content a.struct { color: #ffa0a5; } .content span.enum, .content a.enum { - color: #99e0c9; + color: #ffa0a5; } .content span.trait, .content a.trait { color: #39AFD7; } .content span.type, .content a.type { - color: #cfbcf5; + color: #39AFD7; } +.content span.type, +.content a.type, +.block a.current.type { color: #39AFD7; } +.content span.associatedtype, +.content a.associatedtype, +.block a.current.associatedtype { color: #39AFD7; } .content span.fn, .content a.fn, .content span.method, .content a.method, .content span.tymethod, .content a.tymethod, .content .fnname { @@ -454,11 +460,12 @@ above the `@media (max-width: 700px)` rules due to a bug in the css checker */ .block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {} .content span.struct,.content a.struct,.block a.current.struct {} #titles>button:hover,#titles>button.selected {} -.content span.type,.content a.type,.block a.current.type {} +.content span.typedef,.content a.typedef,.block a.current.typedef {} .content span.union,.content a.union,.block a.current.union {} pre.rust .lifetime {} .stab.unstable {} -h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod) {} +h2, +h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {} .content span.enum,.content a.enum,.block a.current.enum {} .content span.constant,.content a.constant,.block a.current.constant,.content span.static, .content a.static, .block a.current.static {} @@ -495,6 +502,7 @@ a.result-fn:focus, a.result-method:focus, a.result-tymethod:focus {} a.result-type:focus {} +a.result-associatedtype:focus {} a.result-foreigntype:focus {} a.result-attr:focus, a.result-derive:focus, diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 6e2cbbecbf7..f4181e431c8 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -119,47 +119,49 @@ pre, .rustdoc.source .example-wrap { a.result-trait:focus { background-color: #013191; } a.result-traitalias:focus { background-color: #013191; } a.result-mod:focus, -a.result-externcrate:focus { background-color: #afc6e4; } -a.result-mod:focus { background-color: #803a1b; } -a.result-externcrate:focus { background-color: #396bac; } -a.result-enum:focus { background-color: #5b4e68; } +a.result-externcrate:focus { background-color: #884719; } +a.result-enum:focus { background-color: #194e9f; } a.result-struct:focus { background-color: #194e9f; } -a.result-union:focus { background-color: #b7bd49; } +a.result-union:focus { background-color: #194e9f; } a.result-fn:focus, a.result-method:focus, a.result-tymethod:focus { background-color: #4950ed; } -a.result-type:focus { background-color: #38902c; } -a.result-foreigntype:focus { background-color: #b200d6; } +a.result-type:focus { background-color: #194e9f; } +a.result-associatedtype:focus { background-color: #884719; } +a.result-foreigntype:focus { background-color: #194e9f; } a.result-attr:focus, a.result-derive:focus, a.result-macro:focus { background-color: #217d1c; } a.result-constant:focus, -a.result-static:focus { background-color: #0063cc; } -a.result-primitive:focus { background-color: #00708a; } +a.result-static:focus { background-color: #884719; } +a.result-primitive:focus { background-color: #194e9f; } a.result-keyword:focus { background-color: #884719; } .content .item-info::before { color: #ccc; } -.content span.enum, .content a.enum, .block a.current.enum { color: #82b089; } +.content span.enum, .content a.enum, .block a.current.enum { color: #2dbfb8; } .content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; } -.content span.type, .content a.type, .block a.current.type { color: #ff7f00; } -.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; } +.content span.type, .content a.type, .block a.current.type { color: #2dbfb8; } +.content span.associatedtype, +.content a.associatedtype, +.block a.current.associatedtype { color: #D2991D; } +.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #2dbfb8; } .content span.attr, .content a.attr, .block a.current.attr, .content span.derive, .content a.derive, .block a.current.derive, .content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; } -.content span.union, .content a.union, .block a.current.union { color: #a6ae37; } +.content span.union, .content a.union, .block a.current.union { color: #2dbfb8; } .content span.constant, .content a.constant, .block a.current.constant, -.content span.static, .content a.static, .block a.current.static { color: #82a5c9; } -.content span.primitive, .content a.primitive, .block a.current.primitive { color: #43aec7; } +.content span.static, .content a.static, .block a.current.static { color: #D2991D; } +.content span.primitive, .content a.primitive, .block a.current.primitive { color: #2dbfb8; } .content span.externcrate, -.content span.mod, .content a.mod, .block a.current.mod { color: #bda000; } +.content span.mod, .content a.mod, .block a.current.mod { color: #D2991D; } .content span.trait, .content a.trait, .block a.current.trait { color: #b78cf2; } -.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #b397da; } +.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #b78cf2; } .content span.fn, .content a.fn, .block a.current.fn, .content span.method, .content a.method, .block a.current.method, .content span.tymethod, .content a.tymethod, .block a.current.tymethod, .content .fnname{ color: #2BAB63; } -.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; } +.content span.keyword, .content a.keyword, .block a.current.keyword { color: #D2991D; } pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 4bf411d459a..176f63098a4 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -9,7 +9,7 @@ h1, h2, h3, h4 { color: black; } h1.fqn { - border-bottom-color: #D5D5D5; + border-bottom-color: #DDDDDD; } h2, h3, h4 { border-bottom-color: #DDDDDD; @@ -31,7 +31,7 @@ pre, .rustdoc.source .example-wrap { } .sidebar { - background-color: #F1F1F1; + background-color: #F5F5F5; } /* Improve the scrollbar display on firefox */ @@ -90,7 +90,7 @@ pre, .rustdoc.source .example-wrap { .line-numbers span { color: #c67e2d; } .line-numbers .line-highlighted { - background-color: #f6fdb0 !important; + background-color: #FDFFD3 !important; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { @@ -120,44 +120,48 @@ a.result-trait:focus { background-color: #c7b6ff; } a.result-traitalias:focus { background-color: #c7b6ff; } a.result-mod:focus, a.result-externcrate:focus { background-color: #afc6e4; } -a.result-enum:focus { background-color: #b4d1b9; } +a.result-enum:focus { background-color: #e7b1a0; } a.result-struct:focus { background-color: #e7b1a0; } -a.result-union:focus { background-color: #b7bd49; } +a.result-union:focus { background-color: #e7b1a0; } a.result-fn:focus, a.result-method:focus, a.result-tymethod:focus { background-color: #c6afb3; } -a.result-type:focus { background-color: #ffc891; } -a.result-foreigntype:focus { background-color: #f5c4ff; } +a.result-type:focus { background-color: #e7b1a0; } +a.result-associatedtype:focus { background-color: #afc6e4; } +a.result-foreigntype:focus { background-color: #e7b1a0; } a.result-attr:focus, a.result-derive:focus, a.result-macro:focus { background-color: #8ce488; } a.result-constant:focus, -a.result-static:focus { background-color: #c3e0ff; } -a.result-primitive:focus { background-color: #9aecff; } -a.result-keyword:focus { background-color: #f99650; } +a.result-static:focus { background-color: #afc6e4; } +a.result-primitive:focus { background-color: #e7b1a0; } +a.result-keyword:focus { background-color: #afc6e4; } .content .item-info::before { color: #ccc; } -.content span.enum, .content a.enum, .block a.current.enum { color: #508157; } -.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; } -.content span.type, .content a.type, .block a.current.type { color: #ba5d00; } -.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } +.content span.enum, .content a.enum, .block a.current.enum { color: #AD378A; } +.content span.struct, .content a.struct, .block a.current.struct { color: #AD378A; } +.content span.type, .content a.type, .block a.current.type { color: #AD378A; } +.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #3873AD; } +.content span.associatedtype, +.content a.associatedtype, +.block a.current.associatedtype { color: #3873AD; } .content span.attr, .content a.attr, .block a.current.attr, .content span.derive, .content a.derive, .block a.current.derive, .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } -.content span.union, .content a.union, .block a.current.union { color: #767b27; } +.content span.union, .content a.union, .block a.current.union { color: #AD378A; } .content span.constant, .content a.constant, .block a.current.constant, -.content span.static, .content a.static, .block a.current.static { color: #546e8a; } -.content span.primitive, .content a.primitive, .block a.current.primitive { color: #2c8093; } +.content span.static, .content a.static, .block a.current.static { color: #3873AD; } +.content span.primitive, .content a.primitive, .block a.current.primitive { color: #AD378A; } .content span.externcrate, -.content span.mod, .content a.mod, .block a.current.mod { color: #4d76ae; } -.content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; } -.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #6841f1; } +.content span.mod, .content a.mod, .block a.current.mod { color: #3873AD; } +.content span.trait, .content a.trait, .block a.current.trait { color: #6E4FC9; } +.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #5137AD; } .content span.fn, .content a.fn, .block a.current.fn, .content span.method, .content a.method, .block a.current.method, .content span.tymethod, .content a.tymethod, .block a.current.tymethod, -.content .fnname { color: #9a6e31; } -.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; } +.content .fnname { color: #AD7C37; } +.content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; } nav:not(.sidebar) { border-bottom-color: #e0e0e0; @@ -268,7 +272,7 @@ pre.rust .question-mark { } a.test-arrow { - background-color: rgba(78, 139, 202, 0.2); + background-color: rgb(78, 139, 202, 0.2); } a.test-arrow:hover{ @@ -285,7 +289,7 @@ a.test-arrow:hover{ } :target { - border-right: 3px solid #ffb44c; + border-right: 3px solid #AD7C37; } pre.compile_fail { @@ -337,7 +341,7 @@ pre.ignore:hover, .information:hover + pre.ignore { } .search-failed a { - color: #0089ff; + color: #3873AD; } .tooltip::after { @@ -374,18 +378,18 @@ pre.ignore:hover, .information:hover + pre.ignore { @media (max-width: 700px) { .sidebar-menu { - background-color: #F1F1F1; + background-color: #F5F5F5; border-bottom-color: #e0e0e0; border-right-color: #e0e0e0; } .sidebar-elems { - background-color: #F1F1F1; + background-color: #F5F5F5; border-right-color: #000; } #sidebar-filler { - background-color: #F1F1F1; + background-color: #F5F5F5; border-bottom-color: #e0e0e0; } } @@ -453,13 +457,13 @@ kbd { } #sidebar-toggle { - background-color: #F1F1F1; + background-color: #F5F5F5; } #sidebar-toggle:hover { background-color: #E0E0E0; } #source-sidebar { - background-color: #F1F1F1; + background-color: #F5F5F5; } #source-sidebar > .title { border-bottom-color: #ccc; diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 005da01b52b..88a5c0c5ca2 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -37,7 +37,7 @@ crate struct JsonRenderer<'tcx> { cache: Rc<Cache>, } -impl JsonRenderer<'tcx> { +impl<'tcx> JsonRenderer<'tcx> { fn sess(&self) -> &'tcx Session { self.tcx.sess } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 95de28e0c5b..014ac484dcf 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -8,7 +8,6 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(box_syntax)] -#![feature(in_band_lifetimes)] #![feature(let_else)] #![feature(nll)] #![feature(test)] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 10ef92e5f40..26ccdb1c87e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -210,7 +210,7 @@ enum MalformedGenerics { EmptyAngleBrackets, } -impl ResolutionFailure<'a> { +impl ResolutionFailure<'_> { /// This resolved fully (not just partially) but is erroneous for some other reason /// /// Returns the full resolution of the link, if present. @@ -336,7 +336,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// full path segments left in the link. /// /// [enum struct variant]: hir::VariantData::Struct - fn variant_field( + fn variant_field<'path>( &self, path_str: &'path str, module_id: DefId, diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 5884fdc715a..cc1d994dc99 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -129,7 +129,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate // `tcx.crates(())` doesn't include the local crate, and `tcx.all_trait_implementations` // doesn't work with it anyway, so pull them from the HIR map instead let mut extra_attrs = Vec::new(); - for &trait_did in cx.tcx.all_traits(()).iter() { + for trait_did in cx.tcx.all_traits() { for &impl_did in cx.tcx.hir().trait_impls(trait_did) { let impl_did = impl_did.to_def_id(); cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ea7372761ba..8e29cb16a40 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -32,8 +32,8 @@ crate struct Module<'hir> { crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>, } -impl Module<'hir> { - crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> { +impl Module<'_> { + crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Self { Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() } } diff --git a/src/test/assembly/aarch64-pointer-auth.rs b/src/test/assembly/aarch64-pointer-auth.rs new file mode 100644 index 00000000000..27e289086b9 --- /dev/null +++ b/src/test/assembly/aarch64-pointer-auth.rs @@ -0,0 +1,22 @@ +// Test that PAC instructions are emitted when branch-protection is specified. + +// min-llvm-version: 10.0.1 +// assembly-output: emit-asm +// compile-flags: --target aarch64-unknown-linux-gnu +// compile-flags: -Z branch-protection=pac-ret,leaf +// needs-llvm-components: aarch64 + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +// CHECK: hint #25 +// CHECK: hint #29 +#[no_mangle] +pub fn test() -> u8 { + 42 +} diff --git a/src/test/codegen/branch-protection.rs b/src/test/codegen/branch-protection.rs new file mode 100644 index 00000000000..106c9b148ee --- /dev/null +++ b/src/test/codegen/branch-protection.rs @@ -0,0 +1,41 @@ +// Test that the correct module flags are emitted with different branch protection flags. + +// revisions: bti pac-ret leaf b-key +// min-llvm-version: 12.0.0 +// needs-llvm-components: aarch64 +// [bti] compile-flags: -Z branch-protection=bti +// [pac-ret] compile-flags: -Z branch-protection=pac-ret +// [leaf] compile-flags: -Z branch-protection=pac-ret,leaf +// [b-key] compile-flags: -Z branch-protection=pac-ret,b-key +// compile-flags: --target aarch64-unknown-linux-gnu + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } + +// A basic test function. +pub fn test() { +} + +// bti: !"branch-target-enforcement", i32 1 +// bti: !"sign-return-address", i32 0 +// bti: !"sign-return-address-all", i32 0 +// bti: !"sign-return-address-with-bkey", i32 0 + +// pac-ret: !"branch-target-enforcement", i32 0 +// pac-ret: !"sign-return-address", i32 1 +// pac-ret: !"sign-return-address-all", i32 0 +// pac-ret: !"sign-return-address-with-bkey", i32 0 + +// leaf: !"branch-target-enforcement", i32 0 +// leaf: !"sign-return-address", i32 1 +// leaf: !"sign-return-address-all", i32 1 +// leaf: !"sign-return-address-with-bkey", i32 0 + +// b-key: !"branch-target-enforcement", i32 0 +// b-key: !"sign-return-address", i32 1 +// b-key: !"sign-return-address-all", i32 0 +// b-key: !"sign-return-address-with-bkey", i32 1 diff --git a/src/test/codegen/inline-hint.rs b/src/test/codegen/inline-hint.rs index a2571c2e532..ad41badf381 100644 --- a/src/test/codegen/inline-hint.rs +++ b/src/test/codegen/inline-hint.rs @@ -1,7 +1,7 @@ // Checks that closures, constructors, and shims except // for a drop glue receive inline hint by default. // -// compile-flags: -Cno-prepopulate-passes -Zsymbol-mangling-version=v0 +// compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 #![crate_type = "lib"] pub fn f() { diff --git a/src/test/codegen/unwind-landingpad-cold.rs b/src/test/codegen/unwind-landingpad-cold.rs new file mode 100644 index 00000000000..650d5b230f4 --- /dev/null +++ b/src/test/codegen/unwind-landingpad-cold.rs @@ -0,0 +1,15 @@ +// no-system-llvm: needs #92110 +// compile-flags: -Cno-prepopulate-passes +#![crate_type = "lib"] + +// This test checks that drop calls in unwind landing pads +// get the `cold` attribute. + +// CHECK-LABEL: @check_cold +// CHECK: call void {{.+}}drop_in_place{{.+}} [[ATTRIBUTES:#[0-9]+]] +// CHECK: attributes [[ATTRIBUTES]] = { cold } +#[no_mangle] +pub fn check_cold(f: fn(), x: Box<u32>) { + // this may unwind + f(); +} diff --git a/src/test/codegen/unwind-landingpad-inline.rs b/src/test/codegen/unwind-landingpad-inline.rs new file mode 100644 index 00000000000..ce78d075dd0 --- /dev/null +++ b/src/test/codegen/unwind-landingpad-inline.rs @@ -0,0 +1,37 @@ +// no-system-llvm: needs #92110 + patch for Rust alloc/dealloc functions +// compile-flags: -Copt-level=3 +#![crate_type = "lib"] + +// This test checks that we can inline drop_in_place in +// unwind landing pads. + +// Without inlining, the box pointers escape via the call to drop_in_place, +// and LLVM will not optimize out the pointer comparison. +// With inlining, everything should be optimized out. +// See https://github.com/rust-lang/rust/issues/46515 +// CHECK-LABEL: @check_no_escape_in_landingpad +// CHECK: start: +// CHECK-NEXT: ret void +#[no_mangle] +pub fn check_no_escape_in_landingpad(f: fn()) { + let x = &*Box::new(0); + let y = &*Box::new(0); + + if x as *const _ == y as *const _ { + f(); + } +} + +// Without inlining, the compiler can't tell that +// dropping an empty string (in a landing pad) does nothing. +// With inlining, the landing pad should be optimized out. +// See https://github.com/rust-lang/rust/issues/87055 +// CHECK-LABEL: @check_eliminate_noop_drop +// CHECK: start: +// CHECK-NEXT: call void %g() +// CHECK-NEXT: ret void +#[no_mangle] +pub fn check_eliminate_noop_drop(g: fn()) { + let _var = String::new(); + g(); +} diff --git a/src/test/incremental/hashes/inline_asm.rs b/src/test/incremental/hashes/inline_asm.rs index a5d53258a7b..1ddb345e566 100644 --- a/src/test/incremental/hashes/inline_asm.rs +++ b/src/test/incremental/hashes/inline_asm.rs @@ -8,6 +8,7 @@ // build-pass (FIXME(62277): could be check-pass?) // revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6 // compile-flags: -Z query-dep-graph +// needs-asm-support // [cfail1]compile-flags: -Zincremental-ignore-spans // [cfail2]compile-flags: -Zincremental-ignore-spans // [cfail3]compile-flags: -Zincremental-ignore-spans diff --git a/src/test/incremental/issue-72386.rs b/src/test/incremental/issue-72386.rs index be624faad04..5917152e1bc 100644 --- a/src/test/incremental/issue-72386.rs +++ b/src/test/incremental/issue-72386.rs @@ -1,4 +1,5 @@ // revisions: rpass1 cfail1 rpass3 +// needs-asm-support // only-x86_64 // Regression test for issue #72386 // Checks that we don't ICE when switching to an invalid register diff --git a/src/test/incremental/issue-92163-missing-sourcefile/auxiliary/first_crate.rs b/src/test/incremental/issue-92163-missing-sourcefile/auxiliary/first_crate.rs new file mode 100644 index 00000000000..134afd4fbb1 --- /dev/null +++ b/src/test/incremental/issue-92163-missing-sourcefile/auxiliary/first_crate.rs @@ -0,0 +1,3 @@ +pub enum Foo { + Variant +} diff --git a/src/test/incremental/issue-92163-missing-sourcefile/auxiliary/second_crate.rs b/src/test/incremental/issue-92163-missing-sourcefile/auxiliary/second_crate.rs new file mode 100644 index 00000000000..ab7961f3823 --- /dev/null +++ b/src/test/incremental/issue-92163-missing-sourcefile/auxiliary/second_crate.rs @@ -0,0 +1,10 @@ +// compile-flags:--extern first_crate + +// Note: adding `first_crate` to the extern prelude +// (instead of using `extern_crate`) appears to be necessary to +// trigger the original incremental compilation bug. +// I'm not entirely sure why this is the case + +pub fn make_it() -> first_crate::Foo { + panic!() +} diff --git a/src/test/incremental/issue-92163-missing-sourcefile/issue_92163_main.rs b/src/test/incremental/issue-92163-missing-sourcefile/issue_92163_main.rs new file mode 100644 index 00000000000..e9219c6f5ab --- /dev/null +++ b/src/test/incremental/issue-92163-missing-sourcefile/issue_92163_main.rs @@ -0,0 +1,31 @@ +// aux-build:first_crate.rs +// aux-build:second_crate.rs +// revisions:rpass1 rpass2 + +// Regression test for issue #92163 +// Under certain circumstances, we may end up trying to +// decode a foreign `Span` from the incremental cache, without previously +// having imported the `SourceFile`s from the owning crate. This can happen +// if the `Span` comes from a transitive dependency (so we never try to resolve +// items from the crate during expansion/resolution). +// +// Previously, this would result in an ICE, since we would not have loaded +// the corresponding `SourceFile` for the `StableSourceFileId` we decoded. +// This test verifies that the decoding of a foreign `Span` will always +// try to import the `SourceFile`s from the foreign crate, instead of +// relying on that having already happened during expansion. + +extern crate second_crate; + +pub struct Outer; + +impl Outer { + pub fn use_it() { + // This returns `first_crate::Foo`, causing + // us to encode the `AdtDef `first_crate::Foo` (along with its `Span`s) + // into the query cache for the `TypeckResults` for this function. + second_crate::make_it(); + } +} + +fn main() {} diff --git a/src/test/pretty/nested-item-vis-defaultness.rs b/src/test/pretty/nested-item-vis-defaultness.rs index f46c0e3f1bc..b094ba577db 100644 --- a/src/test/pretty/nested-item-vis-defaultness.rs +++ b/src/test/pretty/nested-item-vis-defaultness.rs @@ -6,42 +6,42 @@ fn main() {} #[cfg(FALSE)] extern "C" { - static X: u8 ; + static X: u8; type X; fn foo(); - pub static X: u8 ; + pub static X: u8; pub type X; pub fn foo(); } #[cfg(FALSE)] trait T { - const X: u8 ; + const X: u8; type X; fn foo(); - default const X: u8 ; + default const X: u8; default type X; default fn foo(); - pub const X: u8 ; + pub const X: u8; pub type X; pub fn foo(); - pub default const X: u8 ; + pub default const X: u8; pub default type X; pub default fn foo(); } #[cfg(FALSE)] impl T for S { - const X: u8 ; + const X: u8; type X; fn foo(); - default const X: u8 ; + default const X: u8; default type X; default fn foo(); - pub const X: u8 ; + pub const X: u8; pub type X; pub fn foo(); - pub default const X: u8 ; + pub default const X: u8; pub default type X; pub default fn foo(); } diff --git a/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile b/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile index 54526e8ef23..4a9b3d70933 100644 --- a/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile +++ b/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile @@ -8,8 +8,8 @@ # and will probably get removed once `legacy` is gone. all: - $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z symbol-mangling-version=legacy - $(RUSTC) b.rs -C prefer-dynamic -Z symbol-mangling-version=legacy + $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy + $(RUSTC) b.rs -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy $(call RUN,b) - $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z symbol-mangling-version=legacy + $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy $(call FAIL,b) diff --git a/src/test/run-make-fulldeps/pointer-auth-link-with-c/Makefile b/src/test/run-make-fulldeps/pointer-auth-link-with-c/Makefile new file mode 100644 index 00000000000..d0e22cfef4c --- /dev/null +++ b/src/test/run-make-fulldeps/pointer-auth-link-with-c/Makefile @@ -0,0 +1,14 @@ +-include ../tools.mk + +# only-aarch64 + +all: + $(COMPILE_OBJ) $(TMPDIR)/test.o test.c + $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o + $(RUSTC) -Z branch-protection=bti,pac-ret,leaf test.rs + $(call RUN,test) + + $(COMPILE_OBJ) $(TMPDIR)/test.o test.c -mbranch-protection=bti+pac-ret+leaf + $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o + $(RUSTC) -Z branch-protection=bti,pac-ret,leaf test.rs + $(call RUN,test) diff --git a/src/test/run-make-fulldeps/pointer-auth-link-with-c/test.c b/src/test/run-make-fulldeps/pointer-auth-link-with-c/test.c new file mode 100644 index 00000000000..9fe07f82f9e --- /dev/null +++ b/src/test/run-make-fulldeps/pointer-auth-link-with-c/test.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/src/test/run-make-fulldeps/pointer-auth-link-with-c/test.rs b/src/test/run-make-fulldeps/pointer-auth-link-with-c/test.rs new file mode 100644 index 00000000000..615ad0aeb3d --- /dev/null +++ b/src/test/run-make-fulldeps/pointer-auth-link-with-c/test.rs @@ -0,0 +1,8 @@ +#[link(name = "test")] +extern "C" { + fn foo() -> i32; +} + +fn main() { + unsafe {foo();} +} diff --git a/src/test/run-make-fulldeps/share-generics-dylib/Makefile b/src/test/run-make-fulldeps/share-generics-dylib/Makefile index c6b5efcb4cd..282cb2461f6 100644 --- a/src/test/run-make-fulldeps/share-generics-dylib/Makefile +++ b/src/test/run-make-fulldeps/share-generics-dylib/Makefile @@ -11,7 +11,7 @@ -include ../../run-make-fulldeps/tools.mk -COMMON_ARGS=-Cprefer-dynamic -Zshare-generics=yes -Ccodegen-units=1 -Zsymbol-mangling-version=v0 +COMMON_ARGS=-Cprefer-dynamic -Zshare-generics=yes -Ccodegen-units=1 -Csymbol-mangling-version=v0 all: $(RUSTC) instance_provider_a.rs $(COMMON_ARGS) --crate-type=rlib diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml index 2216b3f1c97..ca60be72cea 100644 --- a/src/test/rustdoc-gui/anchors.goml +++ b/src/test/rustdoc-gui/anchors.goml @@ -12,7 +12,7 @@ reload: assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"}) assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"}) -assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 68, 142)"}) +assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"}) assert-css: (".srclink", {"color": "rgb(0, 0, 0)"}) assert-css: (".srclink", {"color": "rgb(0, 0, 0)"}) diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml index c9117e2c101..a64ac8b422f 100644 --- a/src/test/rustdoc-gui/font-weight.goml +++ b/src/test/rustdoc-gui/font-weight.goml @@ -37,8 +37,8 @@ assert-css: ( {"font-weight": "400"}, ) -assert-count: (".methods .type", 1) -assert-css: (".methods .type", {"font-weight": "600"}) +assert-count: (".methods .associatedtype", 1) +assert-css: (".methods .associatedtype", {"font-weight": "600"}) assert-count: (".methods .constant", 1) assert-css: (".methods .constant", {"font-weight": "600"}) assert-css: (".methods .method", {"font-weight": "600"}) diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index 471d88701d4..b370dd012fa 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -9,6 +9,16 @@ assert-attribute: (".top-doc", {"open": ""}) click: (3, 280) assert-attribute: (".top-doc", {"open": ""}) +// Assert the position of the toggle on the top doc block. +assert-position: (".top-doc summary::before", {"x": 4}) +// Assert the position of the toggle on the impl block. +assert-position: ("#implementations + details > summary::before", {"x": 4}) +// Assert the position of the toggle on a method. +assert-position: ( + "#trait-implementations-list .impl-items .method-toggle > summary::before", + {"x": 4}, +) + // Now we do the same but with a little bigger width size: (600, 600) assert-attribute: (".top-doc", {"open": ""}) diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs index 273fc62aa17..a409d64131a 100644 --- a/src/test/rustdoc/assoc-item-cast.rs +++ b/src/test/rustdoc/assoc-item-cast.rs @@ -1,6 +1,5 @@ #![crate_name = "foo"] - pub trait Expression { type SqlType; } @@ -11,5 +10,5 @@ pub trait AsExpression<T> { } // @has foo/type.AsExprOf.html -// @has - '//*[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;' +// @has - '//pre[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;' pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression; diff --git a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs index 4d25835bf08..db9adb4838e 100644 --- a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs +++ b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs @@ -6,9 +6,8 @@ pub trait MyTrait { fn defaulted_override(&self) {} } - impl MyTrait for String { - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1 type Assoc = (); // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE @@ -23,7 +22,7 @@ impl MyTrait for String { } impl MyTrait for Vec<u8> { - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2 type Assoc = (); // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE @@ -39,7 +38,7 @@ impl MyTrait for Vec<u8> { impl MyTrait for MyStruct { // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3 - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="associatedtype"]/@href' trait.MyTrait.html#associatedtype.Assoc // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc type Assoc = bool; // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3 diff --git a/src/test/rustdoc/where-clause-order.rs b/src/test/rustdoc/where-clause-order.rs new file mode 100644 index 00000000000..d0d89cbf126 --- /dev/null +++ b/src/test/rustdoc/where-clause-order.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +pub trait SomeTrait<Rhs = Self> +where Rhs: ?Sized +{} + +// @has 'foo/trait.SomeTrait.html' +// @has - "//div[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, " +impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where + A: PartialOrd<A> + PartialEq<A>, + B: PartialOrd<B> + PartialEq<B>, + C: PartialOrd<C> + PartialEq<C>, + D: PartialOrd<D> + PartialEq<D>, + E: PartialOrd<E> + PartialEq<E> + ?Sized +{} diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr index 4fc336122fa..01f800811ab 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr @@ -10,6 +10,9 @@ LL | (a, b) | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant + = note: the struct Type<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/project-fn-ret-invariant.rs:56:5 @@ -23,6 +26,9 @@ LL | (a, b) | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant + = note: the struct Type<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'a` and `'b` must be the same: replace one with the other diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr index 44850df7b2f..e925a424c37 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr @@ -10,6 +10,9 @@ LL | let a = bar(f, x); | ^^^^^^^^^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant + = note: the struct Type<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/project-fn-ret-invariant.rs:40:13 @@ -23,6 +26,9 @@ LL | let b = bar(f, y); | ^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant + = note: the struct Type<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'a` and `'b` must be the same: replace one with the other diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr index c417cdd543e..0457f142e19 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr @@ -6,6 +6,10 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { ... LL | bar(foo, x) | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type Type<'_>, which makes the generic argument '_ invariant + = note: the struct Type<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index cf73403bbae..4b03fe15494 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -7,6 +7,10 @@ LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f | lifetime `'f` defined here LL | ap | ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 @@ -17,6 +21,10 @@ LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f | lifetime `'f` defined here LL | ap | ^^ returning this value requires that `'1` must outlive `'f` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:14:5 @@ -25,6 +33,10 @@ LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'stati | -- has type `VaListImpl<'1>` LL | ap | ^^ returning this value requires that `'1` must outlive `'static` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:18:31 @@ -44,6 +56,10 @@ LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 @@ -54,6 +70,10 @@ LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'2` must outlive `'1` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 @@ -106,6 +126,10 @@ LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:35:12 @@ -116,6 +140,10 @@ LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` + | + = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant + = note: the struct VaListImpl<'f> is invariant over the parameter 'f + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to 11 previous errors diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs new file mode 100644 index 00000000000..1d7fa788534 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs @@ -0,0 +1,3 @@ +// compile-flags: --cfg ) +// error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr new file mode 100644 index 00000000000..7bb1814127b --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr @@ -0,0 +1,2 @@ +error: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) + diff --git a/src/test/ui/consts/invalid-union.32bit.stderr b/src/test/ui/consts/invalid-union.32bit.stderr new file mode 100644 index 00000000000..c8f9e570467 --- /dev/null +++ b/src/test/ui/consts/invalid-union.32bit.stderr @@ -0,0 +1,24 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/invalid-union.rs:41:1 + | +LL | fn main() { + | ^^^^^^^^^ type validation failed at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ╾─alloc7──╼ │ ╾──╼ + } + +error: erroneous constant used + --> $DIR/invalid-union.rs:42:25 + | +LL | let _: &'static _ = &C; + | ^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/invalid-union.64bit.stderr b/src/test/ui/consts/invalid-union.64bit.stderr new file mode 100644 index 00000000000..2ca54ccf9a0 --- /dev/null +++ b/src/test/ui/consts/invalid-union.64bit.stderr @@ -0,0 +1,24 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/invalid-union.rs:41:1 + | +LL | fn main() { + | ^^^^^^^^^ type validation failed at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + ╾───────alloc7────────╼ │ ╾──────╼ + } + +error: erroneous constant used + --> $DIR/invalid-union.rs:42:25 + | +LL | let _: &'static _ = &C; + | ^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/invalid-union.rs b/src/test/ui/consts/invalid-union.rs new file mode 100644 index 00000000000..1d5cc978a9e --- /dev/null +++ b/src/test/ui/consts/invalid-union.rs @@ -0,0 +1,44 @@ +// Check that constants with interior mutability inside unions are rejected +// during validation. +// +// Note that this test case relies on undefined behaviour to construct a +// constant with interior mutability that is "invisible" to the static checks. +// If for some reason this approach no longer works, it is should be fine to +// remove the test case. +// +// build-fail +// stderr-per-bitwidth +#![feature(const_mut_refs)] +#![feature(const_ptr_offset)] +#![feature(untagged_unions)] +use std::cell::Cell; + +#[repr(C)] +struct S { + x: u32, + y: E, +} + +#[repr(u32)] +enum E { + A, + B(U) +} + +union U { + cell: Cell<u32>, +} + +const C: S = { + let s = S { x: 0, y: E::A }; + // Go through an &u32 reference which is definitely not allowed to mutate anything. + let p = &s.x as *const u32 as *mut u32; + // Change enum tag to E::B. + unsafe { *p.add(1) = 1 }; + s +}; + +fn main() { //~ ERROR it is undefined behavior to use this value + let _: &'static _ = &C; //~ ERROR erroneous constant used + //~^ WARN this was previously accepted +} diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr index a5f7c390627..93b73c57e9b 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr @@ -2,7 +2,7 @@ error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:10 | LL | &0.. | _ => {} - | ^^^ help: add parentheses to clarify the precedence: `(0 ..)` + | ^^^ help: add parentheses to clarify the precedence: `(0..)` error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:10:11 @@ -16,7 +16,7 @@ error: the range pattern here has ambiguous interpretation --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:10:10 | LL | &0..= | _ => {} - | ^^^^ help: add parentheses to clarify the precedence: `(0 ..=)` + | ^^^^ help: add parentheses to clarify the precedence: `(0..=)` error[E0586]: inclusive range with no end --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:13:11 diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr index e25acebf7f6..b4c54d52e5c 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr @@ -13,6 +13,9 @@ LL | | fn(Inv<'y>)) } | |______________- in this macro invocation | = help: consider adding the following bound: `'x: 'y` + = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant + = note: the struct Inv<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error: lifetime may not live long enough @@ -30,6 +33,9 @@ LL | | fn(Inv<'y>)) } | |______________- in this macro invocation | = help: consider adding the following bound: `'x: 'y` + = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant + = note: the struct Inv<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs b/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs new file mode 100644 index 00000000000..4f39d223a2e --- /dev/null +++ b/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs @@ -0,0 +1 @@ +// compile-flags: -Z branch-protection=leaf diff --git a/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.stderr b/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.stderr new file mode 100644 index 00000000000..5528d2a0729 --- /dev/null +++ b/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.stderr @@ -0,0 +1,2 @@ +error: incorrect value `leaf` for debugging option `branch-protection` - a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf` was expected + diff --git a/src/test/ui/lifetimes/issue-84604.rs b/src/test/ui/lifetimes/issue-84604.rs index df8368da0a0..b315ef05190 100644 --- a/src/test/ui/lifetimes/issue-84604.rs +++ b/src/test/ui/lifetimes/issue-84604.rs @@ -1,5 +1,5 @@ // run-pass -// compile-flags: -Zsymbol-mangling-version=v0 +// compile-flags: -Csymbol-mangling-version=v0 pub fn f<T: ?Sized>() {} pub trait Frob<T: ?Sized> {} diff --git a/src/test/ui/link-section.rs b/src/test/ui/link-section.rs index 6958eeda697..48efb07ff48 100644 --- a/src/test/ui/link-section.rs +++ b/src/test/ui/link-section.rs @@ -31,7 +31,7 @@ static mut frobulator: usize = 0xdeadbeef; pub fn main() { unsafe { - frobulator = 0xcafebabe; + frobulator = 0x12345678; println!("{} {} {}", i_live_in_more_text(), magic, frobulator); } } diff --git a/src/test/ui/macros/concat-bytes-error.rs b/src/test/ui/macros/concat-bytes-error.rs index 9b4a9c2cf81..db5d3cab0bd 100644 --- a/src/test/ui/macros/concat-bytes-error.rs +++ b/src/test/ui/macros/concat-bytes-error.rs @@ -39,4 +39,12 @@ fn main() { ]); concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8` + concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number + concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number + concat_bytes!([pie; -2]); //~ ERROR repeat count is not a positive number + concat_bytes!([pie; 2]); //~ ERROR expected a byte literal + concat_bytes!([2.2; 0]); //~ ERROR cannot concatenate float literals + concat_bytes!([5.5; ()]); //~ ERROR repeat count is not a positive number + concat_bytes!([[1, 2, 3]; 3]); //~ ERROR cannot concatenate doubly nested array + concat_bytes!([[42; 2]; 3]); //~ ERROR cannot concatenate doubly nested array } diff --git a/src/test/ui/macros/concat-bytes-error.stderr b/src/test/ui/macros/concat-bytes-error.stderr index 1fc2d5c4843..d6cd1a3d178 100644 --- a/src/test/ui/macros/concat-bytes-error.stderr +++ b/src/test/ui/macros/concat-bytes-error.stderr @@ -127,5 +127,55 @@ error: numeric literal is not a `u8` LL | concat_bytes!([5u16]); | ^^^^ -error: aborting due to 20 previous errors +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:42:23 + | +LL | concat_bytes!([3; ()]); + | ^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:43:23 + | +LL | concat_bytes!([3; -2]); + | ^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:44:25 + | +LL | concat_bytes!([pie; -2]); + | ^^ + +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:45:20 + | +LL | concat_bytes!([pie; 2]); + | ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: cannot concatenate float literals + --> $DIR/concat-bytes-error.rs:46:20 + | +LL | concat_bytes!([2.2; 0]); + | ^^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:47:25 + | +LL | concat_bytes!([5.5; ()]); + | ^^ + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:48:20 + | +LL | concat_bytes!([[1, 2, 3]; 3]); + | ^^^^^^^^^ + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:49:20 + | +LL | concat_bytes!([[42; 2]; 3]); + | ^^^^^^^ + +error: aborting due to 28 previous errors diff --git a/src/test/ui/macros/concat-bytes.rs b/src/test/ui/macros/concat-bytes.rs index 5415cf3fe22..fd8f99417ec 100644 --- a/src/test/ui/macros/concat-bytes.rs +++ b/src/test/ui/macros/concat-bytes.rs @@ -3,5 +3,15 @@ fn main() { assert_eq!(concat_bytes!(), &[]); - assert_eq!(concat_bytes!(b'A', b"BC", [68, b'E', 70]), b"ABCDEF"); + assert_eq!( + concat_bytes!(b'A', b"BC", [68, b'E', 70], [b'G'; 1], [72; 2], [73u8; 3], [65; 0]), + b"ABCDEFGHHIII", + ); + assert_eq!( + concat_bytes!( + concat_bytes!(b"AB", b"CD"), + concat_bytes!(b"EF", b"GH"), + ), + b"ABCDEFGH", + ); } diff --git a/src/test/ui/macros/issue-92267.rs b/src/test/ui/macros/issue-92267.rs new file mode 100644 index 00000000000..f1daaeb743e --- /dev/null +++ b/src/test/ui/macros/issue-92267.rs @@ -0,0 +1,3 @@ +// check-fail + +pub fn main() { println!("🦀%%%", 0) } //~ ERROR argument never used diff --git a/src/test/ui/macros/issue-92267.stderr b/src/test/ui/macros/issue-92267.stderr new file mode 100644 index 00000000000..d2d66c81198 --- /dev/null +++ b/src/test/ui/macros/issue-92267.stderr @@ -0,0 +1,16 @@ +error: argument never used + --> $DIR/issue-92267.rs:3:34 + | +LL | pub fn main() { println!("🦀%%%", 0) } + | ^ argument never used + | +note: format specifiers use curly braces, and the conversion specifier ` + ` is unknown or unsupported + --> $DIR/issue-92267.rs:3:30 + | +LL | pub fn main() { println!("🦀%%%", 0) } + | ^^ + = note: printf formatting not supported; see the documentation for `std::fmt` + +error: aborting due to previous error + diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index c0a030a2ecb..90983f35a5e 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -256,7 +256,7 @@ fn test_expr() { assert_eq!(stringify_expr!(expr.await), "expr.await"); // ExprKind::TryBlock - assert_eq!(stringify_expr!(try {}), "try {}"); // FIXME + assert_eq!(stringify_expr!(try {}), "try {}"); // ExprKind::Assign assert_eq!(stringify_expr!(expr = true), "expr = true"); @@ -382,13 +382,13 @@ fn test_item() { stringify_item!( static S: (); ), - "static S: () ;", // FIXME + "static S: ();", ); assert_eq!( stringify_item!( static mut S: (); ), - "static mut S: () ;", + "static mut S: ();", ); // ItemKind::Const @@ -402,7 +402,7 @@ fn test_item() { stringify_item!( const S: (); ), - "const S: () ;", // FIXME + "const S: ();", ); // ItemKind::Fn @@ -712,10 +712,10 @@ fn test_pat() { // PatKind::Range assert_eq!(stringify_pat!(..1), "..1"); - assert_eq!(stringify_pat!(0..), "0 .."); // FIXME - assert_eq!(stringify_pat!(0..1), "0 ..1"); - assert_eq!(stringify_pat!(0..=1), "0 ..=1"); - assert_eq!(stringify_pat!(-2..=-1), "-2 ..=-1"); + assert_eq!(stringify_pat!(0..), "0.."); + assert_eq!(stringify_pat!(0..1), "0..1"); + assert_eq!(stringify_pat!(0..=1), "0..=1"); + assert_eq!(stringify_pat!(-2..=-1), "-2..=-1"); // PatKind::Slice assert_eq!(stringify_pat!([]), "[]"); diff --git a/src/test/ui/match/expr_before_ident_pat.stderr b/src/test/ui/match/expr_before_ident_pat.stderr index 1ac8274ffd5..2bd1b3b9454 100644 --- a/src/test/ui/match/expr_before_ident_pat.stderr +++ b/src/test/ui/match/expr_before_ident_pat.stderr @@ -1,14 +1,14 @@ -error: arbitrary expressions aren't allowed in patterns +error[E0425]: cannot find value `a` in this scope --> $DIR/expr_before_ident_pat.rs:12:12 | LL | funny!(a, a); - | ^ + | ^ not found in this scope -error[E0425]: cannot find value `a` in this scope +error: arbitrary expressions aren't allowed in patterns --> $DIR/expr_before_ident_pat.rs:12:12 | LL | funny!(a, a); - | ^ not found in this scope + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index d77793291c5..cf563072dff 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -51,6 +51,10 @@ LL | | }); | | | | |______`cell_a` escapes the function body here | argument requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type Cell<&'_#10r u32>, which makes the generic argument &'_#10r u32 invariant + = note: the struct Cell<T> is invariant over the parameter T + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index cc67270ad20..453f6801d7e 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -51,6 +51,10 @@ LL | | }); | | | | |______`cell_a` escapes the function body here | argument requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type Cell<&'_#11r u32>, which makes the generic argument &'_#11r u32 invariant + = note: the struct Cell<T> is invariant over the parameter T + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/nll/where_clauses_in_structs.stderr b/src/test/ui/nll/where_clauses_in_structs.stderr index 8499b00f6f5..952667d518d 100644 --- a/src/test/ui/nll/where_clauses_in_structs.stderr +++ b/src/test/ui/nll/where_clauses_in_structs.stderr @@ -9,6 +9,9 @@ LL | Foo { x, y }; | ^ this usage requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type Cell<&u32>, which makes the generic argument &u32 invariant + = note: the struct Cell<T> is invariant over the parameter T + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/no-link.rs b/src/test/ui/no-link.rs index 939271832e3..c80e61b4511 100644 --- a/src/test/ui/no-link.rs +++ b/src/test/ui/no-link.rs @@ -1,8 +1,9 @@ +// check-pass // aux-build:empty-struct.rs #[no_link] extern crate empty_struct; fn main() { - empty_struct::XEmpty1; //~ ERROR cannot find value `XEmpty1` in crate `empty_struct` + empty_struct::XEmpty1 {}; } diff --git a/src/test/ui/no-link.stderr b/src/test/ui/no-link.stderr deleted file mode 100644 index 66a74ff6560..00000000000 --- a/src/test/ui/no-link.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0425]: cannot find value `XEmpty1` in crate `empty_struct` - --> $DIR/no-link.rs:7:19 - | -LL | empty_struct::XEmpty1; - | ^^^^^^^ not found in `empty_struct` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/panics/issue-47429-short-backtraces.rs b/src/test/ui/panics/issue-47429-short-backtraces.rs index 35ecfc0b271..c34e00bab7c 100644 --- a/src/test/ui/panics/issue-47429-short-backtraces.rs +++ b/src/test/ui/panics/issue-47429-short-backtraces.rs @@ -14,8 +14,8 @@ // NOTE(eddyb) output differs between symbol mangling schemes // revisions: legacy v0 -// [legacy] compile-flags: -Zsymbol-mangling-version=legacy -// [v0] compile-flags: -Zsymbol-mangling-version=v0 +// [legacy] compile-flags: -Zunstable-options -Csymbol-mangling-version=legacy +// [v0] compile-flags: -Csymbol-mangling-version=v0 fn main() { panic!() diff --git a/src/test/ui/parser/intersection-patterns.rs b/src/test/ui/parser/intersection-patterns.rs index adb607cf6b9..a6d27aab4f6 100644 --- a/src/test/ui/parser/intersection-patterns.rs +++ b/src/test/ui/parser/intersection-patterns.rs @@ -34,7 +34,7 @@ fn main() { //~| pattern on the left, should be on the right //~| binding on the right, should be on the left //~| HELP switch the order - //~| SUGGESTION e @ 1 ..=5 + //~| SUGGESTION e @ 1..=5 _ => {} } } diff --git a/src/test/ui/parser/intersection-patterns.stderr b/src/test/ui/parser/intersection-patterns.stderr index f5bfee5bbd6..9dc4c469a60 100644 --- a/src/test/ui/parser/intersection-patterns.stderr +++ b/src/test/ui/parser/intersection-patterns.stderr @@ -27,7 +27,7 @@ LL | 1 ..= 5 @ e => {} | | | | | binding on the right, should be on the left | pattern on the left, should be on the right - | help: switch the order: `e @ 1 ..=5` + | help: switch the order: `e @ 1..=5` error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/issue-92074-macro-ice.rs b/src/test/ui/pattern/issue-92074-macro-ice.rs new file mode 100644 index 00000000000..039d3b31444 --- /dev/null +++ b/src/test/ui/pattern/issue-92074-macro-ice.rs @@ -0,0 +1,36 @@ +pub enum En { + A(Vec<u8>) +} + +fn get_usize() -> usize { + 0 +} + +macro_rules! force_expr { + ($e:expr) => { $e } +} + +macro_rules! force_pat { + ($a:expr, $b:expr) => { $a..=$b } +} + +macro_rules! make_vec { + () => { force_expr!(Vec::new()) } //~ ERROR arbitrary expressions aren't allowed +} + +macro_rules! make_pat { + () => { force_pat!(get_usize(), get_usize()) } + //~^ ERROR arbitrary expressions aren't allowed + //~| ERROR arbitrary expressions aren't allowed +} + +#[allow(unreachable_code)] +fn f() -> Result<(), impl core::fmt::Debug> { + let x: En = loop {}; + + assert!(matches!(x, En::A(make_vec!()))); + assert!(matches!(5, make_pat!())); + Ok::<(), &'static str>(()) +} + +fn main() {} diff --git a/src/test/ui/pattern/issue-92074-macro-ice.stderr b/src/test/ui/pattern/issue-92074-macro-ice.stderr new file mode 100644 index 00000000000..b340afff010 --- /dev/null +++ b/src/test/ui/pattern/issue-92074-macro-ice.stderr @@ -0,0 +1,35 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/issue-92074-macro-ice.rs:18:25 + | +LL | () => { force_expr!(Vec::new()) } + | ^^^^^^^^^^ +... +LL | assert!(matches!(x, En::A(make_vec!()))); + | ----------- in this macro invocation + | + = note: this error originates in the macro `make_vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/issue-92074-macro-ice.rs:22:24 + | +LL | () => { force_pat!(get_usize(), get_usize()) } + | ^^^^^^^^^^^ +... +LL | assert!(matches!(5, make_pat!())); + | ----------- in this macro invocation + | + = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/issue-92074-macro-ice.rs:22:37 + | +LL | () => { force_pat!(get_usize(), get_usize()) } + | ^^^^^^^^^^^ +... +LL | assert!(matches!(5, make_pat!())); + | ----------- in this macro invocation + | + = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/polymorphization/closure_in_upvar/fn.rs b/src/test/ui/polymorphization/closure_in_upvar/fn.rs index b0b39dbd3df..e1030858814 100644 --- a/src/test/ui/polymorphization/closure_in_upvar/fn.rs +++ b/src/test/ui/polymorphization/closure_in_upvar/fn.rs @@ -1,5 +1,5 @@ // build-pass -// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 +// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0 fn foo(f: impl Fn()) { let x = |_: ()| (); diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs index ba75f6c5a10..62164ff9485 100644 --- a/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs +++ b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs @@ -1,5 +1,5 @@ // build-pass -// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 +// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0 fn foo(f: impl Fn()) { // Mutate an upvar from `x` so that it implements `FnMut`. diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs index e9761ad0bcb..7a364882fb8 100644 --- a/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs +++ b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs @@ -1,5 +1,5 @@ // build-pass -// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 +// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0 fn foo(f: impl Fn()) { // Move a non-copy type into `x` so that it implements `FnOnce`. diff --git a/src/test/ui/polymorphization/closure_in_upvar/other.rs b/src/test/ui/polymorphization/closure_in_upvar/other.rs index 7614aa83fcd..27d59ec8899 100644 --- a/src/test/ui/polymorphization/closure_in_upvar/other.rs +++ b/src/test/ui/polymorphization/closure_in_upvar/other.rs @@ -1,5 +1,5 @@ // build-pass -// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0 +// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0 fn y_uses_f(f: impl Fn()) { let x = |_: ()| (); diff --git a/src/test/ui/polymorphization/symbol-ambiguity.rs b/src/test/ui/polymorphization/symbol-ambiguity.rs index d97bae183d9..6277a902fa2 100644 --- a/src/test/ui/polymorphization/symbol-ambiguity.rs +++ b/src/test/ui/polymorphization/symbol-ambiguity.rs @@ -1,5 +1,5 @@ // build-pass -// compile-flags: -Zpolymorphize=on -Zsymbol-mangling-version=v0 +// compile-flags: -Zpolymorphize=on -Csymbol-mangling-version=v0 pub(crate) struct Foo<'a, I, E>(I, &'a E); diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.fixed b/src/test/ui/range/range-inclusive-pattern-precedence.fixed index 8a4b8fc38e3..38104bab7c8 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.fixed +++ b/src/test/ui/range/range-inclusive-pattern-precedence.fixed @@ -12,7 +12,7 @@ pub fn main() { //~^ WARN `...` range patterns are deprecated //~| WARN this is accepted in the current edition //~| HELP use `..=` for an inclusive range - &(10 ..=15) => {} + &(10..=15) => {} //~^ ERROR the range pattern here has ambiguous interpretation //~| HELP add parentheses to clarify the precedence &(16..=20) => {} diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr index 8af1a570253..10513374cf8 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr @@ -2,7 +2,7 @@ error: the range pattern here has ambiguous interpretation --> $DIR/range-inclusive-pattern-precedence.rs:15:10 | LL | &10..=15 => {} - | ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)` + | ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)` warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence.rs:11:9 diff --git a/src/test/ui/range/range-inclusive-pattern-precedence2.stderr b/src/test/ui/range/range-inclusive-pattern-precedence2.stderr index 009273c7435..cdec41d7f75 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence2.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence2.stderr @@ -2,7 +2,7 @@ error: the range pattern here has ambiguous interpretation --> $DIR/range-inclusive-pattern-precedence2.rs:14:13 | LL | box 10..=15 => {} - | ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)` + | ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)` warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence2.rs:10:14 diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr index e220cbf5559..376534bf573 100644 --- a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr +++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr @@ -11,6 +11,10 @@ LL | x.unwrap() | | | `x` escapes the function body here | argument requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant + = note: the struct Invariant<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr index 47796e50a88..32f3080ea37 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr @@ -10,6 +10,9 @@ LL | a.bigger_region(b) | ^^^^^^^^^^^^^^^^^^ argument requires that `'y` must outlive `'x` | = help: consider adding the following bound: `'y: 'x` + = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant + = note: the struct Inv<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr index 83d6e13dc0a..62032bcb609 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr @@ -15,6 +15,9 @@ LL | f.method(b); | argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant + = note: the struct Inv<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr index 0c1e3989b23..fede5f2d779 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr @@ -5,6 +5,10 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + | + = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant + = note: the struct Invariant<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr index 0edeb272399..8f5f3667453 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr @@ -5,6 +5,10 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + | + = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant + = note: the struct Invariant<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr index 724dd7e3f6d..8079fb0ef0d 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr @@ -5,6 +5,10 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` + | + = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant + = note: the struct Invariant<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-not-param.nll.stderr b/src/test/ui/regions/regions-infer-not-param.nll.stderr index fcc2ec31f3e..e211f9d1391 100644 --- a/src/test/ui/regions/regions-infer-not-param.nll.stderr +++ b/src/test/ui/regions/regions-infer-not-param.nll.stderr @@ -17,6 +17,9 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | lifetime `'a` defined here | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type Indirect2<'_>, which makes the generic argument '_ invariant + = note: the struct Indirect2<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/regions-infer-not-param.rs:19:63 @@ -27,6 +30,9 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p } | lifetime `'a` defined here | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type Indirect2<'_>, which makes the generic argument '_ invariant + = note: the struct Indirect2<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'b` and `'a` must be the same: replace one with the other diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr index d51db99f81f..8e8ca8e47cc 100644 --- a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr +++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr @@ -10,6 +10,9 @@ LL | let _: Invariant<'short> = c; | ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` | = help: consider adding the following bound: `'short: 'long` + = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant + = note: the struct Invariant<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr index 15853e6ca5d..f9a3d727f7a 100644 --- a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr +++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr @@ -6,6 +6,10 @@ LL | fn use_<'b>(c: Invariant<'b>) { ... LL | let _: Invariant<'static> = c; | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static` + | + = note: requirement occurs because of the type Invariant<'_>, which makes the generic argument '_ invariant + = note: the struct Invariant<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/suggestions/while-let-typo.rs b/src/test/ui/suggestions/while-let-typo.rs new file mode 100644 index 00000000000..dbbcdee3c19 --- /dev/null +++ b/src/test/ui/suggestions/while-let-typo.rs @@ -0,0 +1,9 @@ +fn main() { + let foo = Some(0); + let bar = None; + while Some(x) = foo {} //~ ERROR cannot find value `x` in this scope + while Some(foo) = bar {} + while 3 = foo {} //~ ERROR mismatched types + while Some(3) = foo {} //~ ERROR invalid left-hand side of assignment + while x = 5 {} //~ ERROR cannot find value `x` in this scope +} diff --git a/src/test/ui/suggestions/while-let-typo.stderr b/src/test/ui/suggestions/while-let-typo.stderr new file mode 100644 index 00000000000..7cc2ed3149b --- /dev/null +++ b/src/test/ui/suggestions/while-let-typo.stderr @@ -0,0 +1,45 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/while-let-typo.rs:4:16 + | +LL | while Some(x) = foo {} + | ^ not found in this scope + | +help: you might have meant to use pattern matching + | +LL | while let Some(x) = foo {} + | +++ + +error[E0425]: cannot find value `x` in this scope + --> $DIR/while-let-typo.rs:8:11 + | +LL | while x = 5 {} + | ^ not found in this scope + | +help: you might have meant to use pattern matching + | +LL | while let x = 5 {} + | +++ + +error[E0308]: mismatched types + --> $DIR/while-let-typo.rs:6:11 + | +LL | while 3 = foo {} + | ^^^^^^^ expected `bool`, found `()` + +error[E0070]: invalid left-hand side of assignment + --> $DIR/while-let-typo.rs:7:19 + | +LL | while Some(3) = foo {} + | - ^ + | | + | cannot assign to this expression + | +help: you might have meant to use pattern destructuring + | +LL | while let Some(3) = foo {} + | +++ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0070, E0308, E0425. +For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs index a6fbe98e6ed..65a63262810 100644 --- a/src/test/ui/symbol-names/basic.rs +++ b/src/test/ui/symbol-names/basic.rs @@ -1,7 +1,7 @@ // build-fail // revisions: legacy v0 -//[legacy]compile-flags: -Z symbol-mangling-version=legacy - //[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy + //[v0]compile-flags: -C symbol-mangling-version=v0 #![feature(rustc_attrs)] diff --git a/src/test/ui/symbol-names/const-generics-demangling.rs b/src/test/ui/symbol-names/const-generics-demangling.rs index d44c8f0abae..5c40c391a9e 100644 --- a/src/test/ui/symbol-names/const-generics-demangling.rs +++ b/src/test/ui/symbol-names/const-generics-demangling.rs @@ -1,5 +1,5 @@ // build-fail -// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c +// compile-flags: -C symbol-mangling-version=v0 --crate-name=c // normalize-stderr-test: "c\[.*?\]" -> "c[HASH]" #![feature(rustc_attrs)] diff --git a/src/test/ui/symbol-names/const-generics-str-demangling.rs b/src/test/ui/symbol-names/const-generics-str-demangling.rs index 300f6510380..619b34f2559 100644 --- a/src/test/ui/symbol-names/const-generics-str-demangling.rs +++ b/src/test/ui/symbol-names/const-generics-str-demangling.rs @@ -1,5 +1,5 @@ // build-fail -// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c +// compile-flags: -C symbol-mangling-version=v0 --crate-name=c // normalize-stderr-test: "c\[.*?\]" -> "c[HASH]" #![feature(adt_const_params, rustc_attrs)] #![allow(incomplete_features)] diff --git a/src/test/ui/symbol-names/const-generics-structural-demangling.rs b/src/test/ui/symbol-names/const-generics-structural-demangling.rs index 73de48fed6c..df09ba494a7 100644 --- a/src/test/ui/symbol-names/const-generics-structural-demangling.rs +++ b/src/test/ui/symbol-names/const-generics-structural-demangling.rs @@ -1,5 +1,5 @@ // build-fail -// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c +// compile-flags: -C symbol-mangling-version=v0 --crate-name=c // NOTE(eddyb) we need `core` for `core::option::Option`, normalize away its // disambiguator hash, which can/should change (including between stage{1,2}). diff --git a/src/test/ui/symbol-names/const-generics.rs b/src/test/ui/symbol-names/const-generics.rs index 2d136e6a99a..1242126e0cc 100644 --- a/src/test/ui/symbol-names/const-generics.rs +++ b/src/test/ui/symbol-names/const-generics.rs @@ -1,7 +1,7 @@ // check-pass // revisions: legacy v0 -//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib -//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib +//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy --crate-type=lib +//[v0]compile-flags: -C symbol-mangling-version=v0 --crate-type=lib // `char` pub struct Char<const F: char>; diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index f20cb1c01fd..86f0a8b0bef 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -1,7 +1,7 @@ // build-fail // revisions: legacy v0 -//[legacy]compile-flags: -Z symbol-mangling-version=legacy - //[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy + //[v0]compile-flags: -C symbol-mangling-version=v0 //[legacy]normalize-stderr-test: "h[\w]{16}E?\)" -> "<SYMBOL_HASH>)" #![feature(auto_traits, rustc_attrs)] diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index 57114ca1f15..ab0a3a7df1d 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -1,7 +1,7 @@ // build-fail // revisions: legacy v0 -//[legacy]compile-flags: -Z symbol-mangling-version=legacy - //[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy + //[v0]compile-flags: -C symbol-mangling-version=v0 #![feature(rustc_attrs)] diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs index d1bc152af5c..4a1f5a21263 100644 --- a/src/test/ui/symbol-names/issue-75326.rs +++ b/src/test/ui/symbol-names/issue-75326.rs @@ -1,7 +1,7 @@ // build-fail // revisions: legacy v0 -//[legacy]compile-flags: -Z symbol-mangling-version=legacy -//[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy +//[v0]compile-flags: -C symbol-mangling-version=v0 //[legacy]normalize-stderr-test: "h[\w{16}]+" -> "SYMBOL_HASH" #![feature(rustc_attrs)] diff --git a/src/test/ui/symbol-names/issue-76365.rs b/src/test/ui/symbol-names/issue-76365.rs index c2e9f92f7b5..932057b6590 100644 --- a/src/test/ui/symbol-names/issue-76365.rs +++ b/src/test/ui/symbol-names/issue-76365.rs @@ -1,7 +1,7 @@ // check-pass // revisions: legacy v0 -//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib -//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib +//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy --crate-type=lib +//[v0]compile-flags: -C symbol-mangling-version=v0 --crate-type=lib pub struct Bar<const F: bool>; diff --git a/src/test/ui/symbol-names/trait-objects.rs b/src/test/ui/symbol-names/trait-objects.rs index 502afebcb5a..5bcbc08413f 100644 --- a/src/test/ui/symbol-names/trait-objects.rs +++ b/src/test/ui/symbol-names/trait-objects.rs @@ -2,7 +2,7 @@ // build-fail // revisions: v0 -//[v0]compile-flags: -Z symbol-mangling-version=v0 +//[v0]compile-flags: -C symbol-mangling-version=v0 //[v0]normalize-stderr-test: "core\[.*?\]" -> "core[HASH]" #![feature(rustc_attrs)] diff --git a/src/test/ui/traits/issue-92292.rs b/src/test/ui/traits/issue-92292.rs new file mode 100644 index 00000000000..bb3700a2b5e --- /dev/null +++ b/src/test/ui/traits/issue-92292.rs @@ -0,0 +1,32 @@ +// check-pass + +use std::marker::PhantomData; + +pub struct MyGenericType<T> { + _marker: PhantomData<*const T>, +} + +pub struct MyNonGenericType; + +impl<T> From<MyGenericType<T>> for MyNonGenericType { + fn from(_: MyGenericType<T>) -> Self { + todo!() + } +} + +pub trait MyTrait { + const MY_CONSTANT: i32; +} + +impl<T> MyTrait for MyGenericType<T> +where + Self: Into<MyNonGenericType>, +{ + const MY_CONSTANT: i32 = 1; +} + +impl<T> MyGenericType<T> { + const MY_OTHER_CONSTANT: i32 = <MyGenericType<T> as MyTrait>::MY_CONSTANT; +} + +fn main() {} diff --git a/src/test/ui/unpretty-expr-fn-arg.stdout b/src/test/ui/unpretty-expr-fn-arg.stdout index cb04dfead73..b745b988631 100644 --- a/src/test/ui/unpretty-expr-fn-arg.stdout +++ b/src/test/ui/unpretty-expr-fn-arg.stdout @@ -14,4 +14,4 @@ extern crate std; fn main() ({ } as ()) -fn foo((-(128 as i8) as i8) ...(127 as i8): i8) ({ } as ()) +fn foo((-(128 as i8) as i8)...(127 as i8): i8) ({ } as ()) diff --git a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr index 1f06949c033..867d9f8238a 100644 --- a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr +++ b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr @@ -5,6 +5,10 @@ LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, & | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:7:5 @@ -13,6 +17,10 @@ LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, ( | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, (), &()>, which makes the generic argument () invariant + = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:10:5 @@ -21,6 +29,10 @@ LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, & | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:13:5 @@ -29,6 +41,10 @@ LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, ( | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::IterMut<'_, (), &()>, which makes the generic argument () invariant + = note: the struct std::collections::btree_map::IterMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:17:5 @@ -37,6 +53,10 @@ LL | fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type RangeMut<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct RangeMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:20:5 @@ -45,6 +65,10 @@ LL | fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type RangeMut<'_, (), &()>, which makes the generic argument () invariant + = note: the struct RangeMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:23:5 @@ -53,6 +77,10 @@ LL | fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type RangeMut<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct RangeMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:26:5 @@ -61,6 +89,10 @@ LL | fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type RangeMut<'_, (), &()>, which makes the generic argument () invariant + = note: the struct RangeMut<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:31:5 @@ -70,6 +102,10 @@ LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) LL | -> OccupiedEntry<'a, &'new (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:35:5 @@ -79,6 +115,10 @@ LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) LL | -> OccupiedEntry<'a, (), &'new ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, (), &()>, which makes the generic argument () invariant + = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:39:5 @@ -88,6 +128,10 @@ LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) LL | -> OccupiedEntry<'a, &'static (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:43:5 @@ -97,6 +141,10 @@ LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) LL | -> OccupiedEntry<'a, (), &'static ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::OccupiedEntry<'_, (), &()>, which makes the generic argument () invariant + = note: the struct std::collections::btree_map::OccupiedEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:48:5 @@ -106,6 +154,10 @@ LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) LL | -> VacantEntry<'a, &'new (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:52:5 @@ -115,6 +167,10 @@ LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) LL | -> VacantEntry<'a, (), &'new ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, (), &()>, which makes the generic argument () invariant + = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:56:5 @@ -124,6 +180,10 @@ LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) LL | -> VacantEntry<'a, &'static (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, &(), ()>, which makes the generic argument &() invariant + = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:60:5 @@ -133,6 +193,10 @@ LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) LL | -> VacantEntry<'a, (), &'static ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type std::collections::btree_map::VacantEntry<'_, (), &()>, which makes the generic argument () invariant + = note: the struct std::collections::btree_map::VacantEntry<'a, K, V> is invariant over the parameter K + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to 16 previous errors diff --git a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr index 1fcdfc4b5bb..d6a85680141 100644 --- a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr +++ b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr @@ -10,6 +10,9 @@ LL | let _: Foo<'long> = c; | ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` | = help: consider adding the following bound: `'short: 'long` + = note: requirement occurs because of the type Foo<'_>, which makes the generic argument '_ invariant + = note: the struct Foo<'a> is invariant over the parameter 'a + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr index 385d83adaf8..6890cb115c3 100644 --- a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr +++ b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr @@ -10,6 +10,9 @@ LL | v | ^ returning this value requires that `'min` must outlive `'max` | = help: consider adding the following bound: `'min: 'max` + = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant + = note: the struct SomeStruct<T> is invariant over the parameter T + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variance-use-invariant-struct-1.rs:19:5 @@ -23,6 +26,9 @@ LL | v | ^ returning this value requires that `'min` must outlive `'max` | = help: consider adding the following bound: `'min: 'max` + = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant + = note: the struct SomeStruct<T> is invariant over the parameter T + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to 2 previous errors diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml index 0339de77f3c..3d8c39408a9 100644 --- a/src/tools/clippy/.github/workflows/clippy.yml +++ b/src/tools/clippy/.github/workflows/clippy.yml @@ -58,6 +58,10 @@ jobs: run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint working-directory: clippy_lints + - name: Test clippy_utils + run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint + working-directory: clippy_utils + - name: Test rustc_tools_util run: cargo test --features deny-warnings working-directory: rustc_tools_util diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 1f4d666c7a9..8b644aa2817 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -121,6 +121,10 @@ jobs: run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint working-directory: clippy_lints + - name: Test clippy_utils + run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint + working-directory: clippy_utils + - name: Test rustc_tools_util run: cargo test --features deny-warnings working-directory: rustc_tools_util diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 7b5279cda6e..27bac4718b6 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,13 +6,127 @@ document. ## Unreleased / In Rust Nightly -[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master) +[e181011...master](https://github.com/rust-lang/rust-clippy/compare/e181011...master) + +## Rust 1.58 (beta) + +Current beta, release 2022-01-13 + +[00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011) + +### New lints + +* [`transmute_num_to_bytes`] + [#7805](https://github.com/rust-lang/rust-clippy/pull/7805) +* [`match_str_case_mismatch`] + [#7806](https://github.com/rust-lang/rust-clippy/pull/7806) +* [`format_in_format_args`], [`to_string_in_format_args`] + [#7743](https://github.com/rust-lang/rust-clippy/pull/7743) +* [`uninit_vec`] + [#7682](https://github.com/rust-lang/rust-clippy/pull/7682) +* [`fn_to_numeric_cast_any`] + [#7705](https://github.com/rust-lang/rust-clippy/pull/7705) +* [`undocumented_unsafe_blocks`] + [#7748](https://github.com/rust-lang/rust-clippy/pull/7748) +* [`trailing_empty_array`] + [#7838](https://github.com/rust-lang/rust-clippy/pull/7838) +* [`string_slice`] + [#7878](https://github.com/rust-lang/rust-clippy/pull/7878) + +### Moves or deprecations of lints + +* Move [`non_send_fields_in_send_ty`] to `suspicious` + [#7874](https://github.com/rust-lang/rust-clippy/pull/7874) +* Move [`non_ascii_literal`] to `restriction` + [#7907](https://github.com/rust-lang/rust-clippy/pull/7907) + +### Changes that expand what code existing lints cover + +* [`question_mark`] now covers `Result` + [#7840](https://github.com/rust-lang/rust-clippy/pull/7840) +* Make [`useless_format`] recognize bare `format!("")` + [#7801](https://github.com/rust-lang/rust-clippy/pull/7801) +* Lint on underscored variables with no side effects in [`no_effect`] + [#7775](https://github.com/rust-lang/rust-clippy/pull/7775) +* Expand [`match_ref_pats`] to check for multiple reference patterns + [#7800](https://github.com/rust-lang/rust-clippy/pull/7800) + +### False positive fixes + +* Fix false positive of [`implicit_saturating_sub`] with `else` clause + [#7832](https://github.com/rust-lang/rust-clippy/pull/7832) +* Fix [`question_mark`] when there is call in conditional predicate + [#7860](https://github.com/rust-lang/rust-clippy/pull/7860) +* [`mut_mut`] no longer lints when type is defined in external macros + [#7795](https://github.com/rust-lang/rust-clippy/pull/7795) +* Avoid [`eq_op`] in test functions + [#7811](https://github.com/rust-lang/rust-clippy/pull/7811) +* [`cast_possible_truncation`] no longer lints when cast is coming from `signum` + method call [#7850](https://github.com/rust-lang/rust-clippy/pull/7850) +* [`match_str_case_mismatch`] no longer lints on uncased characters + [#7865](https://github.com/rust-lang/rust-clippy/pull/7865) +* [`ptr_arg`] no longer lints references to type aliases + [#7890](https://github.com/rust-lang/rust-clippy/pull/7890) +* [`missing_safety_doc`] now also accepts "implementation safety" headers + [#7856](https://github.com/rust-lang/rust-clippy/pull/7856) +* [`missing_safety_doc`] no longer lints if any parent has `#[doc(hidden)]` + attribute [#7849](https://github.com/rust-lang/rust-clippy/pull/7849) +* [`if_not_else`] now ignores else-if statements + [#7895](https://github.com/rust-lang/rust-clippy/pull/7895) +* Avoid linting [`cast_possible_truncation`] on bit-reducing operations + [#7819](https://github.com/rust-lang/rust-clippy/pull/7819) +* Avoid linting [`field_reassign_with_default`] when `Drop` and `Copy` are + involved [#7794](https://github.com/rust-lang/rust-clippy/pull/7794) +* [`unnecessary_sort_by`] now checks if argument implements `Ord` trait + [#7824](https://github.com/rust-lang/rust-clippy/pull/7824) +* Fix false positive in [`match_overlapping_arm`] + [#7847](https://github.com/rust-lang/rust-clippy/pull/7847) +* Prevent [`needless_lifetimes`] false positive in `async` function definition + [#7901](https://github.com/rust-lang/rust-clippy/pull/7901) + +### Suggestion fixes/improvements + +* Keep an initial `::` when [`doc_markdown`] suggests to use ticks + [#7916](https://github.com/rust-lang/rust-clippy/pull/7916) +* Add a machine applicable suggestion for the [`doc_markdown`] missing backticks + lint [#7904](https://github.com/rust-lang/rust-clippy/pull/7904) +* [`equatable_if_let`] no longer expands macros in the suggestion + [#7788](https://github.com/rust-lang/rust-clippy/pull/7788) +* Make [`shadow_reuse`] suggestion less verbose + [#7782](https://github.com/rust-lang/rust-clippy/pull/7782) + +### ICE fixes + +* Fix ICE in [`enum_variant_names`] + [#7873](https://github.com/rust-lang/rust-clippy/pull/7873) +* Fix ICE in [`undocumented_unsafe_blocks`] + [#7891](https://github.com/rust-lang/rust-clippy/pull/7891) + +### Documentation improvements + +* Fixed naive doc formatting for `#[must_use]` lints ([`must_use_unit`], + [`double_must_use`], [`must_use_candidate`], [`let_underscore_must_use`]) + [#7827](https://github.com/rust-lang/rust-clippy/pull/7827) +* Fix typo in example for [`match_result_ok`] + [#7815](https://github.com/rust-lang/rust-clippy/pull/7815) + +### Others + +* Allow giving reasons for [`disallowed_types`] + [#7791](https://github.com/rust-lang/rust-clippy/pull/7791) +* Fix [`manual_assert`] and [`match_wild_err_arm`] for `#![no_std]` and Rust + 2021. [#7851](https://github.com/rust-lang/rust-clippy/pull/7851) +* Fix regression in [`semicolon_if_nothing_returned`] on macros containing while + loops [#7789](https://github.com/rust-lang/rust-clippy/pull/7789) +* Added a new configuration `literal-suffix-style` to enforce a certain style + writing [`unseparated_literal_suffix`] + [#7726](https://github.com/rust-lang/rust-clippy/pull/7726) ## Rust 1.57 -Current beta, release 2021-12-02 +Current stable, released 2021-12-02 -[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f) +[7bfc26e...00e31fa](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...00e31fa) ### New Lints @@ -161,7 +275,7 @@ Current beta, release 2021-12-02 ## Rust 1.56 -Current stable, released 2021-10-21 +Released 2021-10-21 [74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e) @@ -2912,6 +3026,7 @@ Released 2018-09-13 [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display +[`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields [`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always [`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax [`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 97ff31b4bc5..fc663de8f79 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -118,7 +118,7 @@ which `IntelliJ Rust` will be able to understand. Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo you just cloned. The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to -Clippys `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses. +Clippy's `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses. Just make sure to remove the dependencies again before finally making a pull request! [rustc_repo]: https://github.com/rust-lang/rust/ @@ -126,8 +126,8 @@ Just make sure to remove the dependencies again before finally making a pull req ### Rust Analyzer As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals -using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippys `Cargo.toml.` -You will required a `nightly` toolchain with the `rustc-dev` component installed. +using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippy's `Cargo.toml.` +You will require a `nightly` toolchain with the `rustc-dev` component installed. Make sure that in the `rust-analyzer` configuration, you set ``` { "rust-analyzer.rustcSource": "discover" } @@ -228,7 +228,7 @@ about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree]. ### Patching git-subtree to work with big repos -Currently there's a bug in `git-subtree` that prevents it from working properly +Currently, there's a bug in `git-subtree` that prevents it from working properly with the [`rust-lang/rust`] repo. There's an open PR to fix that, but it's stale. Before continuing with the following steps, we need to manually apply that fix to our local copy of `git-subtree`. diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 73b0167d363..1bbd89e7822 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -144,7 +144,7 @@ line. (You can swap `clippy::all` with the specific lint category you are target ## Configuration Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable = -value` mapping eg. +value` mapping e.g. ```toml avoid-breaking-exported-api = false @@ -155,6 +155,10 @@ cognitive-complexity-threshold = 30 See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which lints can be configured and the meaning of the variables. +Note that configuration changes will not apply for code that has already been compiled and cached under `./target/`; +for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure that +any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch. + To deactivate the “for further information visit *lint-link*” message you can define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. @@ -193,7 +197,7 @@ And to warn on `lint_name`, run cargo clippy -- -W clippy::lint_name ``` -This also works with lint groups. For example you +This also works with lint groups. For example, you can run Clippy with warnings for all lints enabled: ```terminal cargo clippy -- -W clippy::pedantic @@ -228,7 +232,7 @@ fn main() { You can also omit the patch version when specifying the MSRV, so `msrv = 1.30` is equivalent to `msrv = 1.30.0`. -Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. +Note: `custom_inner_attributes` is an unstable feature, so it has to be enabled explicitly. Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 0661c280386..7d2a3e4f639 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -13,7 +13,7 @@ cargo_metadata = "0.14" clippy_utils = { path = "../clippy_utils" } if_chain = "1.0" itertools = "0.10" -pulldown-cmark = { version = "0.8", default-features = false } +pulldown-cmark = { version = "0.9", default-features = false } quine-mc_cluskey = "0.2" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 12435eefbc4..5061c9d1eaf 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -87,7 +87,7 @@ impl ApproxConstant { let s = s.as_str(); if s.parse::<f64>().is_ok() { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { - if is_approx_const(constant, &s, min_digits) + if is_approx_const(constant, s, min_digits) && msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv)) { span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 489945b513d..0629674307b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -310,8 +310,10 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { || is_word(lint, sym::deprecated) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) - || extract_clippy_lint(lint).map_or(false, |s| s.as_str() == "wildcard_imports") - || extract_clippy_lint(lint).map_or(false, |s| s.as_str() == "enum_glob_use") + || extract_clippy_lint(lint) + .map_or(false, |s| s.as_str() == "wildcard_imports") + || extract_clippy_lint(lint) + .map_or(false, |s| s.as_str() == "enum_glob_use") { return; } diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 9ed359922fd..1915d990c12 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -49,8 +49,9 @@ pub(super) fn check( if cast_from.kind() == cast_to.kind() => { if let Some(src) = snippet_opt(cx, lit.span) { - let num_lit = NumericLiteral::from_lit_kind(&src, &lit.node).unwrap(); - lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); + if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { + lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); + } } }, _ => { diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 3650e4f91a0..7c271773357 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -542,16 +542,16 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize }, Start(Link(_, url, _)) => in_link = Some(url), End(Link(..)) => in_link = None, - Start(Heading(_) | Paragraph | Item) => { - if let Start(Heading(_)) = event { + Start(Heading(_, _, _) | Paragraph | Item) => { + if let Start(Heading(_, _, _)) = event { in_heading = true; } ticks_unbalanced = false; let (_, span) = get_current_span(spans, range.start); paragraph_span = first_line_of_span(cx, span); }, - End(Heading(_) | Paragraph | Item) => { - if let End(Heading(_)) = event { + End(Heading(_, _, _) | Paragraph | Item) => { + if let End(Heading(_, _, _)) = event { in_heading = false; } if ticks_unbalanced { diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 689ac6184bf..4f89e567430 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; -use clippy_utils::str_utils::{self, count_match_end, count_match_start}; -use rustc_hir::{EnumDef, Item, ItemKind}; +use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start}; +use rustc_hir::{EnumDef, Item, ItemKind, Variant}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -18,6 +18,12 @@ declare_clippy_lint! { /// Enumeration variant names should specify their variant, /// not repeat the enumeration name. /// + /// ### Limitations + /// Characters with no casing will be considered when comparing prefixes/suffixes + /// This applies to numbers and non-ascii characters without casing + /// e.g. `Foo1` and `Foo2` is considered to have different prefixes + /// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹` + /// /// ### Example /// ```rust /// enum Cake { @@ -120,72 +126,73 @@ impl_lint_pass!(EnumVariantNames => [ MODULE_INCEPTION ]); -fn check_variant( - cx: &LateContext<'_>, - threshold: u64, - def: &EnumDef<'_>, - item_name: &str, - item_name_chars: usize, - span: Span, -) { +fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) { + let name = variant.ident.name.as_str(); + let item_name_chars = item_name.chars().count(); + + if count_match_start(item_name, name).char_count == item_name_chars + && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) + && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) + { + span_lint( + cx, + ENUM_VARIANT_NAMES, + variant.span, + "variant name starts with the enum's name", + ); + } +} + +fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) { + let name = variant.ident.name.as_str(); + let item_name_chars = item_name.chars().count(); + + if count_match_end(item_name, name).char_count == item_name_chars { + span_lint( + cx, + ENUM_VARIANT_NAMES, + variant.span, + "variant name ends with the enum's name", + ); + } +} + +fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_name: &str, span: Span) { if (def.variants.len() as u64) < threshold { return; } + + let first = &def.variants[0].ident.name.as_str(); + let mut pre = camel_case_split(first); + let mut post = pre.clone(); + post.reverse(); for var in def.variants { - let name = var.ident.name.as_str(); - if count_match_start(item_name, &name).char_count == item_name_chars - && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) - && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) - { - span_lint( - cx, - ENUM_VARIANT_NAMES, - var.span, - "variant name starts with the enum's name", - ); - } - if count_match_end(item_name, &name).char_count == item_name_chars { - span_lint( - cx, - ENUM_VARIANT_NAMES, - var.span, - "variant name ends with the enum's name", - ); - } - } - let first = def.variants[0].ident.name.as_str(); - let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index]; - let mut post = &first[str_utils::camel_case_start(&*first).byte_index..]; - for var in def.variants { + check_enum_start(cx, item_name, var); + check_enum_end(cx, item_name, var); let name = var.ident.name.as_str(); - let pre_match = count_match_start(pre, &name).byte_count; - pre = &pre[..pre_match]; - let pre_camel = str_utils::camel_case_until(pre).byte_index; - pre = &pre[..pre_camel]; - while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { - if next.is_numeric() { - return; - } - if next.is_lowercase() { - let last = pre.len() - last.len_utf8(); - let last_camel = str_utils::camel_case_until(&pre[..last]); - pre = &pre[..last_camel.byte_index]; - } else { - break; - } - } + let variant_split = camel_case_split(name); - let post_match = count_match_end(post, &name); - let post_end = post.len() - post_match.byte_count; - post = &post[post_end..]; - let post_camel = str_utils::camel_case_start(post); - post = &post[post_camel.byte_index..]; + pre = pre + .iter() + .zip(variant_split.iter()) + .take_while(|(a, b)| a == b) + .map(|e| *e.0) + .collect(); + post = post + .iter() + .zip(variant_split.iter().rev()) + .take_while(|(a, b)| a == b) + .map(|e| *e.0) + .collect(); } let (what, value) = match (pre.is_empty(), post.is_empty()) { (true, true) => return, - (false, _) => ("pre", pre), - (true, false) => ("post", post), + (false, _) => ("pre", pre.join("")), + (true, false) => { + post.reverse(); + ("post", post.join("")) + }, }; span_lint_and_help( cx, @@ -233,8 +240,7 @@ impl LateLintPass<'_> for EnumVariantNames { #[allow(clippy::similar_names)] fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { let item_name = item.ident.name.as_str(); - let item_name_chars = item_name.chars().count(); - let item_camel = to_camel_case(&item_name); + let item_camel = to_camel_case(item_name); if !item.span.from_expansion() && is_present_in_source(cx, item.span) { if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() { // constants don't have surrounding modules @@ -283,7 +289,7 @@ impl LateLintPass<'_> for EnumVariantNames { } if let ItemKind::Enum(ref def, _) = item.kind { if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) { - check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span); + check_variant(cx, self.threshold, def, item_name, item.span); } } self.modules.push((item.ident.name, item_camel)); diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 6903073fbcd..7a4397a7b74 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { // If its within the 2 decimal digits of being out of precision we // check if the parsed representation is the same as the string // since we'll need the truncated string anyway. - let digits = count_digits(&sym_str); + let digits = count_digits(sym_str); let max = max_digits(fty); let type_suffix = match lit_float_ty { LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"), 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 a70e58c9c3a..6dcbaf68dfd 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -356,7 +356,7 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> { if eq_expr_value(cx, lmul_lhs, lmul_rhs); if eq_expr_value(cx, rmul_lhs, rmul_rhs); then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, ".."), Sugg::hir(cx, rmul_lhs, ".."))); + return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, ".."))); } } @@ -379,7 +379,7 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> { if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { - return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, ".."), Sugg::hir(cx, rargs_0, ".."))); + return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); } } } @@ -654,26 +654,52 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) { + let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); + if_chain! { + if let ExprKind::Lit(ref literal) = mul_lhs.kind; + if let ast::LitKind::Float(ref value, float_type) = literal.node; + if float_type == ast::LitFloatType::Unsuffixed; + then { + if value.as_str().ends_with('.') { + proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); + } else { + proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); + } + } + } span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, expr.span, "conversion to degrees can be done more accurately", "consider using", - format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")), + proposal, Applicability::MachineApplicable, ); } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) { + let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")); + if_chain! { + if let ExprKind::Lit(ref literal) = mul_lhs.kind; + if let ast::LitKind::Float(ref value, float_type) = literal.node; + if float_type == ast::LitFloatType::Unsuffixed; + then { + if value.as_str().ends_with('.') { + proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); + } else { + proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, "..")); + } + } + } span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, expr.span, "conversion to radians can be done more accurately", "consider using", - format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")), + proposal, Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs index b4e7bbc7671..f824f20ca40 100644 --- a/src/tools/clippy/clippy_lints/src/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/identity_op.rs @@ -61,15 +61,18 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp { } fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool { - // `1 << 0` is a common pattern in bit manipulation code - cmp.node == BinOpKind::Shl - && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0)) - && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)) + // This lint applies to integers + !cx.typeck_results().expr_ty(left).peel_refs().is_integral() + || !cx.typeck_results().expr_ty(right).peel_refs().is_integral() + // `1 << 0` is a common pattern in bit manipulation code + || (cmp.node == BinOpKind::Shl + && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0)) + && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))) } fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) { - if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) { - let check = match *cx.typeck_results().expr_ty(e).kind() { + if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) { + let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), ty::Uint(uty) => clip(cx.tcx, !0, uty), _ => return, 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 26a196aab59..6515975fbff 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let LitKind::Int(0, _) = cond_lit.node { if cx.typeck_results().expr_ty(cond_left).is_signed() { } else { - print_lint_and_sugg(cx, &var_name, expr); + print_lint_and_sugg(cx, var_name, expr); }; } }, @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok()); if int_ids.any(|int_id| int_id == impl_id); then { - print_lint_and_sugg(cx, &var_name, expr) + print_lint_and_sugg(cx, var_name, expr) } } }, @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok()); if int_ids.any(|int_id| int_id == impl_id); then { - print_lint_and_sugg(cx, &var_name, expr) + print_lint_and_sugg(cx, var_name, expr) } } }, diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs new file mode 100644 index 00000000000..5fe6725b581 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -0,0 +1,80 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::borrow::Cow; +use std::cmp::Reverse; +use std::collections::BinaryHeap; + +declare_clippy_lint! { + /// ### What it does + /// Checks for tuple structs initialized with field syntax. + /// It will however not lint if a base initializer is present. + /// The lint will also ignore code in macros. + /// + /// ### Why is this bad? + /// This may be confusing to the uninitiated and adds no + /// benefit as opposed to tuple initializers + /// + /// ### Example + /// ```rust + /// struct TupleStruct(u8, u16); + /// + /// let _ = TupleStruct { + /// 0: 1, + /// 1: 23, + /// }; + /// + /// // should be written as + /// let base = TupleStruct(1, 23); + /// + /// // This is OK however + /// let _ = TupleStruct { 0: 42, ..base }; + /// ``` + #[clippy::version = "1.59.0"] + pub INIT_NUMBERED_FIELDS, + style, + "numbered fields in tuple struct initializer" +} + +declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]); + +impl<'tcx> LateLintPass<'tcx> for NumberedFields { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Struct(path, fields, None) = e.kind { + if !fields.is_empty() + && !in_macro(e.span) + && fields + .iter() + .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit)) + { + let expr_spans = fields + .iter() + .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span)) + .collect::<BinaryHeap<_>>(); + let mut appl = Applicability::MachineApplicable; + let snippet = format!( + "{}({})", + snippet_with_applicability(cx, path.span(), "..", &mut appl), + expr_spans + .into_iter_sorted() + .map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl)) + .intersperse(Cow::Borrowed(", ")) + .collect::<String>() + ); + span_lint_and_sugg( + cx, + INIT_NUMBERED_FIELDS, + e.span, + "used a field initializer for a tuple struct", + "try this instead", + snippet, + appl, + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 09cd0d22d8b..20e6220ec7d 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -441,7 +441,7 @@ fn is_empty_string(expr: &Expr<'_>) -> bool { if let ExprKind::Lit(ref lit) = expr.kind { if let LitKind::Str(lit, _) = lit.node { let lit = lit.as_str(); - return lit == ""; + return lit.is_empty(); } } false diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs index 3d3999d4cc0..944411087e9 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -81,6 +81,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(infinite_iter::INFINITE_ITER), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS), LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), LintId::of(int_plus_one::INT_PLUS_ONE), LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs index 766c5ba1bcb..002122793f3 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs @@ -178,6 +178,7 @@ store.register_lints(&[ inherent_impl::MULTIPLE_INHERENT_IMPL, inherent_to_string::INHERENT_TO_STRING, inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, + init_numbered_fields::INIT_NUMBERED_FIELDS, inline_fn_without_body::INLINE_FN_WITHOUT_BODY, int_plus_one::INT_PLUS_ONE, integer_division::INTEGER_DIVISION, diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs index ea87e7e7a73..1a0b869d40a 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs @@ -29,6 +29,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS), LintId::of(len_zero::COMPARISON_TO_EMPTY), LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(len_zero::LEN_ZERO), diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index d1c7956a7a5..d4687a1e287 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,13 +1,15 @@ // error-pattern:cargo-clippy +#![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] +#![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(iter_intersperse)] +#![feature(let_else)] #![feature(once_cell)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] -#![feature(control_flow_enum)] -#![feature(let_else)] #![recursion_limit = "512"] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)] @@ -242,6 +244,7 @@ mod indexing_slicing; mod infinite_iter; mod inherent_impl; mod inherent_to_string; +mod init_numbered_fields; mod inline_fn_without_body; mod int_plus_one; mod integer_division; @@ -854,6 +857,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit)); store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); + store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index 6cda9268534..c62fa5e998b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -12,6 +12,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Pat, PatKind, StmtKind} use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; +use std::fmt::Display; use std::iter::Iterator; /// Checks for for loops that sequentially copy items from one slice-like @@ -108,7 +109,7 @@ fn build_manual_memcpy_suggestion<'tcx>( src: &IndexExpr<'_>, ) -> String { fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> { - if offset.as_str() == "0" { + if offset.to_string() == "0" { sugg::EMPTY.into() } else { offset @@ -123,7 +124,7 @@ fn build_manual_memcpy_suggestion<'tcx>( if let Some(arg) = len_args.get(0); if path_to_local(arg) == path_to_local(base); then { - if sugg.as_str() == end_str { + if sugg.to_string() == end_str { sugg::EMPTY.into() } else { sugg @@ -147,7 +148,7 @@ fn build_manual_memcpy_suggestion<'tcx>( print_offset(apply_offset(&start_str, &idx_expr.idx_offset)).into_sugg(), print_limit( end, - end_str.as_str(), + end_str.to_string().as_str(), idx_expr.base, apply_offset(&end_str, &idx_expr.idx_offset), ) @@ -159,7 +160,7 @@ fn build_manual_memcpy_suggestion<'tcx>( print_offset(apply_offset(&counter_start, &idx_expr.idx_offset)).into_sugg(), print_limit( end, - end_str.as_str(), + end_str.to_string().as_str(), idx_expr.base, apply_offset(&end_str, &idx_expr.idx_offset) + &counter_start - &start_str, ) @@ -202,15 +203,13 @@ fn build_manual_memcpy_suggestion<'tcx>( #[derive(Clone)] struct MinifyingSugg<'a>(Sugg<'a>); -impl<'a> MinifyingSugg<'a> { - fn as_str(&self) -> &str { - // HACK: Don't sync to Clippy! Required because something with the `or_patterns` feature - // changed and this would now require parentheses. - match &self.0 { - Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) => s.as_ref(), - } +impl Display for MinifyingSugg<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) } +} +impl<'a> MinifyingSugg<'a> { fn into_sugg(self) -> Sugg<'a> { self.0 } @@ -225,7 +224,7 @@ impl<'a> From<Sugg<'a>> for MinifyingSugg<'a> { impl std::ops::Add for &MinifyingSugg<'static> { type Output = MinifyingSugg<'static>; fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { - match (self.as_str(), rhs.as_str()) { + match (self.to_string().as_str(), rhs.to_string().as_str()) { ("0", _) => rhs.clone(), (_, "0") => self.clone(), (_, _) => (&self.0 + &rhs.0).into(), @@ -236,7 +235,7 @@ impl std::ops::Add for &MinifyingSugg<'static> { impl std::ops::Sub for &MinifyingSugg<'static> { type Output = MinifyingSugg<'static>; fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { - match (self.as_str(), rhs.as_str()) { + match (self.to_string().as_str(), rhs.to_string().as_str()) { (_, "0") => self.clone(), ("0", _) => (-rhs.0.clone()).into(), (x, y) if x == y => sugg::ZERO.into(), @@ -248,7 +247,7 @@ impl std::ops::Sub for &MinifyingSugg<'static> { impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> { type Output = MinifyingSugg<'static>; fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { - match (self.as_str(), rhs.as_str()) { + match (self.to_string().as_str(), rhs.to_string().as_str()) { ("0", _) => rhs.clone(), (_, "0") => self, (_, _) => (self.0 + &rhs.0).into(), @@ -259,7 +258,7 @@ impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> { impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> { type Output = MinifyingSugg<'static>; fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> { - match (self.as_str(), rhs.as_str()) { + match (self.to_string().as_str(), rhs.to_string().as_str()) { (_, "0") => self, ("0", _) => (-rhs.0.clone()).into(), (x, y) if x == y => sugg::ZERO.into(), diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 5b22b64a370..50d80e6a1d2 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; @@ -8,7 +9,6 @@ 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_span::hygiene::ExpnKind; use rustc_span::{edition::Edition, sym, Span}; declare_clippy_lint! { @@ -213,7 +213,3 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } } } - -fn in_macro(span: Span) -> bool { - span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) -} diff --git a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs index dbf103143d9..2c0fc218ca0 100644 --- a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs @@ -94,8 +94,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { - ExprKind::MethodCall(segment, _, [receiver], _) - if self.case_altered(segment.ident.as_str(), receiver) => {}, + ExprKind::MethodCall(segment, _, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => { + }, _ => walk_expr(self, ex), } } @@ -142,7 +142,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( }) = arm.pat.kind; if let LitKind::Str(symbol, _) = lit.node; let input = symbol.as_str(); - if !case_check(&input); + if !case_check(input); then { return Some((lit.span, symbol)); } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs index e32594757d0..f5410c7fd7f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs @@ -1,8 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; +use clippy_utils::path_to_local; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::{BindingAnnotation, Node, PatKind}; use rustc_lint::LateContext; use rustc_span::sym; @@ -11,14 +13,34 @@ use super::ITER_SKIP_NEXT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { // lint if caller of skip is an Iterator if is_trait_method(cx, expr, sym::Iterator) { - span_lint_and_sugg( + let mut application = Applicability::MachineApplicable; + span_lint_and_then( cx, ITER_SKIP_NEXT, expr.span.trim_start(recv.span).unwrap(), "called `skip(..).next()` on an iterator", - "use `nth` instead", - format!(".nth({})", snippet(cx, arg.span, "..")), - Applicability::MachineApplicable, + |diag| { + if_chain! { + if let Some(id) = path_to_local(recv); + if let Node::Binding(pat) = cx.tcx.hir().get(id); + if let PatKind::Binding(ann, _, _, _) = pat.kind; + if ann != BindingAnnotation::Mutable; + then { + application = Applicability::Unspecified; + diag.span_help( + pat.span, + &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")), + ); + } + } + + diag.span_suggestion( + expr.span.trim_start(recv.span).unwrap(), + "use `nth` instead", + format!(".nth({})", snippet(cx, arg.span, "..")), + application, + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 4934240abfc..4e33b2ff14c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2112,7 +2112,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { { wrong_self_convention::check( cx, - &name, + name, self_ty, first_arg_ty, first_arg.pat.span, diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs index 276467b1dfd..f3af281d6ca 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -2,7 +2,8 @@ use super::UNWRAP_OR_ELSE_DEFAULT; use clippy_utils::{ - diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item, + diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability, + ty::is_type_diagnostic_item, }; use rustc_errors::Applicability; use rustc_hir as hir; @@ -24,7 +25,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if is_trait_item(cx, u_arg, sym::Default); + if is_default_equivalent_call(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index 11ad881ee7b..24b44f819f4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -57,7 +57,7 @@ pub(super) fn get_hint_if_single_char_arg( let string = r.as_str(); if string.chars().count() == 1; then { - let snip = snippet_with_applicability(cx, arg.span, &string, applicability); + let snip = snippet_with_applicability(cx, arg.span, string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { let nhash = nhash as usize; // for raw string: r##"a"## diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index d391fbecf82..778d49cb4b6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -187,14 +187,14 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { BinOpKind::Eq => { let true_case = Some((|h| h, "equality checks against true are unnecessary")); let false_case = Some(( - |h: Sugg<'_>| !h, + |h: Sugg<'tcx>| !h, "equality checks against false can be replaced by a negation", )); check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Ne => { let true_case = Some(( - |h: Sugg<'_>| !h, + |h: Sugg<'tcx>| !h, "inequality checks against true can be replaced by a negation", )); let false_case = Some((|h| h, "inequality checks against false are unnecessary")); @@ -206,12 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { ignore_case, Some((|h| h, "greater than checks against false are unnecessary")), Some(( - |h: Sugg<'_>| !h, + |h: Sugg<'tcx>| !h, "less than comparison against true can be replaced by a negation", )), ignore_case, Some(( - |l: Sugg<'_>, r: Sugg<'_>| (!l).bit_and(&r), + |l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r), "order comparisons between booleans can be simplified", )), ), @@ -219,14 +219,14 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { cx, e, Some(( - |h: Sugg<'_>| !h, + |h: Sugg<'tcx>| !h, "less than comparison against true can be replaced by a negation", )), ignore_case, ignore_case, Some((|h| h, "greater than checks against false are unnecessary")), Some(( - |l: Sugg<'_>, r: Sugg<'_>| l.bit_and(&(!r)), + |l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)), "order comparisons between booleans can be simplified", )), ), diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index cb67fab1740..0d05c83ffe4 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -1,6 +1,8 @@ use clippy_utils::consts::{self, Constant}; -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; +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}; @@ -18,12 +20,16 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// x * -1 + /// // Bad + /// let a = x * -1; + /// + /// // Good + /// let b = -x; /// ``` #[clippy::version = "pre 1.29.0"] pub NEG_MULTIPLY, style, - "multiplying integers with `-1`" + "multiplying integers by `-1`" } declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]); @@ -49,8 +55,19 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { if let ExprKind::Lit(ref l) = lit.kind; if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if cx.typeck_results().expr_ty(exp).is_integral(); + then { - span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`"); + let mut applicability = Applicability::MachineApplicable; + let suggestion = format!("-{}", snippet_with_applicability(cx, exp.span, "..", &mut applicability)); + span_lint_and_sugg( + cx, + NEG_MULTIPLY, + span, + "this multiplication by -1 can be written more succinctly", + "consider using", + suggestion, + applicability, + ); } } } 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 25fbcb3c609..39a37e3e378 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -218,20 +218,20 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { return; } for existing_name in &self.0.names { - if allowed_to_be_similar(&interned_name, existing_name.exemptions) { + if allowed_to_be_similar(interned_name, existing_name.exemptions) { continue; } match existing_name.len.cmp(&count) { Ordering::Greater => { if existing_name.len - count != 1 - || levenstein_not_1(&interned_name, existing_name.interned.as_str()) + || levenstein_not_1(interned_name, existing_name.interned.as_str()) { continue; } }, Ordering::Less => { if count - existing_name.len != 1 - || levenstein_not_1(existing_name.interned.as_str(), &interned_name) + || levenstein_not_1(existing_name.interned.as_str(), interned_name) { continue; } @@ -298,7 +298,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { return; } self.0.names.push(ExistingName { - exemptions: get_exemptions(&interned_name).unwrap_or(&[]), + exemptions: get_exemptions(interned_name).unwrap_or(&[]), interned: ident.name, span: ident.span, len: count, diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 52c060bc42c..c8cbfefb63d 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -378,8 +378,8 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { span, "an inclusive range would be more readable", |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string()); - let end = Sugg::hir(cx, y, "y"); + let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); + let end = Sugg::hir(cx, y, "y").maybe_par(); if let Some(is_wrapped) = &snippet_opt(cx, span) { if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') { diag.span_suggestion( @@ -415,8 +415,8 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "an exclusive range would be more readable", |diag| { - let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string()); - let end = Sugg::hir(cx, y, "y"); + let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string()); + let end = Sugg::hir(cx, y, "y").maybe_par(); diag.span_suggestion( expr.span, "use", 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 1118da6c8cb..b57ec96bc7e 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 @@ -1,11 +1,12 @@ -use clippy_utils::{diagnostics::span_lint, must_use_attr, nth_arg, return_ty}; +use clippy_utils::ty::is_must_use_ty; +use clippy_utils::{diagnostics::span_lint, nth_arg, return_ty}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId, 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_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -50,9 +51,9 @@ fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalD if decl.implicit_self.has_implicit_self(); // We only show this warning for public exported methods. if cx.access_levels.is_exported(fn_def); + // We don't want to emit this lint if the `#[must_use]` attribute is already there. + if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use)); if cx.tcx.visibility(fn_def.to_def_id()).is_public(); - // No need to warn if the attribute is already present. - if must_use_attr(cx.tcx.hir().attrs(hir_id)).is_none(); let ret_ty = return_ty(cx, hir_id); let self_arg = nth_arg(cx, hir_id, 0); // If `Self` has the same type as the returned type, then we want to warn. @@ -60,6 +61,8 @@ fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalD // For this check, we don't want to remove the reference on the returned type because if // there is one, we shouldn't emit a warning! if self_arg.peel_refs() == ret_ty; + // If `Self` is already marked as `#[must_use]`, no need for the attribute here. + if !is_must_use_ty(cx, ret_ty); then { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 494bc7dda18..112ccdcdd42 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -73,6 +73,7 @@ declare_clippy_lint! { enum RetReplacement { Empty, Block, + Unit, } declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]); @@ -212,7 +213,7 @@ fn check_final_expr<'tcx>( // (except for unit type functions) so we don't match it ExprKind::Match(_, arms, MatchSource::Normal) => { for arm in arms.iter() { - check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block); + check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Unit); } }, ExprKind::DropTemps(expr) => check_final_expr(cx, expr, None, RetReplacement::Empty), @@ -259,6 +260,17 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa Applicability::MachineApplicable, ); }, + RetReplacement::Unit => { + span_lint_and_sugg( + cx, + NEEDLESS_RETURN, + ret_span, + "unneeded `return` statement", + "replace `return` with a unit value", + "()".to_string(), + Applicability::MachineApplicable, + ); + }, }, } } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index f6880af0cab..ce05c5a6164 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; -use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp}; +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_span::{Span, Symbol}; @@ -220,14 +220,14 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_ } } -/// Finds the "init" expression for a pattern: `let <pat> = <init>;` or +/// Finds the "init" expression for a pattern: `let <pat> = <init>;` (or `if let`) or /// `match <init> { .., <pat> => .., .. }` fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { for (_, node) in cx.tcx.hir().parent_iter(hir_id) { let init = match node { Node::Arm(_) | Node::Pat(_) => continue, Node::Expr(expr) => match expr.kind { - ExprKind::Match(e, _, _) => Some(e), + ExprKind::Match(e, _, _) | ExprKind::Let(&Let { init: e, .. }) => Some(e), _ => None, }, Node::Local(local) => local.init, 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 c9b4b245f4c..15543b6a262 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 @@ -64,7 +64,7 @@ impl TabsInDocComments { if let ast::AttrKind::DocComment(_, comment) = attr.kind { let comment = comment.as_str(); - for (lo, hi) in get_chunks_of_tabs(&comment) { + for (lo, hi) in get_chunks_of_tabs(comment) { // +3 skips the opening delimiter let new_span = Span::new( attr.span.lo() + BytePos(3 + lo), 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 ccc49caf47c..3d3b4a6679d 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -15,7 +15,7 @@ use std::borrow::Cow; declare_clippy_lint! { /// ### What it does - /// Checks for `unsafe` blocks without a `// Safety: ` comment + /// Checks for `unsafe` blocks without a `// SAFETY: ` comment /// explaining why the unsafe operations performed inside /// the block are safe. /// @@ -36,7 +36,7 @@ declare_clippy_lint! { /// use std::ptr::NonNull; /// let a = &mut 42; /// - /// // Safety: references are guaranteed to be non-null. + /// // SAFETY: references are guaranteed to be non-null. /// let ptr = unsafe { NonNull::new_unchecked(a) }; /// ``` #[clippy::version = "1.58.0"] @@ -213,7 +213,7 @@ impl UndocumentedUnsafeBlocks { ); } else { let block_indent = indent_of(cx, span); - let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, "..")); + let suggestion = format!("// SAFETY: ...\n{}", snippet(cx, span, "..")); span_lint_and_sugg( cx, 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 44b1989dbc6..64f7a055cd9 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 @@ -60,7 +60,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) { fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, span: Span) { let old_str = old_name.name.as_str(); let new_str = new_name.name.as_str(); - if contains_unsafe(&old_str) && !contains_unsafe(&new_str) { + if contains_unsafe(old_str) && !contains_unsafe(new_str) { span_lint( cx, UNSAFE_REMOVED_FROM_NAME, diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 01a5691223b..918fa5f7dc1 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -161,7 +161,7 @@ fn collect_unwrap_info<'tcx>( if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name); then { assert!(args.len() == 1); - let unwrappable = match name.as_ref() { + let unwrappable = match name { "is_some" | "is_ok" => true, "is_err" | "is_none" => false, _ => unreachable!(), 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 0c62161e53d..7286d0a7bf9 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -87,7 +87,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2) // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive // upper-case-acronyms-aggressive config option enabled - || (be_aggressive && ident != &corrected) + || (be_aggressive && ident != corrected) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index 81e9c2e15c9..e98dcd3cf98 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -28,7 +28,7 @@ use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{Symbol, SymbolStr}; +use rustc_span::symbol::Symbol; use rustc_span::{sym, BytePos, Span}; use rustc_typeck::hir_ty_to_ty; @@ -344,11 +344,11 @@ impl EarlyLintPass for ClippyLintsInternal { if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind { if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") { if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind { - let mut last_name: Option<SymbolStr> = None; + let mut last_name: Option<&str> = None; for item in items { let name = item.ident.as_str(); - if let Some(ref last_name) = last_name { - if **last_name > *name { + if let Some(last_name) = last_name { + if *last_name > *name { span_lint( cx, CLIPPY_LINTS_INTERNAL, @@ -608,8 +608,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { } let (method_names, arg_lists, spans) = method_calls(expr, 2); - let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect(); - let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect(); + let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect(); if_chain! { if let ["expn_data", "outer_expn"] = method_names.as_slice(); let args = arg_lists[1]; @@ -839,7 +838,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]); // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, ty_path); - let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); + let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect(); if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id(); // Check if the matched type is a diagnostic item if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did); @@ -862,7 +861,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { } } -fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> { +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<Symbol>> { use rustc_hir::ItemKind; match &expr.kind { @@ -887,12 +886,12 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve _ => {}, }, ExprKind::Array(exprs) => { - let segments: Vec<SymbolStr> = exprs + let segments: Vec<Symbol> = exprs .iter() .filter_map(|expr| { if let ExprKind::Lit(lit) = &expr.kind { if let LitKind::Str(sym, _) = lit.node { - return Some(sym.as_str()); + return Some(sym); } } @@ -1076,7 +1075,6 @@ impl InterningDefinedSymbol { &paths::SYMBOL_TO_IDENT_STRING, &paths::TO_STRING_METHOD, ]; - // SymbolStr might be de-referenced: `&*symbol.as_str()` let call = if_chain! { if let ExprKind::AddrOf(_, _, e) = expr.kind; if let ExprKind::Unary(UnOp::Deref, e) = e.kind; diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index dc5ec5f2295..5c024612f8e 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -168,6 +168,14 @@ impl Constant { None } } + + #[must_use] + pub fn peel_refs(mut self) -> Self { + while let Constant::Ref(r) = self { + self = *r; + } + self + } } /// Parses a `LitKind` to a `Constant`. @@ -320,7 +328,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let res = self.typeck_results.qpath_res(qpath, callee.hir_id); if let Some(def_id) = res.opt_def_id(); let def_path = self.lcx.get_def_path(def_id); - let def_path: Vec<&str> = def_path.iter().take(4).map(|s| s.as_str()).collect(); + let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect(); if let ["core", "num", int_impl, "max_value"] = *def_path; then { let value = match int_impl { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7e054a54c3c..54d470ca738 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,8 +1,9 @@ #![feature(box_patterns)] +#![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(let_else)] +#![feature(once_cell)] #![feature(rustc_private)] -#![feature(control_flow_enum)] #![recursion_limit = "512"] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)] @@ -60,9 +61,12 @@ pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, Spanl use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; +use std::lazy::SyncOnceCell; +use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; use rustc_ast::ast::{self, Attribute, LitKind}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -87,6 +91,7 @@ use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture}; use rustc_semver::RustcVersion; use rustc_session::Session; +use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::sym; @@ -142,6 +147,13 @@ macro_rules! extract_msrv_attr { }; } +/// Returns `true` if the span comes from a macro expansion, no matter if from a +/// macro by example or from a procedural macro +#[must_use] +pub fn in_macro(span: Span) -> bool { + span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) +} + /// Returns `true` if the two spans come from differing expansions (i.e., one is /// from a macro and one isn't). #[must_use] @@ -156,18 +168,18 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { /// instead. /// /// Examples: -/// ```ignore +/// ``` /// let abc = 1; /// // ^ output /// let def = abc; -/// dbg!(def) +/// dbg!(def); /// // ^^^ input /// /// // or... /// let abc = 1; /// let def = abc + 2; /// // ^^^^^^^ output -/// dbg!(def) +/// dbg!(def); /// // ^^^ input /// ``` pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> { @@ -664,6 +676,22 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< false } +/// Return true if the expr is equal to `Default::default` when evaluated. +pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool { + if_chain! { + if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind; + if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); + if is_diag_trait_item(cx, repl_def_id, sym::Default) + || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); + then { + true + } + else { + false + } + } +} + /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. /// It doesn't cover all cases, for example indirect function calls (some of std /// functions are supported) but it is the best we have. @@ -686,18 +714,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { false } }, - ExprKind::Call(repl_func, _) => if_chain! { - if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diag_trait_item(cx, repl_def_id, sym::Default) - || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); - then { - true - } - else { - false - } - }, + ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func), ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone), ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])), _ => false, @@ -1136,7 +1153,7 @@ pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> { /// Extends the span to the beginning of the spans line, incl. whitespaces. /// -/// ```rust,ignore +/// ```rust /// let x = (); /// // ^^ /// // will be converted to @@ -1337,7 +1354,7 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { cx.typeck_results().adjustments().get(e.hir_id).is_some() } -/// Returns the pre-expansion span if is this comes from an expansion of the +/// Returns the pre-expansion span if this comes from an expansion of the /// macro `name`. /// See also [`is_direct_expn_of`]. #[must_use] @@ -1364,7 +1381,8 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { /// of the macro `name`. /// The difference with [`is_expn_of`] is that in /// ```rust -/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } } +/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } } +/// # macro_rules! bar { ($e:expr) => { $e } } /// foo!(bar!(42)); /// ``` /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only @@ -1905,7 +1923,9 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { /// Check if parent of a hir node is a trait implementation block. /// For example, `f` in -/// ```rust,ignore +/// ```rust +/// # struct S; +/// # trait Trait { fn f(); } /// impl Trait for S { /// fn f() {} /// } @@ -2124,17 +2144,16 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { false } -struct VisitConstTestStruct<'tcx> { +struct TestItemNamesVisitor<'tcx> { tcx: TyCtxt<'tcx>, names: Vec<Symbol>, - found: bool, } -impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> { + +impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> { fn visit_item(&mut self, item: &Item<'_>) { if let ItemKind::Const(ty, _body) = item.kind { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { // We could also check for the type name `test::TestDescAndFn` - // and the `#[rustc_test_marker]` attribute? if let Res::Def(DefKind::Struct, _) = path.res { let has_test_marker = self .tcx @@ -2142,8 +2161,8 @@ impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> { .attrs(item.hir_id()) .iter() .any(|a| a.has_name(sym::rustc_test_marker)); - if has_test_marker && self.names.contains(&item.ident.name) { - self.found = true; + if has_test_marker { + self.names.push(item.ident.name); } } } @@ -2154,32 +2173,42 @@ impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> { fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {} } +static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new(); + +fn with_test_item_names(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { + let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default())); + let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap(); + match map.entry(module) { + Entry::Occupied(entry) => f(entry.get()), + Entry::Vacant(entry) => { + let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() }; + tcx.hir().visit_item_likes_in_module(module, &mut visitor); + visitor.names.sort_unstable(); + f(&*entry.insert(visitor.names)) + }, + } +} + /// Checks if the function containing the given `HirId` is a `#[test]` function /// /// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`. pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { - let names: Vec<_> = tcx - .hir() - .parent_iter(id) - // Since you can nest functions we need to collect all until we leave - // function scope - .filter_map(|(_id, node)| { - if let Node::Item(item) = node { - if let ItemKind::Fn(_, _, _) = item.kind { - return Some(item.ident.name); + with_test_item_names(tcx, tcx.parent_module(id), |names| { + tcx.hir() + .parent_iter(id) + // Since you can nest functions we need to collect all until we leave + // function scope + .any(|(_id, node)| { + if let Node::Item(item) = node { + if let ItemKind::Fn(_, _, _) = item.kind { + // Note that we have sorted the item names in the visitor, + // so the binary_search gets the same as `contains`, but faster. + return names.binary_search(&item.ident.name).is_ok(); + } } - } - None - }) - .collect(); - let parent_mod = tcx.parent_module(id); - let mut vis = VisitConstTestStruct { - tcx, - names, - found: false, - }; - tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis); - vis.found + false + }) + }) } /// Checks whether item either has `test` attribute applied, or diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 1a4da1627b7..836558b07cb 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -193,7 +193,6 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv } }, Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), - Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs index cba96e05a24..03a9d3c25fd 100644 --- a/src/tools/clippy/clippy_utils/src/str_utils.rs +++ b/src/tools/clippy/clippy_utils/src/str_utils.rs @@ -15,6 +15,7 @@ impl StrIndex { /// Returns the index of the character after the first camel-case component of `s`. /// /// ``` +/// # use clippy_utils::str_utils::{camel_case_until, StrIndex}; /// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6)); /// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); /// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3)); @@ -55,9 +56,10 @@ pub fn camel_case_until(s: &str) -> StrIndex { } } -/// Returns index of the last camel-case component of `s`. +/// Returns index of the first camel-case component of `s`. /// /// ``` +/// # use clippy_utils::str_utils::{camel_case_start, StrIndex}; /// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); /// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); /// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4)); @@ -66,19 +68,37 @@ pub fn camel_case_until(s: &str) -> StrIndex { /// ``` #[must_use] pub fn camel_case_start(s: &str) -> StrIndex { + camel_case_start_from_idx(s, 0) +} + +/// Returns `StrIndex` of the last camel-case component of `s[idx..]`. +/// +/// ``` +/// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex}; +/// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0)); +/// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3)); +/// assert_eq!(camel_case_start_from_idx("AbcDefGhi", 0), StrIndex::new(0, 0)); +/// assert_eq!(camel_case_start_from_idx("AbcDefGhi", 1), StrIndex::new(3, 3)); +/// assert_eq!(camel_case_start_from_idx("Abcdefg", 1), StrIndex::new(7, 7)); +/// ``` +pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> StrIndex { let char_count = s.chars().count(); let range = 0..char_count; let mut iter = range.rev().zip(s.char_indices().rev()); - if let Some((char_index, (_, first))) = iter.next() { + if let Some((_, (_, first))) = iter.next() { if !first.is_lowercase() { - return StrIndex::new(char_index, s.len()); + return StrIndex::new(char_count, s.len()); } } else { return StrIndex::new(char_count, s.len()); } + let mut down = true; let mut last_index = StrIndex::new(char_count, s.len()); for (char_index, (byte_index, c)) in iter { + if byte_index < start_idx { + break; + } if down { if c.is_uppercase() { down = false; @@ -96,9 +116,55 @@ pub fn camel_case_start(s: &str) -> StrIndex { return last_index; } } + last_index } +/// Get the indexes of camel case components of a string `s` +/// +/// ``` +/// # use clippy_utils::str_utils::{camel_case_indices, StrIndex}; +/// assert_eq!( +/// camel_case_indices("AbcDef"), +/// vec![StrIndex::new(0, 0), StrIndex::new(3, 3), StrIndex::new(6, 6)] +/// ); +/// assert_eq!( +/// camel_case_indices("abcDef"), +/// vec![StrIndex::new(3, 3), StrIndex::new(6, 6)] +/// ); +/// ``` +pub fn camel_case_indices(s: &str) -> Vec<StrIndex> { + let mut result = Vec::new(); + let mut str_idx = camel_case_start(s); + + while str_idx.byte_index < s.len() { + let next_idx = str_idx.byte_index + 1; + result.push(str_idx); + str_idx = camel_case_start_from_idx(s, next_idx); + } + result.push(str_idx); + + result +} + +/// Split camel case string into a vector of its components +/// +/// ``` +/// # use clippy_utils::str_utils::{camel_case_split, StrIndex}; +/// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); +/// ``` +pub fn camel_case_split(s: &str) -> Vec<&str> { + let mut offsets = camel_case_indices(s) + .iter() + .map(|e| e.byte_index) + .collect::<Vec<usize>>(); + if offsets[0] != 0 { + offsets.insert(0, 0); + } + + offsets.windows(2).map(|w| &s[w[0]..w[1]]).collect() +} + /// Dealing with sting comparison can be complicated, this struct ensures that both the /// character and byte count are provided for correct indexing. #[derive(Debug, Default, PartialEq, Eq)] @@ -116,6 +182,7 @@ impl StrCount { /// Returns the number of chars that match from the start /// /// ``` +/// # use clippy_utils::str_utils::{count_match_start, StrCount}; /// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6)); /// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0)); /// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11)); @@ -141,6 +208,7 @@ pub fn count_match_start(str1: &str, str2: &str) -> StrCount { /// Returns the number of chars and bytes that match from the end /// /// ``` +/// # use clippy_utils::str_utils::{count_match_end, StrCount}; /// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4)); /// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0)); /// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6)); @@ -227,4 +295,31 @@ mod test { fn until_caps() { assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); } + + #[test] + fn camel_case_start_from_idx_full() { + assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0)); + assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3)); + assert_eq!(camel_case_start_from_idx("AbcDef", 4), StrIndex::new(6, 6)); + assert_eq!(camel_case_start_from_idx("AbcDefGhi", 0), StrIndex::new(0, 0)); + assert_eq!(camel_case_start_from_idx("AbcDefGhi", 1), StrIndex::new(3, 3)); + assert_eq!(camel_case_start_from_idx("Abcdefg", 1), StrIndex::new(7, 7)); + } + + #[test] + fn camel_case_indices_full() { + assert_eq!(camel_case_indices("Abc\u{f6}\u{f6}DD"), vec![StrIndex::new(7, 9)]); + } + + #[test] + fn camel_case_split_full() { + assert_eq!(camel_case_split("A"), vec!["A"]); + assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); + assert_eq!(camel_case_split("Abc"), vec!["Abc"]); + assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]); + assert_eq!( + camel_case_split("\u{f6}\u{f6}AabABcd"), + vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"] + ); + } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 586934df460..92662c59226 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -1,9 +1,7 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::source::{ - snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite, -}; +use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite}; use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ast, token}; @@ -33,7 +31,7 @@ pub enum Sugg<'a> { MaybeParen(Cow<'a, str>), /// A binary operator expression, including `as`-casts and explicit type /// coercion. - BinOp(AssocOp, Cow<'a, str>), + BinOp(AssocOp, Cow<'a, str>, Cow<'a, str>), } /// Literal constant `0`, for convenience. @@ -46,7 +44,8 @@ pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("")); impl Display for Sugg<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match *self { - Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => s.fmt(f), + Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) => s.fmt(f), + Sugg::BinOp(op, ref lhs, ref rhs) => binop_to_string(op, lhs, rhs).fmt(f), } } } @@ -55,10 +54,8 @@ impl Display for Sugg<'_> { impl<'a> Sugg<'a> { /// Prepare a suggestion from an expression. pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> { - snippet_opt(cx, expr.span).map(|snippet| { - let snippet = Cow::Owned(snippet); - Self::hir_from_snippet(expr, snippet) - }) + let get_snippet = |span| snippet(cx, span, ""); + snippet_opt(cx, expr.span).map(|_| Self::hir_from_snippet(expr, get_snippet)) } /// Convenience function around `hir_opt` for suggestions with a default @@ -93,9 +90,8 @@ impl<'a> Sugg<'a> { /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro. pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - let snippet = snippet_with_macro_callsite(cx, expr.span, default); - - Self::hir_from_snippet(expr, snippet) + let get_snippet = |span| snippet_with_macro_callsite(cx, span, default); + Self::hir_from_snippet(expr, get_snippet) } /// Same as `hir`, but first walks the span up to the given context. This will result in the @@ -112,24 +108,26 @@ impl<'a> Sugg<'a> { default: &'a str, applicability: &mut Applicability, ) -> Self { - let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability); - - if in_macro { - Sugg::NonParen(snippet) + if expr.span.ctxt() == ctxt { + Self::hir_from_snippet(expr, |span| snippet(cx, span, default)) } else { - Self::hir_from_snippet(expr, snippet) + let snip = snippet_with_applicability(cx, expr.span, default, applicability); + Sugg::NonParen(snip) } } /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*` /// function variants of `Sugg`, since these use different snippet functions. - fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self { + fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a, str>) -> Self { if let Some(range) = higher::Range::hir(expr) { let op = match range.limits { ast::RangeLimits::HalfOpen => AssocOp::DotDot, ast::RangeLimits::Closed => AssocOp::DotDotEq, }; - return Sugg::BinOp(op, snippet); + let start = range.start.map_or("".into(), |expr| get_snippet(expr.span)); + let end = range.end.map_or("".into(), |expr| get_snippet(expr.span)); + + return Sugg::BinOp(op, start, end); } match expr.kind { @@ -139,7 +137,7 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Let(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Unary(..) - | hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet), + | hir::ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)), hir::ExprKind::Continue(..) | hir::ExprKind::Yield(..) | hir::ExprKind::Array(..) @@ -160,12 +158,20 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Struct(..) | hir::ExprKind::Tup(..) | hir::ExprKind::DropTemps(_) - | hir::ExprKind::Err => Sugg::NonParen(snippet), - hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet), - hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet), - hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node.into()), snippet), - hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet), - hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet), + | hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)), + hir::ExprKind::Assign(lhs, rhs, _) => { + Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) + }, + hir::ExprKind::AssignOp(op, lhs, rhs) => { + 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()), + get_snippet(lhs.span), + get_snippet(rhs.span), + ), + hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), + hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Colon, get_snippet(lhs.span), get_snippet(ty.span)), } } @@ -173,10 +179,12 @@ impl<'a> Sugg<'a> { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use rustc_ast::ast::RangeLimits; - let snippet = if expr.span.from_expansion() { - snippet_with_macro_callsite(cx, expr.span, default) - } else { - snippet(cx, expr.span, default) + let get_whole_snippet = || { + if expr.span.from_expansion() { + snippet_with_macro_callsite(cx, expr.span, default) + } else { + snippet(cx, expr.span, default) + } }; match expr.kind { @@ -186,7 +194,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::If(..) | ast::ExprKind::Let(..) | ast::ExprKind::Unary(..) - | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet), + | ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()), ast::ExprKind::Async(..) | ast::ExprKind::Block(..) | ast::ExprKind::Break(..) @@ -215,14 +223,42 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err => Sugg::NonParen(snippet), - ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet), - ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet), - ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet), - ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet), - ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet), - ast::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet), - ast::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet), + | ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()), + ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( + AssocOp::DotDot, + lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)), + rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)), + ), + ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( + AssocOp::DotDotEq, + lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)), + rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)), + ), + ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp( + AssocOp::Assign, + snippet(cx, lhs.span, default), + snippet(cx, rhs.span, default), + ), + ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( + astbinop2assignop(op), + snippet(cx, lhs.span, default), + snippet(cx, rhs.span, default), + ), + ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( + AssocOp::from_ast_binop(op.node), + snippet(cx, lhs.span, default), + snippet(cx, rhs.span, default), + ), + ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp( + AssocOp::As, + snippet(cx, lhs.span, default), + snippet(cx, ty.span, default), + ), + ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( + AssocOp::Colon, + snippet(cx, lhs.span, default), + snippet(cx, ty.span, default), + ), } } @@ -306,17 +342,51 @@ impl<'a> Sugg<'a> { Sugg::NonParen(format!("({})", sugg).into()) } }, - Sugg::BinOp(_, sugg) => { - if has_enclosing_paren(&sugg) { - Sugg::NonParen(sugg) - } else { - Sugg::NonParen(format!("({})", sugg).into()) - } + Sugg::BinOp(op, lhs, rhs) => { + let sugg = binop_to_string(op, &lhs, &rhs); + Sugg::NonParen(format!("({})", sugg).into()) }, } } } +/// Generates a string from the operator and both sides. +fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { + match op { + AssocOp::Add + | AssocOp::Subtract + | AssocOp::Multiply + | AssocOp::Divide + | AssocOp::Modulus + | AssocOp::LAnd + | AssocOp::LOr + | AssocOp::BitXor + | AssocOp::BitAnd + | AssocOp::BitOr + | AssocOp::ShiftLeft + | AssocOp::ShiftRight + | AssocOp::Equal + | AssocOp::Less + | AssocOp::LessEqual + | AssocOp::NotEqual + | AssocOp::Greater + | AssocOp::GreaterEqual => format!( + "{} {} {}", + lhs, + op.to_ast_binop().expect("Those are AST ops").to_string(), + rhs + ), + AssocOp::Assign => format!("{} = {}", lhs, rhs), + AssocOp::AssignOp(op) => { + format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs) + }, + AssocOp::As => format!("{} as {}", lhs, rhs), + AssocOp::DotDot => format!("{}..{}", lhs, rhs), + AssocOp::DotDotEq => format!("{}..={}", lhs, rhs), + AssocOp::Colon => format!("{}: {}", lhs, rhs), + } +} + /// Return `true` if `sugg` is enclosed in parenthesis. fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool { let mut chars = sugg.as_ref().chars(); @@ -391,10 +461,25 @@ impl Neg for Sugg<'_> { } } -impl Not for Sugg<'_> { - type Output = Sugg<'static>; - fn not(self) -> Sugg<'static> { - make_unop("!", self) +impl Not for Sugg<'a> { + type Output = Sugg<'a>; + fn not(self) -> Sugg<'a> { + use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual}; + + if let Sugg::BinOp(op, lhs, rhs) = self { + let to_op = match op { + Equal => NotEqual, + NotEqual => Equal, + Less => GreaterEqual, + GreaterEqual => Less, + Greater => LessEqual, + LessEqual => Greater, + _ => return make_unop("!", Sugg::BinOp(op, lhs, rhs)), + }; + Sugg::BinOp(to_op, lhs, rhs) + } else { + make_unop("!", self) + } } } @@ -463,53 +548,21 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> || is_shift(other) && is_arith(op) } - let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs { + let lhs_paren = if let Sugg::BinOp(lop, _, _) = *lhs { needs_paren(op, lop, Associativity::Left) } else { false }; - let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs { + let rhs_paren = if let Sugg::BinOp(rop, _, _) = *rhs { needs_paren(op, rop, Associativity::Right) } else { false }; - let lhs = ParenHelper::new(lhs_paren, lhs); - let rhs = ParenHelper::new(rhs_paren, rhs); - let sugg = match op { - AssocOp::Add - | AssocOp::BitAnd - | AssocOp::BitOr - | AssocOp::BitXor - | AssocOp::Divide - | AssocOp::Equal - | AssocOp::Greater - | AssocOp::GreaterEqual - | AssocOp::LAnd - | AssocOp::LOr - | AssocOp::Less - | AssocOp::LessEqual - | AssocOp::Modulus - | AssocOp::Multiply - | AssocOp::NotEqual - | AssocOp::ShiftLeft - | AssocOp::ShiftRight - | AssocOp::Subtract => format!( - "{} {} {}", - lhs, - op.to_ast_binop().expect("Those are AST ops").to_string(), - rhs - ), - AssocOp::Assign => format!("{} = {}", lhs, rhs), - AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs), - AssocOp::As => format!("{} as {}", lhs, rhs), - AssocOp::DotDot => format!("{}..{}", lhs, rhs), - AssocOp::DotDotEq => format!("{}..={}", lhs, rhs), - AssocOp::Colon => format!("{}: {}", lhs, rhs), - }; - - Sugg::BinOp(op, sugg.into()) + let lhs = ParenHelper::new(lhs_paren, lhs).to_string(); + let rhs = ParenHelper::new(rhs_paren, rhs).to_string(); + Sugg::BinOp(op, lhs.into(), rhs.into()) } /// Convenience wrapper around `make_assoc` and `AssocOp::from_ast_binop`. @@ -1007,10 +1060,32 @@ mod test { #[test] fn binop_maybe_par() { - let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into()); + let sugg = Sugg::BinOp(AssocOp::Add, "1".into(), "1".into()); assert_eq!("(1 + 1)", sugg.maybe_par().to_string()); - let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1) + (1 + 1)".into()); + let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into(), "(1 + 1)".into()); assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string()); } + #[test] + fn not_op() { + use AssocOp::{Add, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, NotEqual}; + + fn test_not(op: AssocOp, correct: &str) { + let sugg = Sugg::BinOp(op, "x".into(), "y".into()); + assert_eq!((!sugg).to_string(), correct); + } + + // Invert the comparison operator. + test_not(Equal, "x != y"); + test_not(NotEqual, "x == y"); + test_not(Less, "x >= y"); + test_not(LessEqual, "x > y"); + test_not(Greater, "x <= y"); + test_not(GreaterEqual, "x < y"); + + // Other operators are inverted like !(..). + test_not(Add, "!(x + y)"); + test_not(LAnd, "!(x && y)"); + test_not(LOr, "!(x || y)"); + } } diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 3a5dfa6a8c7..471ae40f1ac 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-12-17" +channel = "nightly-2021-12-30" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr index d7b49eb89a2..111350a6280 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr @@ -7,7 +7,7 @@ LL | unsafe { 0 }; = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL ~ unsafe { 0 }; | diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index 083f5143e6e..d3662a0a213 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -145,4 +145,10 @@ enum HIDataRequest { DeleteUnpubHIData(String), } +enum North { + Normal, + NoLeft, + NoRight, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index add8a91e26b..8a3265086e8 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -6,6 +6,18 @@ LL | cFoo, | = note: `-D clippy::enum-variant-names` implied by `-D warnings` +error: all variants have the same prefix: `c` + --> $DIR/enum_variants.rs:14:1 + | +LL | / enum Foo { +LL | | cFoo, +LL | | cBar, +LL | | cBaz, +LL | | } + | |_^ + | + = help: remove the prefixes and use full paths to the variants instead of glob imports + error: variant name starts with the enum's name --> $DIR/enum_variants.rs:26:5 | @@ -60,25 +72,25 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: all variants have the same prefix: `WithOut` - --> $DIR/enum_variants.rs:81:1 +error: all variants have the same prefix: `C` + --> $DIR/enum_variants.rs:59:1 | -LL | / enum Seallll { -LL | | WithOutCake, -LL | | WithOutTea, -LL | | WithOut, +LL | / enum Something { +LL | | CCall, +LL | | CCreate, +LL | | CCryogenize, LL | | } | |_^ | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: all variants have the same prefix: `Prefix` - --> $DIR/enum_variants.rs:87:1 +error: all variants have the same prefix: `WithOut` + --> $DIR/enum_variants.rs:81:1 | -LL | / enum NonCaps { -LL | | Prefix的, -LL | | PrefixTea, -LL | | PrefixCake, +LL | / enum Seallll { +LL | | WithOutCake, +LL | | WithOutTea, +LL | | WithOut, LL | | } | |_^ | @@ -108,5 +120,5 @@ LL | | } | = help: remove the postfixes and use full paths to the variants instead of glob imports -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed index a35bb1c27f3..ce91fe176c6 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.fixed +++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed @@ -11,7 +11,12 @@ pub const fn const_context() { fn main() { let x = 3f32; let _ = x.to_degrees(); + let _ = 90.0_f64.to_degrees(); + let _ = 90.5_f64.to_degrees(); let _ = x.to_radians(); + let _ = 90.0_f64.to_radians(); + let _ = 90.5_f64.to_radians(); + // let _ = 90.5 * 80. * std::f32::consts::PI / 180f32; // Cases where the lint shouldn't be applied let _ = x * 90f32 / std::f32::consts::PI; let _ = x * std::f32::consts::PI / 90f32; diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs index 834db4be533..8f323498614 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.rs +++ b/src/tools/clippy/tests/ui/floating_point_rad.rs @@ -11,7 +11,12 @@ pub const fn const_context() { fn main() { let x = 3f32; let _ = x * 180f32 / std::f32::consts::PI; + let _ = 90. * 180f64 / std::f64::consts::PI; + let _ = 90.5 * 180f64 / std::f64::consts::PI; let _ = x * std::f32::consts::PI / 180f32; + let _ = 90. * std::f32::consts::PI / 180f32; + let _ = 90.5 * std::f32::consts::PI / 180f32; + // let _ = 90.5 * 80. * std::f32::consts::PI / 180f32; // Cases where the lint shouldn't be applied let _ = x * 90f32 / std::f32::consts::PI; let _ = x * std::f32::consts::PI / 90f32; diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr index acecddbca53..f12d3d23f3a 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.stderr +++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr @@ -6,11 +6,35 @@ LL | let _ = x * 180f32 / std::f32::consts::PI; | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` -error: conversion to radians can be done more accurately +error: conversion to degrees can be done more accurately --> $DIR/floating_point_rad.rs:14:13 | +LL | let _ = 90. * 180f64 / std::f64::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()` + +error: conversion to degrees can be done more accurately + --> $DIR/floating_point_rad.rs:15:13 + | +LL | let _ = 90.5 * 180f64 / std::f64::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()` + +error: conversion to radians can be done more accurately + --> $DIR/floating_point_rad.rs:16:13 + | LL | let _ = x * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` -error: aborting due to 2 previous errors +error: conversion to radians can be done more accurately + --> $DIR/floating_point_rad.rs:17:13 + | +LL | let _ = 90. * std::f32::consts::PI / 180f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()` + +error: conversion to radians can be done more accurately + --> $DIR/floating_point_rad.rs:18:13 + | +LL | let _ = 90.5 * std::f32::consts::PI / 180f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs index ceaacaaf6bd..2ed4b5db574 100644 --- a/src/tools/clippy/tests/ui/identity_op.rs +++ b/src/tools/clippy/tests/ui/identity_op.rs @@ -2,10 +2,20 @@ const ONE: i64 = 1; const NEG_ONE: i64 = -1; const ZERO: i64 = 0; +struct A(String); + +impl std::ops::Shl<i32> for A { + type Output = A; + fn shl(mut self, other: i32) -> Self { + self.0.push_str(&format!("{}", other)); + self + } +} #[allow( clippy::eq_op, clippy::no_effect, clippy::unnecessary_operation, + clippy::op_ref, clippy::double_parens )] #[warn(clippy::identity_op)] @@ -38,4 +48,9 @@ fn main() { 42 << 0; 1 >> 0; 42 >> 0; + &x >> 0; + x >> &0; + + let mut a = A("".into()); + let b = a << 0; // no error: non-integer } diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr index d8d44a74f9a..ff34b38db01 100644 --- a/src/tools/clippy/tests/ui/identity_op.stderr +++ b/src/tools/clippy/tests/ui/identity_op.stderr @@ -1,5 +1,5 @@ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:16:5 + --> $DIR/identity_op.rs:26:5 | LL | x + 0; | ^^^^^ @@ -7,64 +7,76 @@ LL | x + 0; = note: `-D clippy::identity-op` implied by `-D warnings` error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:17:5 + --> $DIR/identity_op.rs:27:5 | LL | x + (1 - 1); | ^^^^^^^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:19:5 + --> $DIR/identity_op.rs:29:5 | LL | 0 + x; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:22:5 + --> $DIR/identity_op.rs:32:5 | LL | x | (0); | ^^^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:25:5 + --> $DIR/identity_op.rs:35:5 | LL | x * 1; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:26:5 + --> $DIR/identity_op.rs:36:5 | LL | 1 * x; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:32:5 + --> $DIR/identity_op.rs:42:5 | LL | -1 & x; | ^^^^^^ error: the operation is ineffective. Consider reducing it to `u` - --> $DIR/identity_op.rs:35:5 + --> $DIR/identity_op.rs:45:5 | LL | u & 255; | ^^^^^^^ error: the operation is ineffective. Consider reducing it to `42` - --> $DIR/identity_op.rs:38:5 + --> $DIR/identity_op.rs:48:5 | LL | 42 << 0; | ^^^^^^^ error: the operation is ineffective. Consider reducing it to `1` - --> $DIR/identity_op.rs:39:5 + --> $DIR/identity_op.rs:49:5 | LL | 1 >> 0; | ^^^^^^ error: the operation is ineffective. Consider reducing it to `42` - --> $DIR/identity_op.rs:40:5 + --> $DIR/identity_op.rs:50:5 | LL | 42 >> 0; | ^^^^^^^ -error: aborting due to 11 previous errors +error: the operation is ineffective. Consider reducing it to `&x` + --> $DIR/identity_op.rs:51:5 + | +LL | &x >> 0; + | ^^^^^^^ + +error: the operation is ineffective. Consider reducing it to `x` + --> $DIR/identity_op.rs:52:5 + | +LL | x >> &0; + | ^^^^^^^ + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed index 928b6acb951..2db4c2bee7f 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.fixed +++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed @@ -4,6 +4,7 @@ #![warn(clippy::iter_skip_next)] #![allow(clippy::blacklisted_name)] #![allow(clippy::iter_nth)] +#![allow(unused_mut, dead_code)] extern crate option_helpers; @@ -19,4 +20,18 @@ fn main() { let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); + + // fix #8128 + let test_string = "1|1 2"; + let mut sp = test_string.split('|').map(|s| s.trim()); + let _: Vec<&str> = sp.nth(1).unwrap().split(' ').collect(); + if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) { + let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect(); + }; + fn check<T>(mut s: T) + where + T: Iterator<Item = String>, + { + let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect(); + } } diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs index 7075e2598eb..692edb9aed9 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.rs +++ b/src/tools/clippy/tests/ui/iter_skip_next.rs @@ -4,6 +4,7 @@ #![warn(clippy::iter_skip_next)] #![allow(clippy::blacklisted_name)] #![allow(clippy::iter_nth)] +#![allow(unused_mut, dead_code)] extern crate option_helpers; @@ -19,4 +20,18 @@ fn main() { let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); + + // fix #8128 + let test_string = "1|1 2"; + let mut sp = test_string.split('|').map(|s| s.trim()); + let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + }; + fn check<T>(mut s: T) + where + T: Iterator<Item = String>, + { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + } } diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr index 486de718bb5..ca6970b27f1 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr @@ -1,5 +1,5 @@ error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:15:28 + --> $DIR/iter_skip_next.rs:16:28 | LL | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` @@ -7,22 +7,40 @@ LL | let _ = some_vec.iter().skip(42).next(); = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:16:36 + --> $DIR/iter_skip_next.rs:17:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:17:20 + --> $DIR/iter_skip_next.rs:18:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:18:33 + --> $DIR/iter_skip_next.rs:19:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)` -error: aborting due to 4 previous errors +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next.rs:27:26 + | +LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next.rs:29:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next.rs:35:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs new file mode 100644 index 00000000000..3607330cfa0 --- /dev/null +++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs @@ -0,0 +1,19 @@ +#![warn(clippy::iter_skip_next)] +#![allow(dead_code)] + +/// Checks implementation of `ITER_SKIP_NEXT` lint +fn main() { + // fix #8128 + let test_string = "1|1 2"; + let sp = test_string.split('|').map(|s| s.trim()); + let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + }; + fn check<T>(s: T) + where + T: Iterator<Item = String>, + { + let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + } +} diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr new file mode 100644 index 00000000000..74c327c7483 --- /dev/null +++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr @@ -0,0 +1,39 @@ +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next_unfixable.rs:9:26 + | +LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + | + = note: `-D clippy::iter-skip-next` implied by `-D warnings` +help: for this change `sp` has to be mutable + --> $DIR/iter_skip_next_unfixable.rs:8:9 + | +LL | let sp = test_string.split('|').map(|s| s.trim()); + | ^^ + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next_unfixable.rs:11:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + | +help: for this change `s` has to be mutable + --> $DIR/iter_skip_next_unfixable.rs:10:17 + | +LL | if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) { + | ^ + +error: called `skip(..).next()` on an iterator + --> $DIR/iter_skip_next_unfixable.rs:17:29 + | +LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` + | +help: for this change `s` has to be mutable + --> $DIR/iter_skip_next_unfixable.rs:13:17 + | +LL | fn check<T>(s: T) + | ^ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr index 0243158dec5..2e3ebadd7b5 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -43,7 +43,7 @@ LL | / for i in 3..(3 + src.len()) { LL | | dst[i] = src[count]; LL | | count += 1; LL | | } - | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..((3 + src.len()) - 3)]);` + | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..(3 + src.len() - 3)]);` error: it looks like you're manually copying between slices --> $DIR/with_loop_counters.rs:35:5 diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed index 85da1f4e104..89dc13fd5b1 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed @@ -41,6 +41,15 @@ fn main() { x; !x; !(x && y); + let a = 0; + let b = 1; + + a != b; + a == b; + a >= b; + a > b; + a <= b; + a < b; if x { x } else { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs index add60630251..c11d9472e8d 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs @@ -53,6 +53,39 @@ fn main() { } else { true }; + let a = 0; + let b = 1; + + if a == b { + false + } else { + true + }; + if a != b { + false + } else { + true + }; + if a < b { + false + } else { + true + }; + if a <= b { + false + } else { + true + }; + if a > b { + false + } else { + true + }; + if a >= b { + false + } else { + true + }; if x { x } else { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index 22c0a7bb491..d2c48376f76 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -31,7 +31,67 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:72:5 + --> $DIR/fixable.rs:59:5 + | +LL | / if a == b { +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ help: you can reduce it to: `a != b` + +error: this if-then-else expression returns a bool literal + --> $DIR/fixable.rs:64:5 + | +LL | / if a != b { +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ help: you can reduce it to: `a == b` + +error: this if-then-else expression returns a bool literal + --> $DIR/fixable.rs:69:5 + | +LL | / if a < b { +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ help: you can reduce it to: `a >= b` + +error: this if-then-else expression returns a bool literal + --> $DIR/fixable.rs:74:5 + | +LL | / if a <= b { +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ help: you can reduce it to: `a > b` + +error: this if-then-else expression returns a bool literal + --> $DIR/fixable.rs:79:5 + | +LL | / if a > b { +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ help: you can reduce it to: `a <= b` + +error: this if-then-else expression returns a bool literal + --> $DIR/fixable.rs:84:5 + | +LL | / if a >= b { +LL | | false +LL | | } else { +LL | | true +LL | | }; + | |_____^ help: you can reduce it to: `a < b` + +error: this if-then-else expression returns a bool literal + --> $DIR/fixable.rs:105:5 | LL | / if x { LL | | return true; @@ -41,7 +101,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:80:5 + --> $DIR/fixable.rs:113:5 | LL | / if x { LL | | return false; @@ -51,7 +111,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:88:5 + --> $DIR/fixable.rs:121:5 | LL | / if x && y { LL | | return true; @@ -61,7 +121,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:96:5 + --> $DIR/fixable.rs:129:5 | LL | / if x && y { LL | | return false; @@ -71,7 +131,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:104:8 + --> $DIR/fixable.rs:137:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -79,25 +139,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:108:8 + --> $DIR/fixable.rs:141:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:118:8 + --> $DIR/fixable.rs:151:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:119:8 + --> $DIR/fixable.rs:152:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:128:12 + --> $DIR/fixable.rs:161:12 | LL | } else if returns_bool() { | ____________^ @@ -108,7 +168,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:141:5 + --> $DIR/fixable.rs:174:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -118,16 +178,16 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:146:30 + --> $DIR/fixable.rs:179:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:149:9 + --> $DIR/fixable.rs:182:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` -error: aborting due to 15 previous errors +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index 83f467c8400..603d438d558 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -71,7 +71,18 @@ fn test_void_if_fun(b: bool) { fn test_void_match(x: u32) { match x { 0 => (), - _ => {}, + _ => (), + } +} + +fn test_nested_match(x: u32) { + match x { + 0 => (), + 1 => { + let _ = 42; + + }, + _ => (), } } @@ -182,7 +193,7 @@ async fn async_test_void_if_fun(b: bool) { async fn async_test_void_match(x: u32) { match x { 0 => (), - _ => {}, + _ => (), } } diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index 341caf18bd6..c6c8cb9ec15 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -75,6 +75,17 @@ fn test_void_match(x: u32) { } } +fn test_nested_match(x: u32) { + match x { + 0 => (), + 1 => { + let _ = 42; + return; + }, + _ => return, + } +} + fn read_line() -> String { use std::io::BufRead; let stdin = ::std::io::stdin(); diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index c0abc2c63dd..5bc787c56a6 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -70,127 +70,139 @@ error: unneeded `return` statement --> $DIR/needless_return.rs:74:14 | LL | _ => return, - | ^^^^^^ help: replace `return` with an empty block: `{}` + | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:89:9 + --> $DIR/needless_return.rs:83:13 + | +LL | return; + | ^^^^^^^ help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:85:14 + | +LL | _ => return, + | ^^^^^^ help: replace `return` with a unit value: `()` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:100:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:91:9 + --> $DIR/needless_return.rs:102:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:113:32 + --> $DIR/needless_return.rs:124:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:118:13 + --> $DIR/needless_return.rs:129:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:120:20 + --> $DIR/needless_return.rs:131:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:126:32 + --> $DIR/needless_return.rs:137:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:135:5 + --> $DIR/needless_return.rs:146:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:139:5 + --> $DIR/needless_return.rs:150:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:144:9 + --> $DIR/needless_return.rs:155:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:146:9 + --> $DIR/needless_return.rs:157:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:152:17 + --> $DIR/needless_return.rs:163:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:154:13 + --> $DIR/needless_return.rs:165:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:161:9 + --> $DIR/needless_return.rs:172:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:163:16 + --> $DIR/needless_return.rs:174:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:171:5 + --> $DIR/needless_return.rs:182:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:176:9 + --> $DIR/needless_return.rs:187:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:178:9 + --> $DIR/needless_return.rs:189:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:185:14 + --> $DIR/needless_return.rs:196:14 | LL | _ => return, - | ^^^^^^ help: replace `return` with an empty block: `{}` + | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:200:9 + --> $DIR/needless_return.rs:211:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:202:9 + --> $DIR/needless_return.rs:213:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` -error: aborting due to 32 previous errors +error: aborting due to 34 previous errors diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed new file mode 100644 index 00000000000..35af9d6ae31 --- /dev/null +++ b/src/tools/clippy/tests/ui/neg_multiply.fixed @@ -0,0 +1,45 @@ +// run-rustfix +#![warn(clippy::neg_multiply)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] +#![allow(unused)] + +use std::ops::Mul; + +struct X; + +impl Mul<isize> for X { + type Output = X; + + fn mul(self, _r: isize) -> Self { + self + } +} + +impl Mul<X> for isize { + type Output = X; + + fn mul(self, _r: X) -> X { + X + } +} + +fn main() { + let x = 0; + + -x; + + -x; + + 100 + -x; + + -(100 + x); + + -17; + + 0xcafe | -0xff00; + + -1 * -1; // should be ok + + X * -1; // should be ok + -1 * X; // should also be ok +} diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs index d4a20ce9db1..7dbdb0906ce 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.rs +++ b/src/tools/clippy/tests/ui/neg_multiply.rs @@ -1,5 +1,7 @@ +// run-rustfix #![warn(clippy::neg_multiply)] -#![allow(clippy::no_effect, clippy::unnecessary_operation)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] +#![allow(unused)] use std::ops::Mul; @@ -28,6 +30,14 @@ fn main() { -1 * x; + 100 + x * -1; + + (100 + x) * -1; + + -1 * 17; + + 0xcafe | 0xff00 * -1; + -1 * -1; // should be ok X * -1; // should be ok diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr index ad677f6d6fb..dbf8fb36938 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.stderr +++ b/src/tools/clippy/tests/ui/neg_multiply.stderr @@ -1,16 +1,40 @@ -error: negation by multiplying with `-1` - --> $DIR/neg_multiply.rs:27:5 +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:29:5 | LL | x * -1; - | ^^^^^^ + | ^^^^^^ help: consider using: `-x` | = note: `-D clippy::neg-multiply` implied by `-D warnings` -error: negation by multiplying with `-1` - --> $DIR/neg_multiply.rs:29:5 +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:31:5 | LL | -1 * x; - | ^^^^^^ + | ^^^^^^ help: consider using: `-x` + +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:33:11 + | +LL | 100 + x * -1; + | ^^^^^^ help: consider using: `-x` + +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:35:5 + | +LL | (100 + x) * -1; + | ^^^^^^^^^^^^^^ help: consider using: `-(100 + x)` + +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:37:5 + | +LL | -1 * 17; + | ^^^^^^^ help: consider using: `-17` + +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:39:14 + | +LL | 0xcafe | 0xff00 * -1; + | ^^^^^^^^^^^ help: consider using: `-0xff00` -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/numbered_fields.fixed b/src/tools/clippy/tests/ui/numbered_fields.fixed new file mode 100644 index 00000000000..1da97e96879 --- /dev/null +++ b/src/tools/clippy/tests/ui/numbered_fields.fixed @@ -0,0 +1,33 @@ +//run-rustfix +#![warn(clippy::init_numbered_fields)] + +#[derive(Default)] +struct TupleStruct(u32, u32, u8); + +// This shouldn't lint because it's in a macro +macro_rules! tuple_struct_init { + () => { + TupleStruct { 0: 0, 1: 1, 2: 2 } + }; +} + +fn main() { + let tuple_struct = TupleStruct::default(); + + // This should lint + let _ = TupleStruct(1u32, 42, 23u8); + + // This should also lint and order the fields correctly + let _ = TupleStruct(1u32, 3u32, 2u8); + + // Ok because of default initializer + let _ = TupleStruct { 0: 42, ..tuple_struct }; + + let _ = TupleStruct { + 1: 23, + ..TupleStruct::default() + }; + + // Ok because it's in macro + let _ = tuple_struct_init!(); +} diff --git a/src/tools/clippy/tests/ui/numbered_fields.rs b/src/tools/clippy/tests/ui/numbered_fields.rs new file mode 100644 index 00000000000..08ec405a560 --- /dev/null +++ b/src/tools/clippy/tests/ui/numbered_fields.rs @@ -0,0 +1,41 @@ +//run-rustfix +#![warn(clippy::init_numbered_fields)] + +#[derive(Default)] +struct TupleStruct(u32, u32, u8); + +// This shouldn't lint because it's in a macro +macro_rules! tuple_struct_init { + () => { + TupleStruct { 0: 0, 1: 1, 2: 2 } + }; +} + +fn main() { + let tuple_struct = TupleStruct::default(); + + // This should lint + let _ = TupleStruct { + 0: 1u32, + 1: 42, + 2: 23u8, + }; + + // This should also lint and order the fields correctly + let _ = TupleStruct { + 0: 1u32, + 2: 2u8, + 1: 3u32, + }; + + // Ok because of default initializer + let _ = TupleStruct { 0: 42, ..tuple_struct }; + + let _ = TupleStruct { + 1: 23, + ..TupleStruct::default() + }; + + // Ok because it's in macro + let _ = tuple_struct_init!(); +} diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/numbered_fields.stderr new file mode 100644 index 00000000000..01691c8b141 --- /dev/null +++ b/src/tools/clippy/tests/ui/numbered_fields.stderr @@ -0,0 +1,26 @@ +error: used a field initializer for a tuple struct + --> $DIR/numbered_fields.rs:18:13 + | +LL | let _ = TupleStruct { + | _____________^ +LL | | 0: 1u32, +LL | | 1: 42, +LL | | 2: 23u8, +LL | | }; + | |_____^ help: try this instead: `TupleStruct(1u32, 42, 23u8)` + | + = note: `-D clippy::init-numbered-fields` implied by `-D warnings` + +error: used a field initializer for a tuple struct + --> $DIR/numbered_fields.rs:25:13 + | +LL | let _ = TupleStruct { + | _____________^ +LL | | 0: 1u32, +LL | | 2: 2u8, +LL | | 1: 3u32, +LL | | }; + | |_____^ help: try this instead: `TupleStruct(1u32, 3u32, 2u8)` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.rs b/src/tools/clippy/tests/ui/return_self_not_must_use.rs index bdf3f3d7995..7dd5742dae9 100644 --- a/src/tools/clippy/tests/ui/return_self_not_must_use.rs +++ b/src/tools/clippy/tests/ui/return_self_not_must_use.rs @@ -5,12 +5,12 @@ pub struct Bar; pub trait Whatever { fn what(&self) -> Self; - // There should be no warning here! + // There should be no warning here! (returns a reference) fn what2(&self) -> &Self; } impl Bar { - // There should be no warning here! + // There should be no warning here! (note taking a self argument) pub fn not_new() -> Self { Self } @@ -20,23 +20,38 @@ impl Bar { pub fn bar(self) -> Self { self } - // There should be no warning here! + // There should be no warning here! (private method) fn foo2(&self) -> Self { Self } - // There should be no warning here! + // There should be no warning here! (returns a reference) pub fn foo3(&self) -> &Self { self } + // There should be no warning here! (already a `must_use` attribute) + #[must_use] + pub fn foo4(&self) -> Self { + Self + } } impl Whatever for Bar { - // There should be no warning here! + // There should be no warning here! (comes from the trait) fn what(&self) -> Self { self.foo2() } - // There should be no warning here! + // There should be no warning here! (comes from the trait) fn what2(&self) -> &Self { self } } + +#[must_use] +pub struct Foo; + +impl Foo { + // There should be no warning here! (`Foo` already implements `#[must_use]`) + fn foo(&self) -> Self { + Self + } +} diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs index 06f6949b66f..0321f8c4cdf 100644 --- a/src/tools/clippy/tests/ui/shadow.rs +++ b/src/tools/clippy/tests/ui/shadow.rs @@ -47,6 +47,8 @@ fn syntax() { let _ = |[x]: [u32; 1]| { let x = 1; }; + let y = Some(1); + if let Some(y) = y {} } fn negative() { diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr index dcc7d4e6b2f..f8b9221d555 100644 --- a/src/tools/clippy/tests/ui/shadow.stderr +++ b/src/tools/clippy/tests/ui/shadow.stderr @@ -241,17 +241,29 @@ note: previous binding is here LL | let _ = |[x]: [u32; 1]| { | ^ +error: `y` is shadowed + --> $DIR/shadow.rs:51:17 + | +LL | if let Some(y) = y {} + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:50:9 + | +LL | let y = Some(1); + | ^ + error: `_b` shadows a previous, unrelated binding - --> $DIR/shadow.rs:85:9 + --> $DIR/shadow.rs:87:9 | LL | let _b = _a; | ^^ | note: previous binding is here - --> $DIR/shadow.rs:84:28 + --> $DIR/shadow.rs:86:28 | LL | pub async fn foo2(_a: i32, _b: i64) { | ^^ -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.fixed b/src/tools/clippy/tests/ui/short_circuit_statement.fixed index af0a397bd1a..dd22ecab0b5 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.fixed +++ b/src/tools/clippy/tests/ui/short_circuit_statement.fixed @@ -6,7 +6,7 @@ fn main() { if f() { g(); } if !f() { g(); } - if !(1 == 2) { g(); } + if 1 != 2 { g(); } } fn f() -> bool { diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.stderr b/src/tools/clippy/tests/ui/short_circuit_statement.stderr index 0a3f60c3d13..aa84ac3a792 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.stderr +++ b/src/tools/clippy/tests/ui/short_circuit_statement.stderr @@ -16,7 +16,7 @@ error: boolean short circuit operator in statement may be clearer using an expli --> $DIR/short_circuit_statement.rs:9:5 | LL | 1 == 2 || g(); - | ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }` + | ^^^^^^^^^^^^^^ help: replace it with: `if 1 != 2 { g(); }` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs index 7e510d89475..380303d8152 100644 --- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs @@ -5,7 +5,7 @@ fn nested_local() { let _ = { let _ = { - // Safety: + // SAFETY: let _ = unsafe {}; }; }; @@ -14,7 +14,7 @@ fn nested_local() { fn deep_nest() { let _ = { let _ = { - // Safety: + // SAFETY: let _ = unsafe {}; // Safety: @@ -28,7 +28,7 @@ fn deep_nest() { // Safety: let _ = unsafe {}; - // Safety: + // SAFETY: unsafe {}; }; }; @@ -44,7 +44,7 @@ fn deep_nest() { unsafe {}; }; - // Safety: + // SAFETY: unsafe {}; } @@ -59,7 +59,7 @@ fn line_comment() { } fn line_comment_newlines() { - // Safety: + // SAFETY: unsafe {} } @@ -84,7 +84,7 @@ fn block_comment() { } fn block_comment_newlines() { - /* Safety: */ + /* SAFETY: */ unsafe {} } @@ -96,7 +96,7 @@ fn inline_block_comment() { fn block_comment_with_extras() { /* This is a description - * Safety: + * SAFETY: */ unsafe {} } @@ -122,7 +122,7 @@ fn buried_safety() { } fn safety_with_prepended_text() { - // This is a test. Safety: + // This is a test. safety: unsafe {} } @@ -132,7 +132,7 @@ fn local_line_comment() { } fn local_block_comment() { - /* Safety: */ + /* SAFETY: */ let _ = unsafe {}; } @@ -142,18 +142,18 @@ fn comment_array() { } fn comment_tuple() { - // Safety: + // sAFETY: let _ = (42, unsafe {}, "test", unsafe {}); } fn comment_unary() { - // Safety: + // SAFETY: let _ = *unsafe { &42 }; } #[allow(clippy::match_single_binding)] fn comment_match() { - // Safety: + // SAFETY: let _ = match unsafe {} { _ => {}, }; @@ -177,7 +177,7 @@ fn comment_macro_call() { } t!( - // Safety: + // SAFETY: unsafe {} ); } @@ -194,18 +194,18 @@ fn comment_macro_def() { } fn non_ascii_comment() { - // ॐ᧻໒ Safety: ௵∰ + // ॐ᧻໒ SaFeTy: ௵∰ unsafe {}; } fn local_commented_block() { let _ = - // Safety: + // safety: unsafe {}; } fn local_nest() { - // Safety: + // safety: let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})]; } @@ -267,17 +267,17 @@ fn no_comment_macro_def() { } fn trailing_comment() { - unsafe {} // Safety: + unsafe {} // SAFETY: } fn internal_comment() { unsafe { - // Safety: + // SAFETY: } } fn interference() { - // Safety + // SAFETY let _ = 42; diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr index ebe589001a1..f69d0da54e0 100644 --- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr +++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr @@ -7,7 +7,7 @@ LL | unsafe {} = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + unsafe {} | @@ -19,7 +19,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | @@ -31,7 +31,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = (42, unsafe {}, "test", unsafe {}); | @@ -43,7 +43,7 @@ LL | let _ = *unsafe { &42 }; | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = *unsafe { &42 }; | @@ -55,7 +55,7 @@ LL | let _ = match unsafe {} { | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = match unsafe {} { | @@ -67,7 +67,7 @@ LL | let _ = &unsafe {}; | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = &unsafe {}; | @@ -79,7 +79,7 @@ LL | let _ = [unsafe {}; 5]; | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = [unsafe {}; 5]; | @@ -91,7 +91,7 @@ LL | let _ = unsafe {}; | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + let _ = unsafe {}; | @@ -103,7 +103,7 @@ LL | t!(unsafe {}); | help: consider adding a safety comment | -LL ~ t!(// Safety: ... +LL ~ t!(// SAFETY: ... LL ~ unsafe {}); | @@ -122,13 +122,13 @@ LL | t!(); error: unsafe block missing a safety comment --> $DIR/undocumented_unsafe_blocks.rs:270:5 | -LL | unsafe {} // Safety: +LL | unsafe {} // SAFETY: | ^^^^^^^^^ | help: consider adding a safety comment | -LL ~ // Safety: ... -LL ~ unsafe {} // Safety: +LL ~ // SAFETY: ... +LL ~ unsafe {} // SAFETY: | error: unsafe block missing a safety comment @@ -139,7 +139,7 @@ LL | unsafe { | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL + unsafe { | @@ -151,7 +151,7 @@ LL | unsafe {}; | help: consider adding a safety comment | -LL ~ // Safety: ... +LL ~ // SAFETY: ... LL ~ unsafe {}; | @@ -163,7 +163,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | help: consider adding a safety comment | -LL ~ println!("{}", // Safety: ... +LL ~ println!("{}", // SAFETY: ... LL ~ unsafe { String::from_utf8_unchecked(vec![]) }); | diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed index c2e38037add..e726b652ef1 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.fixed +++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed @@ -30,7 +30,7 @@ fn main() { 1_234.123_f32, 1.123_4_f32, ); - let _bad = (0b11_0110_i64, 0xcafe_babe_usize, 123_456_f32, 1.234_567_f32); + let _bad = (0b11_0110_i64, 0x1234_5678_usize, 123_456_f32, 1.234_567_f32); let _good_sci = 1.1234e1; let _bad_sci = 1.123_456e1; diff --git a/src/tools/clippy/tests/ui/unreadable_literal.rs b/src/tools/clippy/tests/ui/unreadable_literal.rs index 8296945b25e..5bbb2fc9dc1 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.rs +++ b/src/tools/clippy/tests/ui/unreadable_literal.rs @@ -30,7 +30,7 @@ fn main() { 1_234.123_f32, 1.123_4_f32, ); - let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); + let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); let _good_sci = 1.1234e1; let _bad_sci = 1.123456e1; diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr index 8436aac17ac..ee5466fd517 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.stderr +++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr @@ -9,7 +9,7 @@ LL | 0x1_234_567, error: long literal lacking separators --> $DIR/unreadable_literal.rs:33:17 | -LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); +LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` | = note: `-D clippy::unreadable-literal` implied by `-D warnings` @@ -17,19 +17,19 @@ LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); error: long literal lacking separators --> $DIR/unreadable_literal.rs:33:31 | -LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); - | ^^^^^^^^^^^^^^^^ help: consider: `0xcafe_babe_usize` +LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); + | ^^^^^^^^^^^^^^^^ help: consider: `0x1234_5678_usize` error: long literal lacking separators --> $DIR/unreadable_literal.rs:33:49 | -LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); +LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^ help: consider: `123_456_f32` error: long literal lacking separators --> $DIR/unreadable_literal.rs:33:61 | -LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); +LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed index 7ac3f426c97..c2b9bd2c881 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed @@ -45,7 +45,7 @@ fn unwrap_or_else_default() { with_enum.unwrap_or_else(Enum::A); let with_new = Some(vec![1]); - with_new.unwrap_or_else(Vec::new); + with_new.unwrap_or_default(); let with_err: Result<_, ()> = Ok(vec![1]); with_err.unwrap_or_else(make); @@ -66,6 +66,9 @@ fn unwrap_or_else_default() { let with_default_type = Some(1); with_default_type.unwrap_or_default(); + + let with_default_type: Option<Vec<u64>> = None; + with_default_type.unwrap_or_default(); } fn main() {} diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs index 82b727a039e..d55664990ae 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs @@ -66,6 +66,9 @@ fn unwrap_or_else_default() { let with_default_type = Some(1); with_default_type.unwrap_or_else(u64::default); + + let with_default_type: Option<Vec<u64>> = None; + with_default_type.unwrap_or_else(Vec::new); } fn main() {} diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr index feb215b09f6..53e31d85edf 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr @@ -1,10 +1,16 @@ error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:48:5 + | +LL | with_new.unwrap_or_else(Vec::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()` + | + = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` + +error: use of `.unwrap_or_else(..)` to construct default value --> $DIR/unwrap_or_else_default.rs:62:5 | LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()` - | - = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings` error: use of `.unwrap_or_else(..)` to construct default value --> $DIR/unwrap_or_else_default.rs:65:5 @@ -18,5 +24,11 @@ error: use of `.unwrap_or_else(..)` to construct default value LL | with_default_type.unwrap_or_else(u64::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` -error: aborting due to 3 previous errors +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:71:5 + | +LL | with_default_type.unwrap_or_else(Vec::new); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` + +error: aborting due to 5 previous errors diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain index 1d2cad66751..d4cdcec2018 100644 --- a/src/tools/rustfmt/rust-toolchain +++ b/src/tools/rustfmt/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-11-08" +channel = "nightly-2021-12-29" components = ["rustc-dev"] diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 9d2e97c9479..4d845547cdf 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -26,7 +26,7 @@ fn main() { let exit_code = match execute(&opts) { Ok(code) => code, Err(e) => { - eprintln!("{}", e.to_string()); + eprintln!("{}", e); 1 } }; diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index 34d73a77fd3..e688db1c39d 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -236,21 +236,21 @@ fn rewrite_closure_fn_decl( context: &RewriteContext<'_>, shape: Shape, ) -> Option<(String, usize)> { - let is_async = if asyncness.is_async() { "async " } else { "" }; - let mover = if capture == ast::CaptureBy::Value { - "move " + let immovable = if movability == ast::Movability::Static { + "static " } else { "" }; - let immovable = if movability == ast::Movability::Static { - "static " + let is_async = if asyncness.is_async() { "async " } else { "" }; + let mover = if capture == ast::CaptureBy::Value { + "move " } else { "" }; // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. let nested_shape = shape - .shrink_left(is_async.len() + mover.len() + immovable.len())? + .shrink_left(immovable.len() + is_async.len() + mover.len())? .sub_width(4)?; // 1 = | @@ -288,7 +288,7 @@ fn rewrite_closure_fn_decl( .tactic(tactic) .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{}{}{}|{}|", is_async, immovable, mover, list_str); + let mut prefix = format!("{}{}{}|{}|", immovable, is_async, mover, list_str); if !ret_str.is_empty() { if prefix.contains('\n') { diff --git a/src/tools/rustfmt/src/config/file_lines.rs b/src/tools/rustfmt/src/config/file_lines.rs index 4b799780d85..7b498dc46b3 100644 --- a/src/tools/rustfmt/src/config/file_lines.rs +++ b/src/tools/rustfmt/src/config/file_lines.rs @@ -13,9 +13,9 @@ use thiserror::Error; /// A range of lines in a file, inclusive of both ends. pub struct LineRange { - pub file: Lrc<SourceFile>, - pub lo: usize, - pub hi: usize, + pub(crate) file: Lrc<SourceFile>, + pub(crate) lo: usize, + pub(crate) hi: usize, } /// Defines the name of an input - either a file or stdin. @@ -75,7 +75,7 @@ impl Serialize for FileName { } impl LineRange { - pub fn file_name(&self) -> FileName { + pub(crate) fn file_name(&self) -> FileName { self.file.name.clone().into() } } diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index bce9e5d07f2..d857c29be29 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -218,24 +218,24 @@ pub enum Verbosity { pub struct WidthHeuristics { // Maximum width of the args of a function call before falling back // to vertical formatting. - pub fn_call_width: usize, + pub(crate) fn_call_width: usize, // Maximum width of the args of a function-like attributes before falling // back to vertical formatting. - pub attr_fn_like_width: usize, + pub(crate) attr_fn_like_width: usize, // Maximum width in the body of a struct lit before falling back to // vertical formatting. - pub struct_lit_width: usize, + pub(crate) struct_lit_width: usize, // Maximum width in the body of a struct variant before falling back // to vertical formatting. - pub struct_variant_width: usize, + pub(crate) struct_variant_width: usize, // Maximum width of an array literal before falling back to vertical // formatting. - pub array_width: usize, + pub(crate) array_width: usize, // Maximum length of a chain to fit on a single line. - pub chain_width: usize, + pub(crate) chain_width: usize, // Maximum line length for single line if-else expressions. A value // of zero means always break if-else expressions. - pub single_line_if_else_max_width: usize, + pub(crate) single_line_if_else_max_width: usize, } impl fmt::Display for WidthHeuristics { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 5fd86c1a4ea..c9c8852cd3b 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -108,9 +108,21 @@ pub(crate) fn format_expr( ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape), ast::ExprKind::Struct(ref struct_expr) => { let ast::StructExpr { - fields, path, rest, .. + qself, + fields, + path, + rest, } = &**struct_expr; - rewrite_struct_lit(context, path, fields, rest, &expr.attrs, expr.span, shape) + rewrite_struct_lit( + context, + path, + qself.as_ref(), + fields, + rest, + &expr.attrs, + expr.span, + shape, + ) } ast::ExprKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1) @@ -1511,6 +1523,7 @@ fn struct_lit_can_be_aligned(fields: &[ast::ExprField], has_base: bool) -> bool fn rewrite_struct_lit<'a>( context: &RewriteContext<'_>, path: &ast::Path, + qself: Option<&ast::QSelf>, fields: &'a [ast::ExprField], struct_rest: &ast::StructRest, attrs: &[ast::Attribute], @@ -1527,7 +1540,7 @@ fn rewrite_struct_lit<'a>( // 2 = " {".len() let path_shape = shape.sub_width(2)?; - let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?; + let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?; let has_base_or_rest = match struct_rest { ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)), @@ -2003,9 +2016,7 @@ fn choose_rhs<R: Rewrite>( has_rhs_comment: bool, ) -> Option<String> { match orig_rhs { - Some(ref new_str) if new_str.is_empty() => { - return Some(String::new()); - } + Some(ref new_str) if new_str.is_empty() => Some(String::new()), Some(ref new_str) if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width => { diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index 7d0facb8f12..67cf1232f66 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -5,6 +5,7 @@ use std::io::{self, Write}; use std::time::{Duration, Instant}; use rustc_ast::ast; +use rustc_ast::AstLike; use rustc_span::Span; use self::newline_style::apply_newline_style; @@ -13,9 +14,9 @@ use crate::config::{Config, FileName, Verbosity}; use crate::formatting::generated::is_generated_file; use crate::issues::BadIssueSeeker; use crate::modules::Module; -use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError}; -use crate::syntux::session::ParseSess; -use crate::utils::count_newlines; +use crate::parse::parser::{DirectoryOwnership, Parser, ParserError}; +use crate::parse::session::ParseSess; +use crate::utils::{contains_skip, count_newlines}; use crate::visitor::FmtVisitor; use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session}; @@ -58,6 +59,39 @@ impl<'b, T: Write + 'b> Session<'b, T> { } } +/// Determine if a module should be skipped. True if the module should be skipped, false otherwise. +fn should_skip_module<T: FormatHandler>( + config: &Config, + context: &FormatContext<'_, T>, + input_is_stdin: bool, + main_file: &FileName, + path: &FileName, + module: &Module<'_>, +) -> bool { + if contains_skip(module.attrs()) { + return true; + } + + if config.skip_children() && path != main_file { + return true; + } + + if !input_is_stdin && context.ignore_file(path) { + return true; + } + + if !config.format_generated_files() { + let source_file = context.parse_session.span_to_file_contents(module.span); + let src = source_file.src.as_ref().expect("SourceFile without src"); + + if is_generated_file(src) { + return true; + } + } + + false +} + // Format an entire crate (or subset of the module tree). fn format_project<T: FormatHandler>( input: Input, @@ -97,7 +131,12 @@ fn format_project<T: FormatHandler>( directory_ownership.unwrap_or(DirectoryOwnership::UnownedViaBlock), !input_is_stdin && !config.skip_children(), ) - .visit_crate(&krate)?; + .visit_crate(&krate)? + .into_iter() + .filter(|(path, module)| { + !should_skip_module(config, &context, input_is_stdin, &main_file, path, module) + }) + .collect::<Vec<_>>(); timer = timer.done_parsing(); @@ -105,15 +144,6 @@ fn format_project<T: FormatHandler>( context.parse_session.set_silent_emitter(); for (path, module) in files { - let source_file = context.parse_session.span_to_file_contents(module.span); - let src = source_file.src.as_ref().expect("SourceFile without src"); - - let should_ignore = (!input_is_stdin && context.ignore_file(&path)) - || (!config.format_generated_files() && is_generated_file(src)); - - if (config.skip_children() && path != main_file) || should_ignore { - continue; - } should_emit_verbose(input_is_stdin, config, || println!("Formatting {}", path)); context.format_file(path, &module, is_macro_def)?; } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index b7dd6b06ff8..babc56f86ed 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1535,7 +1535,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases match (visitor_kind, &op_ty) { - (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(ref op_bounds)) => { + (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(op_bounds)) => { let op = OpaqueType { bounds: op_bounds }; rewrite_ty(rw_info, Some(bounds), Some(&op), vis) } @@ -1543,7 +1543,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( rewrite_ty(rw_info, Some(bounds), ty_opt, vis) } (AssocImplItem(_), _) => { - let result = if let Some(ref op_bounds) = op_ty { + let result = if let Some(op_bounds) = op_ty { let op = OpaqueType { bounds: op_bounds }; rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY) } else { @@ -3124,7 +3124,7 @@ impl Rewrite for ast::ForeignItem { let inner_attrs = inner_attributes(&self.attrs); let fn_ctxt = visit::FnCtxt::Foreign; visitor.visit_fn( - visit::FnKind::Fn(fn_ctxt, self.ident, &sig, &self.vis, Some(body)), + visit::FnKind::Fn(fn_ctxt, self.ident, sig, &self.vis, Some(body)), generics, &sig.decl, self.span, @@ -3137,7 +3137,7 @@ impl Rewrite for ast::ForeignItem { context, shape.indent, self.ident, - &FnSig::from_method_sig(&sig, generics, &self.vis), + &FnSig::from_method_sig(sig, generics, &self.vis), span, FnBraceStyle::None, ) @@ -3166,7 +3166,7 @@ impl Rewrite for ast::ForeignItem { .map(|s| s + ";") } ast::ForeignItemKind::TyAlias(ref ty_alias) => { - let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span); + let (kind, span) = (&ItemVisitorKind::ForeignItem(self), self.span); rewrite_type_alias(ty_alias, context, shape.indent, kind, span) } ast::ForeignItemKind::MacCall(ref mac) => { diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs index 792a1080f0e..ad23b16e02e 100644 --- a/src/tools/rustfmt/src/lib.rs +++ b/src/tools/rustfmt/src/lib.rs @@ -15,6 +15,7 @@ extern crate log; // N.B. these crates are loaded from the sysroot, so they need extern crate. extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_builtin_macros; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_expand; @@ -40,8 +41,8 @@ use crate::emitter::Emitter; use crate::formatting::{FormatErrorMap, FormattingError, ReportedErrors, SourceFile}; use crate::issues::Issue; use crate::modules::ModuleResolutionError; +use crate::parse::parser::DirectoryOwnership; use crate::shape::Indent; -use crate::syntux::parser::DirectoryOwnership; use crate::utils::indent_next_line; pub use crate::config::{ @@ -77,6 +78,7 @@ mod missed_spans; pub(crate) mod modules; mod overflow; mod pairs; +mod parse; mod patterns; mod release_channel; mod reorder; @@ -89,7 +91,6 @@ pub(crate) mod source_map; mod spanned; mod stmt; mod string; -mod syntux; #[cfg(test)] mod test; mod types; diff --git a/src/tools/rustfmt/src/lists.rs b/src/tools/rustfmt/src/lists.rs index 3515dd17251..7aa0315f18c 100644 --- a/src/tools/rustfmt/src/lists.rs +++ b/src/tools/rustfmt/src/lists.rs @@ -448,10 +448,8 @@ where true } else if starts_with_newline(comment) { false - } else if comment.trim().contains('\n') || comment.trim().len() > width { - true } else { - false + comment.trim().contains('\n') || comment.trim().len() > width }; rewrite_comment( diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index a52568be9ea..f29552caf8d 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -16,8 +16,6 @@ use rustc_ast::token::{BinOpToken, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{Cursor, Spacing, TokenStream, TokenTree}; use rustc_ast::{ast, ptr}; use rustc_ast_pretty::pprust; -use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS}; use rustc_span::{ symbol::{self, kw}, BytePos, Span, Symbol, DUMMY_SP, @@ -30,6 +28,8 @@ use crate::config::lists::*; use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind}; use crate::lists::{itemize_list, write_list, ListFormatting}; use crate::overflow; +use crate::parse::macros::lazy_static::parse_lazy_static; +use crate::parse::macros::{parse_expr, parse_macro_args, ParsedMacroArgs}; use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::{Indent, Shape}; use crate::source_map::SpanUtils; @@ -60,7 +60,7 @@ pub(crate) enum MacroArg { } impl MacroArg { - fn is_item(&self) -> bool { + pub(crate) fn is_item(&self) -> bool { match self { MacroArg::Item(..) => true, _ => false, @@ -90,61 +90,6 @@ impl Rewrite for MacroArg { } } -fn build_parser<'a>(context: &RewriteContext<'a>, cursor: Cursor) -> Parser<'a> { - stream_to_parser( - context.parse_sess.inner(), - cursor.collect(), - MACRO_ARGUMENTS, - ) -} - -fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { - macro_rules! parse_macro_arg { - ($macro_arg:ident, $parser:expr, $f:expr) => { - let mut cloned_parser = (*parser).clone(); - match $parser(&mut cloned_parser) { - Ok(x) => { - if parser.sess.span_diagnostic.has_errors() { - parser.sess.span_diagnostic.reset_err_count(); - } else { - // Parsing succeeded. - *parser = cloned_parser; - return Some(MacroArg::$macro_arg($f(x)?)); - } - } - Err(mut e) => { - e.cancel(); - parser.sess.span_diagnostic.reset_err_count(); - } - } - }; - } - - parse_macro_arg!( - Expr, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(), - |x: ptr::P<ast::Expr>| Some(x) - ); - parse_macro_arg!( - Ty, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(), - |x: ptr::P<ast::Ty>| Some(x) - ); - parse_macro_arg!( - Pat, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None), - |x: ptr::P<ast::Pat>| Some(x) - ); - // `parse_item` returns `Option<ptr::P<ast::Item>>`. - parse_macro_arg!( - Item, - |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No), - |x: Option<ptr::P<ast::Item>>| x - ); - - None -} - /// Rewrite macro name without using pretty-printer if possible. fn rewrite_macro_name( context: &RewriteContext<'_>, @@ -232,25 +177,6 @@ pub(crate) fn rewrite_macro( } } -fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { - for &keyword in RUST_KW.iter() { - if parser.token.is_keyword(keyword) - && parser.look_ahead(1, |t| { - t.kind == TokenKind::Eof - || t.kind == TokenKind::Comma - || t.kind == TokenKind::CloseDelim(DelimToken::NoDelim) - }) - { - parser.bump(); - return Some(MacroArg::Keyword( - symbol::Ident::with_dummy_span(keyword), - parser.prev_token.span, - )); - } - } - None -} - fn rewrite_macro_inner( mac: &ast::MacCall, extra_ident: Option<symbol::Ident>, @@ -269,8 +195,9 @@ fn rewrite_macro_inner( let original_style = macro_style(mac, context); let macro_name = rewrite_macro_name(context, &mac.path, extra_ident); + let is_forced_bracket = FORCED_BRACKET_MACROS.contains(&¯o_name[..]); - let style = if FORCED_BRACKET_MACROS.contains(&¯o_name[..]) && !is_nested_macro { + let style = if is_forced_bracket && !is_nested_macro { DelimToken::Bracket } else { original_style @@ -294,67 +221,21 @@ fn rewrite_macro_inner( } // Format well-known macros which cannot be parsed as a valid AST. if macro_name == "lazy_static!" && !has_comment { - if let success @ Some(..) = format_lazy_static(context, shape, &ts) { + if let success @ Some(..) = format_lazy_static(context, shape, ts.trees().collect()) { return success; } } - let mut parser = build_parser(context, ts.trees()); - let mut arg_vec = Vec::new(); - let mut vec_with_semi = false; - let mut trailing_comma = false; - - if DelimToken::Brace != style { - loop { - if let Some(arg) = check_keyword(&mut parser) { - arg_vec.push(arg); - } else if let Some(arg) = parse_macro_arg(&mut parser) { - arg_vec.push(arg); - } else { - return return_macro_parse_failure_fallback(context, shape.indent, mac.span()); - } - - match parser.token.kind { - TokenKind::Eof => break, - TokenKind::Comma => (), - TokenKind::Semi => { - // Try to parse `vec![expr; expr]` - if FORCED_BRACKET_MACROS.contains(&¯o_name[..]) { - parser.bump(); - if parser.token.kind != TokenKind::Eof { - match parse_macro_arg(&mut parser) { - Some(arg) => { - arg_vec.push(arg); - parser.bump(); - if parser.token.kind == TokenKind::Eof && arg_vec.len() == 2 { - vec_with_semi = true; - break; - } - } - None => { - return return_macro_parse_failure_fallback( - context, - shape.indent, - mac.span(), - ); - } - } - } - } - return return_macro_parse_failure_fallback(context, shape.indent, mac.span()); - } - _ if arg_vec.last().map_or(false, MacroArg::is_item) => continue, - _ => return return_macro_parse_failure_fallback(context, shape.indent, mac.span()), - } - - parser.bump(); - - if parser.token.kind == TokenKind::Eof { - trailing_comma = true; - break; - } + let ParsedMacroArgs { + args: arg_vec, + vec_with_semi, + trailing_comma, + } = match parse_macro_args(context, ts, style, is_forced_bracket) { + Some(args) => args, + None => { + return return_macro_parse_failure_fallback(context, shape.indent, mac.span()); } - } + }; if !arg_vec.is_empty() && arg_vec.iter().all(MacroArg::is_item) { return rewrite_macro_with_items( @@ -1179,11 +1060,10 @@ pub(crate) fn convert_try_mac( let path = &pprust::path_to_string(&mac.path); if path == "try" || path == "r#try" { let ts = mac.args.inner_tokens(); - let mut parser = build_parser(context, ts.trees()); Some(ast::Expr { id: ast::NodeId::root(), // dummy value - kind: ast::ExprKind::Try(parser.parse_expr().ok()?), + kind: ast::ExprKind::Try(parse_expr(context, ts)?), span: mac.span(), // incorrect span, but shouldn't matter too much attrs: ast::AttrVec::new(), tokens: None, @@ -1414,10 +1294,9 @@ impl MacroBranch { fn format_lazy_static( context: &RewriteContext<'_>, shape: Shape, - ts: &TokenStream, + ts: TokenStream, ) -> Option<String> { let mut result = String::with_capacity(1024); - let mut parser = build_parser(context, ts.trees()); let nested_shape = shape .block_indent(context.config.tab_spaces()) .with_max_width(context.config); @@ -1425,42 +1304,11 @@ fn format_lazy_static( result.push_str("lazy_static! {"); result.push_str(&nested_shape.indent.to_string_with_newline(context.config)); - macro_rules! parse_or { - ($method:ident $(,)* $($arg:expr),* $(,)*) => { - match parser.$method($($arg,)*) { - Ok(val) => { - if parser.sess.span_diagnostic.has_errors() { - parser.sess.span_diagnostic.reset_err_count(); - return None; - } else { - val - } - } - Err(mut err) => { - err.cancel(); - parser.sess.span_diagnostic.reset_err_count(); - return None; - } - } - } - } - - while parser.token.kind != TokenKind::Eof { - // Parse a `lazy_static!` item. - let vis = crate::utils::format_visibility( - context, - &parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No), - ); - parser.eat_keyword(kw::Static); - parser.eat_keyword(kw::Ref); - let id = parse_or!(parse_ident); - parser.eat(&TokenKind::Colon); - let ty = parse_or!(parse_ty); - parser.eat(&TokenKind::Eq); - let expr = parse_or!(parse_expr); - parser.eat(&TokenKind::Semi); - + let parsed_elems = parse_lazy_static(context, ts)?; + let last = parsed_elems.len() - 1; + for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() { // Rewrite as a static item. + let vis = crate::utils::format_visibility(context, vis); let mut stmt = String::with_capacity(128); stmt.push_str(&format!( "{}static ref {}: {} =", @@ -1476,7 +1324,7 @@ fn format_lazy_static( nested_shape.sub_width(1)?, )?); result.push(';'); - if parser.token.kind != TokenKind::Eof { + if i != last { result.push_str(&nested_shape.indent.to_string_with_newline(context.config)); } } @@ -1528,65 +1376,3 @@ fn rewrite_macro_with_items( result.push_str(trailing_semicolon); Some(result) } - -const RUST_KW: [Symbol; 59] = [ - kw::PathRoot, - kw::DollarCrate, - kw::Underscore, - kw::As, - kw::Box, - kw::Break, - kw::Const, - kw::Continue, - kw::Crate, - kw::Else, - kw::Enum, - kw::Extern, - kw::False, - kw::Fn, - kw::For, - kw::If, - kw::Impl, - kw::In, - kw::Let, - kw::Loop, - kw::Match, - kw::Mod, - kw::Move, - kw::Mut, - kw::Pub, - kw::Ref, - kw::Return, - kw::SelfLower, - kw::SelfUpper, - kw::Static, - kw::Struct, - kw::Super, - kw::Trait, - kw::True, - kw::Type, - kw::Unsafe, - kw::Use, - kw::Where, - kw::While, - kw::Abstract, - kw::Become, - kw::Do, - kw::Final, - kw::Macro, - kw::Override, - kw::Priv, - kw::Typeof, - kw::Unsized, - kw::Virtual, - kw::Yield, - kw::Dyn, - kw::Async, - kw::Try, - kw::UnderscoreLifetime, - kw::StaticLifetime, - kw::Auto, - kw::Catch, - kw::Default, - kw::Union, -]; diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs index 22d23fc1cdb..85d9c5d2b9b 100644 --- a/src/tools/rustfmt/src/matches.rs +++ b/src/tools/rustfmt/src/matches.rs @@ -322,7 +322,11 @@ fn flatten_arm_body<'a>( if let Some(block) = block_can_be_flattened(context, body) { if let ast::StmtKind::Expr(ref expr) = block.stmts[0].kind { if let ast::ExprKind::Block(..) = expr.kind { - flatten_arm_body(context, expr, None) + if expr.attrs.is_empty() { + flatten_arm_body(context, expr, None) + } else { + (true, body) + } } else { let cond_becomes_muti_line = opt_shape .and_then(|shape| rewrite_cond(context, expr, shape)) diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index 9d438a80d94..9c964b274e0 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -12,10 +12,10 @@ use thiserror::Error; use crate::attr::MetaVisitor; use crate::config::FileName; use crate::items::is_mod_decl; -use crate::syntux::parser::{ +use crate::parse::parser::{ Directory, DirectoryOwnership, ModError, ModulePathSuccess, Parser, ParserError, }; -use crate::syntux::session::ParseSess; +use crate::parse::session::ParseSess; use crate::utils::{contains_skip, mk_sp}; mod visitor; diff --git a/src/tools/rustfmt/src/modules/visitor.rs b/src/tools/rustfmt/src/modules/visitor.rs index d5acf3f1cbc..ea67977c17a 100644 --- a/src/tools/rustfmt/src/modules/visitor.rs +++ b/src/tools/rustfmt/src/modules/visitor.rs @@ -3,8 +3,8 @@ use rustc_ast::visit::Visitor; use rustc_span::Symbol; use crate::attr::MetaVisitor; -use crate::syntux::parser::Parser; -use crate::syntux::session::ParseSess; +use crate::parse::macros::cfg_if::parse_cfg_if; +use crate::parse::session::ParseSess; pub(crate) struct ModItem { pub(crate) item: ast::Item, @@ -62,7 +62,7 @@ impl<'a, 'ast: 'a> CfgIfVisitor<'a> { } }; - let items = Parser::parse_cfg_if(self.parse_sess, mac)?; + let items = parse_cfg_if(self.parse_sess, mac)?; self.mods .append(&mut items.into_iter().map(|item| ModItem { item }).collect()); diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs new file mode 100644 index 00000000000..cc9fb5072ce --- /dev/null +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -0,0 +1,11 @@ +use rustc_ast::ast; +use rustc_builtin_macros::asm::{parse_asm_args, AsmArgs}; + +use crate::rewrite::RewriteContext; + +#[allow(dead_code)] +pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> { + let ts = mac.args.inner_tokens(); + let mut parser = super::build_parser(context, ts); + parse_asm_args(&mut parser, context.parse_sess.inner(), mac.span(), false).ok() +} diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs new file mode 100644 index 00000000000..e10fbe64bcd --- /dev/null +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -0,0 +1,89 @@ +use std::panic::{catch_unwind, AssertUnwindSafe}; + +use rustc_ast::ast; +use rustc_ast::token::{DelimToken, TokenKind}; +use rustc_parse::parser::ForceCollect; +use rustc_span::symbol::kw; + +use crate::parse::macros::build_stream_parser; +use crate::parse::session::ParseSess; + +pub(crate) fn parse_cfg_if<'a>( + sess: &'a ParseSess, + mac: &'a ast::MacCall, +) -> Result<Vec<ast::Item>, &'static str> { + match catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(sess, mac))) { + Ok(Ok(items)) => Ok(items), + Ok(err @ Err(_)) => err, + Err(..) => Err("failed to parse cfg_if!"), + } +} + +fn parse_cfg_if_inner<'a>( + sess: &'a ParseSess, + mac: &'a ast::MacCall, +) -> Result<Vec<ast::Item>, &'static str> { + let ts = mac.args.inner_tokens(); + let mut parser = build_stream_parser(sess.inner(), ts); + + let mut items = vec![]; + let mut process_if_cfg = true; + + while parser.token.kind != TokenKind::Eof { + if process_if_cfg { + if !parser.eat_keyword(kw::If) { + return Err("Expected `if`"); + } + // Inner attributes are not actually syntactically permitted here, but we don't + // care about inner vs outer attributes in this position. Our purpose with this + // special case parsing of cfg_if macros is to ensure we can correctly resolve + // imported modules that may have a custom `path` defined. + // + // As such, we just need to advance the parser past the attribute and up to + // to the opening brace. + // See also https://github.com/rust-lang/rust/pull/79433 + parser + .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted) + .map_err(|_| "Failed to parse attributes")?; + } + + if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) { + return Err("Expected an opening brace"); + } + + while parser.token != TokenKind::CloseDelim(DelimToken::Brace) + && parser.token.kind != TokenKind::Eof + { + let item = match parser.parse_item(ForceCollect::No) { + Ok(Some(item_ptr)) => item_ptr.into_inner(), + Ok(None) => continue, + Err(mut err) => { + err.cancel(); + parser.sess.span_diagnostic.reset_err_count(); + return Err( + "Expected item inside cfg_if block, but failed to parse it as an item", + ); + } + }; + if let ast::ItemKind::Mod(..) = item.kind { + items.push(item); + } + } + + if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) { + return Err("Expected a closing brace"); + } + + if parser.eat(&TokenKind::Eof) { + break; + } + + if !parser.eat_keyword(kw::Else) { + return Err("Expected `else`"); + } + + process_if_cfg = parser.token.is_keyword(kw::If); + } + + Ok(items) +} diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs new file mode 100644 index 00000000000..9c8651aa3fa --- /dev/null +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -0,0 +1,50 @@ +use rustc_ast::ast; +use rustc_ast::ptr::P; +use rustc_ast::token::TokenKind; +use rustc_ast::tokenstream::TokenStream; +use rustc_span::symbol::{self, kw}; + +use crate::rewrite::RewriteContext; + +pub(crate) fn parse_lazy_static( + context: &RewriteContext<'_>, + ts: TokenStream, +) -> Option<Vec<(ast::Visibility, symbol::Ident, P<ast::Ty>, P<ast::Expr>)>> { + let mut result = vec![]; + let mut parser = super::build_parser(context, ts); + macro_rules! parse_or { + ($method:ident $(,)* $($arg:expr),* $(,)*) => { + match parser.$method($($arg,)*) { + Ok(val) => { + if parser.sess.span_diagnostic.has_errors() { + parser.sess.span_diagnostic.reset_err_count(); + return None; + } else { + val + } + } + Err(mut err) => { + err.cancel(); + parser.sess.span_diagnostic.reset_err_count(); + return None; + } + } + } + } + + while parser.token.kind != TokenKind::Eof { + // Parse a `lazy_static!` item. + let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No); + parser.eat_keyword(kw::Static); + parser.eat_keyword(kw::Ref); + let id = parse_or!(parse_ident); + parser.eat(&TokenKind::Colon); + let ty = parse_or!(parse_ty); + parser.eat(&TokenKind::Eq); + let expr = parse_or!(parse_expr); + parser.eat(&TokenKind::Semi); + result.push((vis, id, ty, expr)); + } + + Some(result) +} diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs new file mode 100644 index 00000000000..2e9ce1d35f4 --- /dev/null +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -0,0 +1,231 @@ +use rustc_ast::token::{DelimToken, TokenKind}; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{ast, ptr}; +use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS}; +use rustc_session::parse::ParseSess; +use rustc_span::symbol::{self, kw}; +use rustc_span::Symbol; + +use crate::macros::MacroArg; +use crate::rewrite::RewriteContext; + +pub(crate) mod asm; +pub(crate) mod cfg_if; +pub(crate) mod lazy_static; + +fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> { + stream_to_parser(sess, tokens, MACRO_ARGUMENTS) +} + +fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> { + build_stream_parser(context.parse_sess.inner(), tokens) +} + +fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { + macro_rules! parse_macro_arg { + ($macro_arg:ident, $parser:expr, $f:expr) => { + let mut cloned_parser = (*parser).clone(); + match $parser(&mut cloned_parser) { + Ok(x) => { + if parser.sess.span_diagnostic.has_errors() { + parser.sess.span_diagnostic.reset_err_count(); + } else { + // Parsing succeeded. + *parser = cloned_parser; + return Some(MacroArg::$macro_arg($f(x)?)); + } + } + Err(mut e) => { + e.cancel(); + parser.sess.span_diagnostic.reset_err_count(); + } + } + }; + } + + parse_macro_arg!( + Expr, + |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(), + |x: ptr::P<ast::Expr>| Some(x) + ); + parse_macro_arg!( + Ty, + |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(), + |x: ptr::P<ast::Ty>| Some(x) + ); + parse_macro_arg!( + Pat, + |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None), + |x: ptr::P<ast::Pat>| Some(x) + ); + // `parse_item` returns `Option<ptr::P<ast::Item>>`. + parse_macro_arg!( + Item, + |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No), + |x: Option<ptr::P<ast::Item>>| x + ); + + None +} + +pub(crate) struct ParsedMacroArgs { + pub(crate) vec_with_semi: bool, + pub(crate) trailing_comma: bool, + pub(crate) args: Vec<MacroArg>, +} + +fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { + for &keyword in RUST_KW.iter() { + if parser.token.is_keyword(keyword) + && parser.look_ahead(1, |t| { + t.kind == TokenKind::Eof + || t.kind == TokenKind::Comma + || t.kind == TokenKind::CloseDelim(DelimToken::NoDelim) + }) + { + parser.bump(); + return Some(MacroArg::Keyword( + symbol::Ident::with_dummy_span(keyword), + parser.prev_token.span, + )); + } + } + None +} + +pub(crate) fn parse_macro_args( + context: &RewriteContext<'_>, + tokens: TokenStream, + style: DelimToken, + forced_bracket: bool, +) -> Option<ParsedMacroArgs> { + let mut parser = build_parser(context, tokens); + let mut args = Vec::new(); + let mut vec_with_semi = false; + let mut trailing_comma = false; + + if DelimToken::Brace != style { + loop { + if let Some(arg) = check_keyword(&mut parser) { + args.push(arg); + } else if let Some(arg) = parse_macro_arg(&mut parser) { + args.push(arg); + } else { + return None; + } + + match parser.token.kind { + TokenKind::Eof => break, + TokenKind::Comma => (), + TokenKind::Semi => { + // Try to parse `vec![expr; expr]` + if forced_bracket { + parser.bump(); + if parser.token.kind != TokenKind::Eof { + match parse_macro_arg(&mut parser) { + Some(arg) => { + args.push(arg); + parser.bump(); + if parser.token.kind == TokenKind::Eof && args.len() == 2 { + vec_with_semi = true; + break; + } + } + None => { + return None; + } + } + } + } + return None; + } + _ if args.last().map_or(false, MacroArg::is_item) => continue, + _ => return None, + } + + parser.bump(); + + if parser.token.kind == TokenKind::Eof { + trailing_comma = true; + break; + } + } + } + + Some(ParsedMacroArgs { + vec_with_semi, + trailing_comma, + args, + }) +} + +pub(crate) fn parse_expr( + context: &RewriteContext<'_>, + tokens: TokenStream, +) -> Option<ptr::P<ast::Expr>> { + let mut parser = build_parser(context, tokens); + parser.parse_expr().ok() +} + +const RUST_KW: [Symbol; 59] = [ + kw::PathRoot, + kw::DollarCrate, + kw::Underscore, + kw::As, + kw::Box, + kw::Break, + kw::Const, + kw::Continue, + kw::Crate, + kw::Else, + kw::Enum, + kw::Extern, + kw::False, + kw::Fn, + kw::For, + kw::If, + kw::Impl, + kw::In, + kw::Let, + kw::Loop, + kw::Match, + kw::Mod, + kw::Move, + kw::Mut, + kw::Pub, + kw::Ref, + kw::Return, + kw::SelfLower, + kw::SelfUpper, + kw::Static, + kw::Struct, + kw::Super, + kw::Trait, + kw::True, + kw::Type, + kw::Unsafe, + kw::Use, + kw::Where, + kw::While, + kw::Abstract, + kw::Become, + kw::Do, + kw::Final, + kw::Macro, + kw::Override, + kw::Priv, + kw::Typeof, + kw::Unsized, + kw::Virtual, + kw::Yield, + kw::Dyn, + kw::Async, + kw::Try, + kw::UnderscoreLifetime, + kw::StaticLifetime, + kw::Auto, + kw::Catch, + kw::Default, + kw::Union, +]; diff --git a/src/tools/rustfmt/src/parse/mod.rs b/src/tools/rustfmt/src/parse/mod.rs new file mode 100644 index 00000000000..5e88826ea8c --- /dev/null +++ b/src/tools/rustfmt/src/parse/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod macros; +pub(crate) mod parser; +pub(crate) mod session; diff --git a/src/tools/rustfmt/src/syntux/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 23d065c9cc9..657217633f4 100644 --- a/src/tools/rustfmt/src/syntux/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -1,17 +1,14 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::{Path, PathBuf}; -use rustc_ast::token::{DelimToken, TokenKind}; +use rustc_ast::token::TokenKind; use rustc_ast::{ast, ptr}; use rustc_errors::Diagnostic; -use rustc_parse::{ - new_parser_from_file, - parser::{ForceCollect, Parser as RawParser}, -}; -use rustc_span::{sym, symbol::kw, Span}; +use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; +use rustc_span::{sym, Span}; use crate::attr::first_attr_value_str_by_name; -use crate::syntux::session::ParseSess; +use crate::parse::session::ParseSess; use crate::Input; pub(crate) type DirectoryOwnership = rustc_expand::module::DirOwnership; @@ -175,84 +172,4 @@ impl<'a> Parser<'a> { Err(_) => Err(ParserError::ParsePanicError), } } - - pub(crate) fn parse_cfg_if( - sess: &'a ParseSess, - mac: &'a ast::MacCall, - ) -> Result<Vec<ast::Item>, &'static str> { - match catch_unwind(AssertUnwindSafe(|| Parser::parse_cfg_if_inner(sess, mac))) { - Ok(Ok(items)) => Ok(items), - Ok(err @ Err(_)) => err, - Err(..) => Err("failed to parse cfg_if!"), - } - } - - fn parse_cfg_if_inner( - sess: &'a ParseSess, - mac: &'a ast::MacCall, - ) -> Result<Vec<ast::Item>, &'static str> { - let token_stream = mac.args.inner_tokens(); - let mut parser = rustc_parse::stream_to_parser(sess.inner(), token_stream, Some("")); - - let mut items = vec![]; - let mut process_if_cfg = true; - - while parser.token.kind != TokenKind::Eof { - if process_if_cfg { - if !parser.eat_keyword(kw::If) { - return Err("Expected `if`"); - } - // Inner attributes are not actually syntactically permitted here, but we don't - // care about inner vs outer attributes in this position. Our purpose with this - // special case parsing of cfg_if macros is to ensure we can correctly resolve - // imported modules that may have a custom `path` defined. - // - // As such, we just need to advance the parser past the attribute and up to - // to the opening brace. - // See also https://github.com/rust-lang/rust/pull/79433 - parser - .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted) - .map_err(|_| "Failed to parse attributes")?; - } - - if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) { - return Err("Expected an opening brace"); - } - - while parser.token != TokenKind::CloseDelim(DelimToken::Brace) - && parser.token.kind != TokenKind::Eof - { - let item = match parser.parse_item(ForceCollect::No) { - Ok(Some(item_ptr)) => item_ptr.into_inner(), - Ok(None) => continue, - Err(mut err) => { - err.cancel(); - parser.sess.span_diagnostic.reset_err_count(); - return Err( - "Expected item inside cfg_if block, but failed to parse it as an item", - ); - } - }; - if let ast::ItemKind::Mod(..) = item.kind { - items.push(item); - } - } - - if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) { - return Err("Expected a closing brace"); - } - - if parser.eat(&TokenKind::Eof) { - break; - } - - if !parser.eat_keyword(kw::Else) { - return Err("Expected `else`"); - } - - process_if_cfg = parser.token.is_keyword(kw::If); - } - - Ok(items) - } } diff --git a/src/tools/rustfmt/src/syntux/session.rs b/src/tools/rustfmt/src/parse/session.rs index dd7c7352686..624fed0d2de 100644 --- a/src/tools/rustfmt/src/syntux/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -222,7 +222,7 @@ impl ParseSess { } } -// Methods that should be restricted within the syntux module. +// Methods that should be restricted within the parse module. impl ParseSess { pub(super) fn emit_diagnostics(&self, diagnostics: Vec<Diagnostic>) { for diagnostic in diagnostics { diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index a80d63201f9..9b74b35f314 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -318,10 +318,12 @@ fn rewrite_struct_pat( let mut fields_str = write_list(&item_vec, &fmt)?; let one_line_width = h_shape.map_or(0, |shape| shape.width); + let has_trailing_comma = fmt.needs_trailing_separator(); + if ellipsis { if fields_str.contains('\n') || fields_str.len() > one_line_width { // Add a missing trailing comma. - if context.config.trailing_comma() == SeparatorTactic::Never { + if !has_trailing_comma { fields_str.push(','); } fields_str.push('\n'); @@ -329,8 +331,7 @@ fn rewrite_struct_pat( } else { if !fields_str.is_empty() { // there are preceding struct fields being matched on - if tactic == DefinitiveListTactic::Vertical { - // if the tactic is Vertical, write_list already added a trailing , + if has_trailing_comma { fields_str.push(' '); } else { fields_str.push_str(", "); diff --git a/src/tools/rustfmt/src/rewrite.rs b/src/tools/rustfmt/src/rewrite.rs index c8abe70141b..4a3bd129d16 100644 --- a/src/tools/rustfmt/src/rewrite.rs +++ b/src/tools/rustfmt/src/rewrite.rs @@ -7,9 +7,9 @@ use rustc_ast::ptr; use rustc_span::Span; use crate::config::{Config, IndentStyle}; +use crate::parse::session::ParseSess; use crate::shape::Shape; use crate::skip::SkipContext; -use crate::syntux::session::ParseSess; use crate::visitor::SnippetProvider; use crate::FormatReport; diff --git a/src/tools/rustfmt/src/rustfmt_diff.rs b/src/tools/rustfmt/src/rustfmt_diff.rs index a394ce07398..1724a0f87bf 100644 --- a/src/tools/rustfmt/src/rustfmt_diff.rs +++ b/src/tools/rustfmt/src/rustfmt_diff.rs @@ -6,20 +6,20 @@ use std::io::Write; use crate::config::{Color, Config, Verbosity}; #[derive(Debug, PartialEq)] -pub enum DiffLine { +pub(crate) enum DiffLine { Context(String), Expected(String), Resulting(String), } #[derive(Debug, PartialEq)] -pub struct Mismatch { +pub(crate) struct Mismatch { /// The line number in the formatted version. - pub line_number: u32, + pub(crate) line_number: u32, /// The line number in the original version. - pub line_number_orig: u32, + pub(crate) line_number_orig: u32, /// The set of lines (context and old/new) in the mismatch. - pub lines: Vec<DiffLine>, + pub(crate) lines: Vec<DiffLine>, } impl Mismatch { diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs index 853336004d8..56d4ab40038 100644 --- a/src/tools/rustfmt/src/source_file.rs +++ b/src/tools/rustfmt/src/source_file.rs @@ -4,7 +4,7 @@ use std::path::Path; use crate::config::FileName; use crate::emitter::{self, Emitter}; -use crate::syntux::session::ParseSess; +use crate::parse::session::ParseSess; use crate::NewlineStyle; #[cfg(test)] diff --git a/src/tools/rustfmt/src/test/configuration_snippet.rs b/src/tools/rustfmt/src/test/configuration_snippet.rs index ef7dd0ddcd1..92949ab576a 100644 --- a/src/tools/rustfmt/src/test/configuration_snippet.rs +++ b/src/tools/rustfmt/src/test/configuration_snippet.rs @@ -110,14 +110,7 @@ impl ConfigCodeBlock { assert!(self.code_block.is_some() && self.code_block_start.is_some()); // See if code block begins with #![rustfmt::skip]. - let fmt_skip = self - .code_block - .as_ref() - .unwrap() - .lines() - .nth(0) - .unwrap_or("") - == "#![rustfmt::skip]"; + let fmt_skip = self.fmt_skip(); if self.config_name.is_none() && !fmt_skip { write_message(&format!( @@ -138,6 +131,17 @@ impl ConfigCodeBlock { true } + /// True if the code block starts with #![rustfmt::skip] + fn fmt_skip(&self) -> bool { + self.code_block + .as_ref() + .unwrap() + .lines() + .nth(0) + .unwrap_or("") + == "#![rustfmt::skip]" + } + fn has_parsing_errors<T: Write>(&self, session: &Session<'_, T>) -> bool { if session.has_parsing_errors() { write_message(&format!( @@ -251,6 +255,7 @@ fn configuration_snippet_tests() { let blocks = get_code_blocks(); let failures = blocks .iter() + .filter(|block| !block.fmt_skip()) .map(ConfigCodeBlock::formatted_is_idempotent) .fold(0, |acc, r| acc + (!r as u32)); diff --git a/src/tools/rustfmt/src/test/mod_resolver.rs b/src/tools/rustfmt/src/test/mod_resolver.rs index ae4a0d0fccb..ec9ed0f0b8d 100644 --- a/src/tools/rustfmt/src/test/mod_resolver.rs +++ b/src/tools/rustfmt/src/test/mod_resolver.rs @@ -41,3 +41,12 @@ fn out_of_line_nested_inline_within_out_of_line() { ], ); } + +#[test] +fn skip_out_of_line_nested_inline_within_out_of_line() { + // See also https://github.com/rust-lang/rustfmt/issues/5065 + verify_mod_resolution( + "tests/mod-resolver/skip-files-issue-5065/main.rs", + &["tests/mod-resolver/skip-files-issue-5065/one.rs"], + ); +} diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index e4a7be742ab..0177689958a 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -16,13 +16,13 @@ use crate::items::{ }; use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition}; use crate::modules::Module; +use crate::parse::session::ParseSess; use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::{Indent, Shape}; use crate::skip::{is_skip_attr, SkipContext}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; use crate::stmt::Stmt; -use crate::syntux::session::ParseSess; use crate::utils::{ self, contains_skip, count_newlines, depr_skip_annotation, format_unsafety, inner_attributes, last_line_width, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, starts_with_newline, stmt_expr, @@ -552,7 +552,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { _ => visit::FnCtxt::Foreign, }; self.visit_fn( - visit::FnKind::Fn(fn_ctxt, item.ident, &sig, &item.vis, Some(body)), + visit::FnKind::Fn(fn_ctxt, item.ident, sig, &item.vis, Some(body)), generics, &sig.decl, item.span, @@ -562,14 +562,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } else { let indent = self.block_indent; let rewrite = self.rewrite_required_fn( - indent, item.ident, &sig, &item.vis, generics, item.span, + indent, item.ident, sig, &item.vis, generics, item.span, ); self.push_rewrite(item.span, rewrite); } } ast::ItemKind::TyAlias(ref ty_alias) => { use ItemVisitorKind::Item; - self.visit_ty_alias_kind(ty_alias, &Item(&item), item.span); + self.visit_ty_alias_kind(ty_alias, &Item(item), item.span); } ast::ItemKind::GlobalAsm(..) => { let snippet = Some(self.snippet(item.span).to_owned()); @@ -619,17 +619,17 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { skip_out_of_file_lines_range_visitor!(self, ai.span); if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) { - self.push_skipped_with_span(&ai.attrs.as_slice(), skip_span, skip_span); + self.push_skipped_with_span(ai.attrs.as_slice(), skip_span, skip_span); return; } // TODO(calebcartwright): consider enabling box_patterns feature gate match (&ai.kind, visitor_kind) { (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => { - self.visit_static(&StaticParts::from_trait_item(&ai)) + self.visit_static(&StaticParts::from_trait_item(ai)) } (ast::AssocItemKind::Const(..), AssocImplItem(_)) => { - self.visit_static(&StaticParts::from_impl_item(&ai)) + self.visit_static(&StaticParts::from_impl_item(ai)) } (ast::AssocItemKind::Fn(ref fn_kind), _) => { let ast::Fn { @@ -948,12 +948,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { pub(crate) fn format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos) { self.block_indent = Indent::empty(); - if self.visit_attrs(m.attrs(), ast::AttrStyle::Inner) { - self.push_skipped_with_span(m.attrs(), m.span, m.span); - } else { - self.walk_mod_items(&m.items); - self.format_missing_with_indent(end_pos); - } + let skipped = self.visit_attrs(m.attrs(), ast::AttrStyle::Inner); + assert!( + !skipped, + "Skipping module must be handled before reaching this line." + ); + self.walk_mod_items(&m.items); + self.format_missing_with_indent(end_pos); } pub(crate) fn skip_empty_lines(&mut self, end_pos: BytePos) { diff --git a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/foo.rs b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/foo.rs new file mode 100644 index 00000000000..74889acf0c3 --- /dev/null +++ b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/foo.rs @@ -0,0 +1,5 @@ +#![rustfmt::skip] + +mod bar { + + mod baz;} \ No newline at end of file diff --git a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/foo/bar/baz.rs b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/foo/bar/baz.rs new file mode 100644 index 00000000000..3519b0ee59c --- /dev/null +++ b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/foo/bar/baz.rs @@ -0,0 +1 @@ +fn baz() { } \ No newline at end of file diff --git a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs new file mode 100644 index 00000000000..3122e4f220f --- /dev/null +++ b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs @@ -0,0 +1,9 @@ +#![rustfmt::skip] + +mod foo; +mod one; + +fn main() {println!("Hello, world!"); +} + +// trailing commet diff --git a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/one.rs b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/one.rs new file mode 100644 index 00000000000..e7eb2c2d64d --- /dev/null +++ b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/one.rs @@ -0,0 +1 @@ +struct One { value: String } \ No newline at end of file diff --git a/src/tools/rustfmt/tests/source/async_block.rs b/src/tools/rustfmt/tests/source/async_block.rs index 3de51a084d2..18cb4fb5f5c 100644 --- a/src/tools/rustfmt/tests/source/async_block.rs +++ b/src/tools/rustfmt/tests/source/async_block.rs @@ -32,4 +32,20 @@ fn baz() { Ok(()) }, ); + + spawn( + a, + static async || { + action(); + Ok(()) + }, + ); + + spawn( + a, + static async move || { + action(); + Ok(()) + }, + ); } diff --git a/src/tools/rustfmt/tests/source/match.rs b/src/tools/rustfmt/tests/source/match.rs index da20517203a..b5dc9957a2c 100644 --- a/src/tools/rustfmt/tests/source/match.rs +++ b/src/tools/rustfmt/tests/source/match.rs @@ -568,3 +568,22 @@ fn issue_3774() { } } } + +// #4109 +fn issue_4109() { + match () { + _ => { +#[cfg(debug_assertions)] +{ +println!("Foo"); +} +} +} + +match () { +_ => { +#[allow(unsafe_code)] +unsafe {} +} +} +} diff --git a/src/tools/rustfmt/tests/target/async_block.rs b/src/tools/rustfmt/tests/target/async_block.rs index 258dd937a6f..137d849c9ee 100644 --- a/src/tools/rustfmt/tests/target/async_block.rs +++ b/src/tools/rustfmt/tests/target/async_block.rs @@ -22,4 +22,14 @@ fn baz() { action(); Ok(()) }); + + spawn(a, static async || { + action(); + Ok(()) + }); + + spawn(a, static async move || { + action(); + Ok(()) + }); } diff --git a/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_trailing_comma_always_struct_lit_width_0.rs b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_trailing_comma_always_struct_lit_width_0.rs new file mode 100644 index 00000000000..c7122c67623 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_trailing_comma_always_struct_lit_width_0.rs @@ -0,0 +1,10 @@ +// rustfmt-trailing_comma: Always +// rustfmt-struct_lit_single_line: false +// rustfmt-struct_lit_width: 0 + +fn main() { + let Foo { + a, + .. + } = b; +} diff --git a/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_trailing_comma_never_struct_lit_width_0.rs b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_trailing_comma_never_struct_lit_width_0.rs new file mode 100644 index 00000000000..68e89c4179f --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_trailing_comma_never_struct_lit_width_0.rs @@ -0,0 +1,10 @@ +// rustfmt-trailing_comma: Never +// rustfmt-struct_lit_single_line: false +// rustfmt-struct_lit_width: 0 + +fn main() { + let Foo { + a, + .. + } = b; +} diff --git a/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_with_trailing_comma_always.rs b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_with_trailing_comma_always.rs new file mode 100644 index 00000000000..3368f070386 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_with_trailing_comma_always.rs @@ -0,0 +1,10 @@ +// rustfmt-trailing_comma: Always +// rustfmt-struct_lit_single_line: false + +// There is an issue with how this is formatted. +// formatting should look like ./multi_line_struct_trailing_comma_always_struct_lit_width_0.rs +fn main() { + let Foo { + a, .. + } = b; +} diff --git a/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_with_trailing_comma_never.rs b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_with_trailing_comma_never.rs new file mode 100644 index 00000000000..cf63c4c983c --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5066/multi_line_struct_with_trailing_comma_never.rs @@ -0,0 +1,10 @@ +// rustfmt-trailing_comma: Never +// rustfmt-struct_lit_single_line: false + +// There is an issue with how this is formatted. +// formatting should look like ./multi_line_struct_trailing_comma_never_struct_lit_width_0.rs +fn main() { + let Foo { + a, .. + } = b; +} diff --git a/src/tools/rustfmt/tests/target/issue-5066/with_trailing_comma_always.rs b/src/tools/rustfmt/tests/target/issue-5066/with_trailing_comma_always.rs new file mode 100644 index 00000000000..e20bcec9316 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5066/with_trailing_comma_always.rs @@ -0,0 +1,5 @@ +// rustfmt-trailing_comma: Always + +fn main() { + let Foo { a, .. } = b; +} diff --git a/src/tools/rustfmt/tests/target/issue-5066/with_trailing_comma_never.rs b/src/tools/rustfmt/tests/target/issue-5066/with_trailing_comma_never.rs new file mode 100644 index 00000000000..8b95bb137bc --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5066/with_trailing_comma_never.rs @@ -0,0 +1,5 @@ +// rustfmt-trailing_comma: Never + +fn main() { + let Foo { a, .. } = b; +} diff --git a/src/tools/rustfmt/tests/target/issue-5151/minimum_example.rs b/src/tools/rustfmt/tests/target/issue-5151/minimum_example.rs new file mode 100644 index 00000000000..2ed3d936e32 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5151/minimum_example.rs @@ -0,0 +1,16 @@ +#![feature(more_qualified_paths)] + +struct Struct {} + +trait Trait { + type Type; +} + +impl Trait for Struct { + type Type = Self; +} + +fn main() { + // keep the qualified path details + let _ = <Struct as Trait>::Type {}; +} diff --git a/src/tools/rustfmt/tests/target/match.rs b/src/tools/rustfmt/tests/target/match.rs index e2c522bea10..1bf3fb758ee 100644 --- a/src/tools/rustfmt/tests/target/match.rs +++ b/src/tools/rustfmt/tests/target/match.rs @@ -608,3 +608,22 @@ fn issue_3774() { } } } + +// #4109 +fn issue_4109() { + match () { + _ => { + #[cfg(debug_assertions)] + { + println!("Foo"); + } + } + } + + match () { + _ => { + #[allow(unsafe_code)] + unsafe {} + } + } +} diff --git a/src/tools/rustfmt/tests/target/skip/preserve_trailing_comment.rs b/src/tools/rustfmt/tests/target/skip/preserve_trailing_comment.rs new file mode 100644 index 00000000000..f85de33257c --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip/preserve_trailing_comment.rs @@ -0,0 +1,7 @@ +#![rustfmt::skip] + +fn main() { + println!("Hello, world!"); +} + +// Trailing Comment diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 6ece9477140..ca79c835b9f 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -56,6 +56,12 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[ "// normalize-stderr-test", ]; +// Intentionally written in decimal rather than hex +const PROBLEMATIC_CONSTS: &[u32] = &[ + 184594741, 2880289470, 2881141438, 2965027518, 2976579765, 3203381950, 3405691582, 3405697037, + 3735927486, 4027431614, 4276992702, +]; + /// Parser states for `line_is_url`. #[derive(Clone, Copy, PartialEq)] #[allow(non_camel_case_types)] @@ -217,6 +223,10 @@ pub fn check(path: &Path, bad: &mut bool) { fn skip(path: &Path) -> bool { super::filter_dirs(path) || skip_markdown_path(path) } + let problematic_consts_strings: Vec<String> = (PROBLEMATIC_CONSTS.iter().map(u32::to_string)) + .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v))) + .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v))) + .collect(); super::walk(path, &mut skip, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); @@ -306,6 +316,11 @@ pub fn check(path: &Path, bad: &mut bool) { if line.contains("//") && line.contains(" XXX") { err("XXX is deprecated; use FIXME") } + for s in problematic_consts_strings.iter() { + if line.contains(s) { + err("Don't use magic numbers that spell things (consider 0x12345678)"); + } + } } let is_test = || file.components().any(|c| c.as_os_str() == "tests"); // for now we just check libcore |
